lede-packages-rs

git clone git://archive.git.mtrnord.blog/MTRNord/lede-packages-rs.git
Log | Files | Refs | README | LICENSE

perlconfig.pl (8822B)


      1 #!/usr/bin/perl
      2 
      3 # This program is free software: you can redistribute it and/or modify
      4 # it under the terms of the GNU General Public License as published by
      5 # the Free Software Foundation, either version 3 of the License, or
      6 # (at your option) any later version.
      7 # 
      8 # This program is distributed in the hope that it will be useful,
      9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11 # GNU General Public License for more details.
     12 # 
     13 # You should have received a copy of the GNU General Public License
     14 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15 # 
     16 # Copyright 2015 Marcel Denia
     17 
     18 =head1 NAME
     19 
     20 perlconfig.pl
     21 
     22 =head1 SYNOPSIS
     23 
     24 B<perlconfig.pl> [B<-Dsymbol>=I<value>, ...] [B<-dsymbol>=I<value>, ...] I<[files]>
     25 
     26 Generate a configuration file suitable for (cross-)compiling perl 5.
     27 
     28 =head1 OPTIONS
     29 
     30 =over
     31 
     32 =item B<-Dsymbol=value>
     33 
     34 The symbol identified by I<name> will have the literal value I<value>.
     35 When generating the configuration file, it's value will be printed enclosed by
     36 single quotation marks(').
     37 
     38 =item B<-dsymbol=value>
     39 
     40 The symbol identified by I<name> will have the literal value I<value>.
     41 
     42 =back
     43 
     44 =head1 DESCRIPTION
     45 
     46 B<perlconfig.pl> is a program to compile and generate configuration files ready
     47 to be used as a "config.sh" file for compiling perl 5. It does so by processing
     48 specially-made configuration files(usually called *.config), typically augmented
     49 by command-line definitions.
     50 
     51 B<perlconfig.pl>'s intent is to be used in place of perl 5's own Configure
     52 script in situations where it can not be run, like cross-compiling.
     53 
     54 =head2 File syntax
     55 
     56 B<perlconfig.pl>'s configuration files a consist of symbol definitions in
     57 different variations, each one assigning a specific symbol identified by a name
     58 some value, as well as conditional blocks in order to allow for some
     59 flexibility.
     60 
     61 =head3 Symbol names
     62 
     63 A symbol name has to consist entirely of alphanumeric characters as well as
     64 the underscore(_) character. In addition, symbol names may be prefixed with an
     65 all-lowercase string, separated by a colon(:):
     66 
     67   my:name=value
     68 
     69 Having a zero-length prefix string is also valid:
     70 
     71   :name=value
     72 
     73 Symbols prefixed that way are called private symbols. They act exactly like
     74 regular symbols, with the only difference being that they will B<not> be written
     75 to the final configuration file.
     76 
     77 =head3 Symbol definitions
     78 
     79 A symbol definition is in the form of a simple name/value pair, separated by
     80 an equals sign(=):
     81 
     82   name=value
     83 
     84 I<value> can be anything really. However, there are 3 notations, with
     85 differences in quoting and interpolation:
     86 
     87 =over
     88 
     89 =item name=foo
     90 
     91 The symbol identified by I<name> will have the literal value I<foo>.
     92 
     93 =item name='foo'
     94 
     95 The symbol identified by I<name> will have the literal value I<foo>.
     96 When generating the configuration file, it's value will be printed enclosed by
     97 single quotation marks(').
     98 
     99 =item name="foo"
    100 
    101 The symbol identified by I<name> will have the value of I<foo>
    102 S<B<after interpolation>>(as described in L</Interpolation>).
    103 When generating the configuration file, it's value will be printed enclosed by
    104 single quotation marks(').
    105 
    106 =back
    107 
    108 =head3 Conditional blocks
    109 
    110 A conditional block is of the form
    111 
    112   (condition) {
    113       ...
    114   }
    115 
    116 B<perlconfig.pl> will execute everything enclosed in the curly braces({ and }),
    117 or inside the BLOCK in Perl 5 terms, if I<condition> evaluates to any true
    118 value. I<condition> will go through interpolation as described in
    119 L</Interpolation>. It may contain any valid Perl 5 expression. Some common
    120 examples are:
    121 
    122 =over
    123 
    124 =item $name eq 'foo'
    125 
    126 Evaluates to true if configuration symbol I<name> is literally equal to I<foo>.
    127 
    128 =item $name ne 'foo'
    129 
    130 Evaluates to true if configuration symbol I<name> is B<not> literally equal to
    131 I<foo>.
    132 
    133 =item defined($name)
    134 
    135 Evaluates to true if configuration symbol I<name> is defined(has any usable
    136 value, see L<perlfunc/defined>).
    137 
    138 =back
    139 
    140 Conditional blocks may be nested inside conditional blocks. Note that the
    141 opening curl brace({) has to be on the same line as your condition.
    142 
    143 =head3 Comments
    144 
    145 All lines starting with nothing or any number of whitespaces, followed by a
    146 hash sign(#), are considered comments and will be completely ignored by
    147 B<perlconfig.pl>.
    148 
    149 =head3 Interpolation
    150 
    151 In certain situations(see above), B<perlconfig.pl> will interpolate strings or
    152 constructs in order to allow you to refer to configuration symbols or embed
    153 code.
    154 
    155 Interpolated strings are subject to the following rules:
    156 
    157 =over
    158 
    159 =item You may not include any single(') or double(") quotation marks.
    160 
    161 You can use \qq in order to include double quotation marks(") in your string.
    162 
    163 =item $name and ${name} reference configuration symbols
    164 
    165 You can easily refer to existing configuration symbols using the commmon $name
    166 or ${name} syntax. In case you want to refer to the perl variable named $name,
    167 write \$name. This is useful for embedding code.
    168 
    169 =item Perl 5 interpolation rules apply
    170 
    171 Aside from the above, you may include anything that is also valid for an
    172 interpolated(qq//) string in Perl 5. For instance, it's perfectly valid to
    173 execute code using the @{[]} construct.
    174 
    175 =back
    176 
    177 =head1 EXAMPLES
    178 
    179 As a simple example, consider the following configuration file, named
    180 "example.config":
    181 
    182   recommendation='The Perl you want is'
    183   ($:maturity eq 'stable') {
    184       recommendation="$recommendation Perl 5"
    185   }
    186   ($:maturity eq 'experimental') {
    187       recommendation="$recommendation Perl 6(try Rakudo!)"
    188   }
    189 
    190 Executing it using these command-lines will yield the following results:
    191 
    192 =over
    193 
    194 =item $ perlconfig.pl -D:maturity=stable example.config
    195 
    196   recommendation='The Perl you want is Perl 5'
    197 
    198 =item $ perlconfig.pl -D:maturity=experimental example.config
    199 
    200   recommendation='The Perl you want is Perl 6(try Rakudo!)'
    201 
    202 =back
    203 
    204 =head1 AUTHOR
    205 
    206 Marcel Denia <naoir@gmx.net>
    207 
    208 =head1 COPYRIGHT AND LICENSE
    209 
    210 Copyright 2015 Marcel Denia
    211 
    212 This program is free software: you can redistribute it and/or modify
    213 it under the terms of the GNU General Public License as published by
    214 the Free Software Foundation, either version 3 of the License, or
    215 (at your option) any later version.
    216 
    217 This program is distributed in the hope that it will be useful,
    218 but WITHOUT ANY WARRANTY; without even the implied warranty of
    219 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    220 GNU General Public License for more details.
    221 
    222 You should have received a copy of the GNU General Public License
    223 along with this program.  If not, see <http://www.gnu.org/licenses/>.
    224 
    225 =cut
    226 
    227 use strict;
    228 use warnings;
    229 use List::Util qw/all/;
    230 my $symbol_name_prefix_regex = '(?:[a-z]*:)';
    231 my $symbol_name_regex = "($symbol_name_prefix_regex?(?:[a-zA-Z0-9_]+))";
    232 
    233 my %config;
    234 
    235 sub interpolate {
    236 	my $string = shift;
    237 	my %options = @_;
    238 	
    239 	# First, convert $foo into ${foo}
    240 	$string =~ s/(?<!\\)\$$symbol_name_regex/\${$1}/gs;
    241 	
    242 	# Make ${foo} into $config{'foo'}->{value}
    243 	$string =~ s/\$\{$symbol_name_regex\}/\$config{\'$1\'}->{value}/g;
    244 	
    245 	# Un-escape \$foo
    246 	$string =~ s/\\\$/\$/g;
    247 	
    248 	# Turn \qq into "
    249 	$string =~ s/\\qq/\\"/g;
    250 	
    251 	return $string;
    252 }
    253 
    254 # Parse command-line symbol definitions
    255 while ($ARGV[0]) {
    256 	if ($ARGV[0] =~ /^-([D|d])$symbol_name_regex=(.*)$/) {
    257 		$config{$2} = { value => $3, quoted => $1 eq 'D' };
    258 		shift(@ARGV);
    259 	}
    260 	else {
    261 		last;
    262 	}
    263 }
    264 
    265 # Process configuration files
    266 my @condition_stack = ( 1 );
    267 for my $file (@ARGV) {
    268 	open(my $fh, '<', $file) or die "Can't open $file: $!\n";
    269 	while (my $line = <$fh>) {
    270 		chomp($line);
    271 		
    272 		if ($line =~ /^\s*$symbol_name_regex=(.*)$/) { # A symbol definition
    273 			if (all {$_ == 1} @condition_stack) {
    274 				my $symbol = $1;
    275 				(my $quote_begin, my $value, my $quote_end) = $2 =~ /^(['|"])?([^'"]*)(['|"])?$/;
    276 				
    277 				$quote_begin = '' unless defined $quote_begin;
    278 				$quote_end = '' unless defined $quote_end;
    279 				die "$file:$.: Unmatched quotes in \"$line\"\n" unless $quote_begin eq $quote_end;
    280 				
    281 				if ($quote_begin eq '"') {
    282 					$config{$symbol} = { value => eval('"' . interpolate($2) . '"'), quoted => 1 };
    283 				}
    284 				else {
    285 					$config{$symbol} = { value => $2, quoted => $quote_begin eq '\'' };
    286 				}
    287 			}
    288 		}
    289 		elsif ($line =~ /^\s*\((.*)\)\s?{$/) { # A conditional block
    290 			if (eval(interpolate($1))) {
    291 				push(@condition_stack, 1);
    292 			}
    293 			else {
    294 				push(@condition_stack, 0);
    295 			}
    296 		}
    297 		elsif ($line =~ /^\s*}$/) { # Closing a conditional block
    298 			pop(@condition_stack);
    299 			die "$file:$.: Closing non-existent block\n" unless @condition_stack;
    300 		}
    301 		elsif ($line =~ (/^\s*$/) || ($line =~ /^\s*#/)) { # An empty line or comment
    302 		}
    303 		else {
    304 			die "$file:$.: Malformed line: \"$line\"\n";
    305 		}
    306 	}
    307 }
    308 
    309 # Output
    310 for (sort(keys(%config))) {
    311 	my $quote = $config{$_}->{quoted} ? '\'' : '';
    312 	print("$_=$quote$config{$_}->{value}$quote\n") unless $_ =~ /^$symbol_name_prefix_regex/;
    313 }