1 1.1 christos # Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. 2 1.1 christos # 3 1.1 christos # Licensed under the Apache License 2.0 (the "License"). You may not use 4 1.1 christos # this file except in compliance with the License. You can obtain a copy 5 1.1 christos # in the file LICENSE in the source distribution or at 6 1.1 christos # https://www.openssl.org/source/license.html 7 1.1 christos 8 1.1 christos package OpenSSL::Config::Query; 9 1.1 christos 10 1.1 christos use 5.10.0; 11 1.1 christos use strict; 12 1.1 christos use warnings; 13 1.1 christos use Carp; 14 1.1 christos 15 1.1 christos =head1 NAME 16 1.1 christos 17 1.1 christos OpenSSL::Config::Query - Query OpenSSL configuration info 18 1.1 christos 19 1.1 christos =head1 SYNOPSIS 20 1.1 christos 21 1.1 christos use OpenSSL::Config::Info; 22 1.1 christos 23 1.1 christos my $query = OpenSSL::Config::Query->new(info => \%unified_info); 24 1.1 christos 25 1.1 christos # Query for something that's expected to give a scalar back 26 1.1 christos my $variable = $query->method(... args ...); 27 1.1 christos 28 1.1 christos # Query for something that's expected to give a list back 29 1.1 christos my @variable = $query->method(... args ...); 30 1.1 christos 31 1.1 christos =head1 DESCRIPTION 32 1.1 christos 33 1.1 christos The unified info structure, commonly known as the %unified_info table, has 34 1.1 christos become quite complex, and a bit overwhelming to look through directly. This 35 1.1 christos module makes querying this structure simpler, through diverse methods. 36 1.1 christos 37 1.1 christos =head2 Constructor 38 1.1 christos 39 1.1 christos =over 4 40 1.1 christos 41 1.1 christos =item B<new> I<%options> 42 1.1 christos 43 1.1 christos Creates an instance of the B<OpenSSL::Config::Query> class. It takes options 44 1.1 christos in keyed pair form, i.e. a series of C<< key => value >> pairs. Available 45 1.1 christos options are: 46 1.1 christos 47 1.1 christos =over 4 48 1.1 christos 49 1.1 christos =item B<info> =E<gt> I<HASHREF> 50 1.1 christos 51 1.1 christos A reference to a unified information hash table, most commonly known as 52 1.1 christos %unified_info. 53 1.1 christos 54 1.1 christos =item B<config> =E<gt> I<HASHREF> 55 1.1 christos 56 1.1 christos A reference to a config information hash table, most commonly known as 57 1.1 christos %config. 58 1.1 christos 59 1.1 christos =back 60 1.1 christos 61 1.1 christos Example: 62 1.1 christos 63 1.1 christos my $info = OpenSSL::Config::Info->new(info => \%unified_info); 64 1.1 christos 65 1.1 christos =back 66 1.1 christos 67 1.1 christos =cut 68 1.1 christos 69 1.1 christos sub new { 70 1.1 christos my $class = shift; 71 1.1 christos my %opts = @_; 72 1.1 christos 73 1.1 christos my @messages = _check_accepted_options(\%opts, 74 1.1 christos info => 'HASH', 75 1.1 christos config => 'HASH'); 76 1.1 christos croak $messages[0] if @messages; 77 1.1 christos 78 1.1 christos # We make a shallow copy of the input structure. We might make 79 1.1 christos # a different choice in the future... 80 1.1 christos my $instance = { info => $opts{info} // {}, 81 1.1 christos config => $opts{config} // {} }; 82 1.1 christos bless $instance, $class; 83 1.1 christos 84 1.1 christos return $instance; 85 1.1 christos } 86 1.1 christos 87 1.1 christos =head2 Query methods 88 1.1 christos 89 1.1 christos =over 4 90 1.1 christos 91 1.1 christos =item B<get_sources> I<LIST> 92 1.1 christos 93 1.1 christos LIST is expected to be the collection of names of end products, such as 94 1.1 christos programs, modules, libraries. 95 1.1 christos 96 1.1 christos The returned result is a hash table reference, with each key being one of 97 1.1 christos these end product names, and its value being a reference to an array of 98 1.1 christos source file names that constitutes everything that will or may become part 99 1.1 christos of that end product. 100 1.1 christos 101 1.1 christos =cut 102 1.1 christos 103 1.1 christos sub get_sources { 104 1.1 christos my $self = shift; 105 1.1 christos 106 1.1 christos my $result = {}; 107 1.1 christos foreach (@_) { 108 1.1 christos my @sources = @{$self->{info}->{sources}->{$_} // []}; 109 1.1 christos my @staticlibs = 110 1.1 christos grep { $_ =~ m|\.a$| } @{$self->{info}->{depends}->{$_} // []}; 111 1.1 christos 112 1.1 christos my %parts = ( %{$self->get_sources(@sources)}, 113 1.1 christos %{$self->get_sources(@staticlibs)} ); 114 1.1 christos my @parts = map { @{$_} } values %parts; 115 1.1 christos 116 1.1 christos my @generator = 117 1.1 christos ( ( $self->{info}->{generate}->{$_} // [] ) -> [0] // () ); 118 1.1 christos my %generator_parts = %{$self->get_sources(@generator)}; 119 1.1 christos # if there are any generator parts, we ignore it, because that means 120 1.1 christos # it's a compiled program and thus NOT part of the source that's 121 1.1 christos # queried. 122 1.1 christos @generator = () if %generator_parts; 123 1.1 christos 124 1.1 christos my @partial_result = 125 1.1 christos ( ( map { @{$_} } values %parts ), 126 1.1 christos ( grep { !defined($parts{$_}) } @sources, @generator ) ); 127 1.1 christos 128 1.1 christos # Push conditionally, to avoid creating $result->{$_} with an empty 129 1.1 christos # value 130 1.1 christos push @{$result->{$_}}, @partial_result if @partial_result; 131 1.1 christos } 132 1.1 christos 133 1.1 christos return $result; 134 1.1 christos } 135 1.1 christos 136 1.1 christos =item B<get_config> I<LIST> 137 1.1 christos 138 1.1 christos LIST is expected to be the collection of names of configuration data, such 139 1.1 christos as build_infos, sourcedir, ... 140 1.1 christos 141 1.1 christos The returned result is a hash table reference, with each key being one of 142 1.1 christos these configuration data names, and its value being a reference to the value 143 1.1 christos corresponding to that name. 144 1.1 christos 145 1.1 christos =cut 146 1.1 christos 147 1.1 christos sub get_config { 148 1.1 christos my $self = shift; 149 1.1 christos 150 1.1 christos return { map { $_ => $self->{config}->{$_} } @_ }; 151 1.1 christos } 152 1.1 christos 153 1.1 christos ######## 154 1.1 christos # 155 1.1 christos # Helper functions 156 1.1 christos # 157 1.1 christos 158 1.1 christos sub _check_accepted_options { 159 1.1 christos my $opts = shift; # HASH reference (hopefully) 160 1.1 christos my %conds = @_; # key => type 161 1.1 christos 162 1.1 christos my @messages; 163 1.1 christos my %optnames = map { $_ => 1 } keys %$opts; 164 1.1 christos foreach (keys %conds) { 165 1.1 christos delete $optnames{$_}; 166 1.1 christos } 167 1.1 christos push @messages, "Unknown options: " . join(', ', sort keys %optnames) 168 1.1 christos if keys %optnames; 169 1.1 christos foreach (sort keys %conds) { 170 1.1 christos push @messages, "'$_' value not a $conds{$_} reference" 171 1.1 christos if (defined $conds{$_} && defined $opts->{$_} 172 1.1 christos && ref $opts->{$_} ne $conds{$_}); 173 1.1 christos } 174 1.1 christos return @messages; 175 1.1 christos } 176 1.1 christos 177 1.1 christos 1; 178