From b0b92a5bb5b40e9ee7ca751b4d9218ed8726bda0 Mon Sep 17 00:00:00 2001
From: Richard Levitte <levitte@openssl.org>
Date: Sat, 27 Feb 2016 11:08:21 +0100
Subject: [PATCH] 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>
---
 Configure | 62 ++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 43 insertions(+), 19 deletions(-)

diff --git a/Configure b/Configure
index 96be541718..ce8fac77be 100755
--- a/Configure
+++ b/Configure
@@ -1949,18 +1949,26 @@ sub _add {
 
     my @values =
 	map {
-	    if (ref($_) eq "ARRAY") {
-		$found_array = 1;
-		@$_;
+	    my $res = $_;
+	    while (ref($res) eq "CODE") {
+		$res = $res->();
+	    }
+	    if (defined($res)) {
+		if (ref($res) eq "ARRAY") {
+		    $found_array = 1;
+		    @$res;
+		} else {
+		    $res;
+		}
 	    } else {
-		$_;
+		();
 	    }
     } (@_);
 
     if ($found_array) {
 	[ @values ];
     } else {
-	join($separator, @values);
+	join($separator, grep { defined($_) && $_ ne "" } @values);
     }
 }
 sub add_before {
@@ -2080,6 +2088,30 @@ sub resolve_config {
     my %all_keys =
 	map { $_ => 1 } (keys %combined_inheritance,
 			 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) {
 
 	# Current target doesn't have a value for the current key?
@@ -2089,20 +2121,12 @@ sub resolve_config {
 	    $table{$target}->{$_} = $default_combiner;
 	}
 
-	my $valuetype = ref($table{$target}->{$_});
-	if ($valuetype eq "CODE") {
-	    # CODE reference, execute it with the inherited values as
-	    # arguments.
-	    $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";
-	}
+	$table{$target}->{$_} = process_values($table{$target}->{$_},
+					       $combined_inheritance{$_},
+					       $target, $_);
+        unless(defined($table{$target}->{$_})) {
+            delete $table{$target}->{$_};
+        }
     }
 
     # Finally done, return the result.
-- 
2.25.1