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