Configure - Allow CODErefs and ARRAYrefs in configuration setting arrays

This provides for more powerful lazy evaluation and buildup of the
setting contents.  For example, something like this becomes possible:

    defines => [ sub { $config{thisorthat} ? "FOO" : () } ]

Any undefined result of such functions (such as 'undef' or the empty
list) will be ignored.

Reviewed-by: Andy Polyakov <appro@openssl.org>
This commit is contained in:
Richard Levitte 2016-02-27 11:08:21 +01:00
parent ed49f43a03
commit b0b92a5bb5

View file

@ -1949,18 +1949,26 @@ sub _add {
my @values = my @values =
map { map {
if (ref($_) eq "ARRAY") { my $res = $_;
$found_array = 1; while (ref($res) eq "CODE") {
@$_; $res = $res->();
}
if (defined($res)) {
if (ref($res) eq "ARRAY") {
$found_array = 1;
@$res;
} else {
$res;
}
} else { } else {
$_; ();
} }
} (@_); } (@_);
if ($found_array) { if ($found_array) {
[ @values ]; [ @values ];
} else { } else {
join($separator, @values); join($separator, grep { defined($_) && $_ ne "" } @values);
} }
} }
sub add_before { sub add_before {
@ -2080,6 +2088,30 @@ sub resolve_config {
my %all_keys = my %all_keys =
map { $_ => 1 } (keys %combined_inheritance, map { $_ => 1 } (keys %combined_inheritance,
keys %{$table{$target}}); keys %{$table{$target}});
sub process_values {
my $object = shift;
my $inherited = shift; # Always a [ list ]
my $target = shift;
my $entry = shift;
while(ref($object) eq "CODE") {
$object = $object->(@$inherited);
}
if (!defined($object)) {
return ();
}
elsif (ref($object) eq "ARRAY") {
return [ map { process_values($_, $inherited, $target, $entry) }
@$object ];
} elsif (ref($object) eq "") {
return $object;
} else {
die "cannot handle reference type ",ref($object)
," found in target ",$target," -> ",$entry,"\n";
}
}
foreach (sort keys %all_keys) { foreach (sort keys %all_keys) {
# Current target doesn't have a value for the current key? # Current target doesn't have a value for the current key?
@ -2089,20 +2121,12 @@ sub resolve_config {
$table{$target}->{$_} = $default_combiner; $table{$target}->{$_} = $default_combiner;
} }
my $valuetype = ref($table{$target}->{$_}); $table{$target}->{$_} = process_values($table{$target}->{$_},
if ($valuetype eq "CODE") { $combined_inheritance{$_},
# CODE reference, execute it with the inherited values as $target, $_);
# arguments. unless(defined($table{$target}->{$_})) {
$table{$target}->{$_} = delete $table{$target}->{$_};
$table{$target}->{$_}->(@{$combined_inheritance{$_}}); }
} elsif ($valuetype eq "ARRAY" || $valuetype eq "") {
# ARRAY or Scalar, just leave it as is.
} else {
# Some other type of reference that we don't handle.
# Better to abort at this point.
die "cannot handle reference type $valuetype,"
," found in target $target -> $_\n";
}
} }
# Finally done, return the result. # Finally done, return the result.