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