admin (DEVEL): distfiles/specparser.pl - annother trial - robust b...
sparky
sparky at pld-linux.org
Tue Mar 13 04:22:47 CET 2007
Author: sparky Date: Tue Mar 13 03:22:47 2007 GMT
Module: admin Tag: DEVEL
---- Log message:
- annother trial - robust brute-force parsing: tries all %if-%else-%endif
possibilities
for opera.spec gives only 31 results, but it takes 18 seconds (@1.3GHz)
to parse (there are 6192 posibilities)
---- Files affected:
admin/distfiles:
specparser.pl (1.13.2.2 -> 1.13.2.3)
---- Diffs:
================================================================
Index: admin/distfiles/specparser.pl
diff -u admin/distfiles/specparser.pl:1.13.2.2 admin/distfiles/specparser.pl:1.13.2.3
--- admin/distfiles/specparser.pl:1.13.2.2 Mon Mar 12 23:24:17 2007
+++ admin/distfiles/specparser.pl Tue Mar 13 04:22:42 2007
@@ -16,23 +16,23 @@
use strict;
use warnings;
-my %macro;
+my %no_source;
my $spec;
my $base_spec;
+my @spec;
+my @sources;
sub next_spec($)
{
$spec = shift;
+ @spec = ();
$base_spec = $spec;
$base_spec =~ s|.*/||;
- %macro = ( "nil" => [""] );
- #$err_cnt = 0;
}
sub error($)
{
- #$err_cnt++;
- print "ERROR: $base_spec: $_[0]\n";
+ print_once( "ERROR: $base_spec: $_[0]" );
}
sub warning($)
@@ -50,11 +50,26 @@
return $v;
}
-sub expand_tr($)
+# expand macros in string
+sub expand($$) # {{{
{
- my $v = shift;
-
+ my $v = trim_spaces(shift);
+ my $macrotree = shift;
my $cnt = 20;
+
+ while ($v =~ /\%\{([^\}]+)\}/) {
+ my $value;
+ if (defined $macrotree->{$1}) {
+ $value = $macrotree->{$1};
+ } else {
+ error("undefined macro $1");
+ $value = "UNDEFINED";
+ }
+ $v =~ s/\%\{([^\}]+)\}/$value/;
+
+ return $v if (length $v > 1000 or $cnt-- <= 0)
+ }
+
while ($v =~ s/\%\(\s*echo\s+([^\|]+?)\s*\|\s*tr\s*(-d|)\s+([^\)]+?)\s*\)/\@\@tr-me\@\@/) {
my ($what, $d_opt, $how) = ($1, $2, $3);
my ($from, $to) = ($how, "");
@@ -76,83 +91,105 @@
return $v if (length $v > 1000 or $cnt-- <= 0)
}
+ error("unexpanded macros in $v")
+ if ($v =~ /\%[^0-9]/);
+
return $v;
-}
+} # }}}
-# recursive expansion
-sub expand_r($$);
-sub expand_r($$)
-{
- my ($to_expand, $level) = @_;
- return $to_expand if $level < 0;
- $level--;
-
- if ($to_expand =~ /\%\{([^\}]+)\}/) {
- my $key = quotemeta $1;
- my $values;
- if (defined $macro{$1}) {
- $values = $macro{$1};
- } else {
- error("undefined macro $1");
- $values = ["UNDEFINED"];
- }
- my @vs;
- foreach my $value (@{$values}) {
- (my $vs = $to_expand) =~ s/\%\{($key)\}/$value/;
- push @vs, expand_r($vs, $level);
- }
+sub preparse_spec($) # {{{
+{
+ @spec = ("");
- return @vs;
- } else {
- return $to_expand;
+ open(F, "< $_[0]") or die;
+ while (<F>) {
+ chomp;
+ if (/^\s*(\%(description|package|prep|install|pre|post|files)|BuildRoot|URL)/) {
+ last;
+ } elsif (/^\s*(\%if|\%else|\%endif|\%define|Version|Name)/) {
+ if ($spec[$#spec] =~ /\%if/) {
+ if (/\%else/) {
+ next; # don't include empty %if-%else
+ } elsif (/\%endif/) {
+ # remove empty %if-%endif
+ pop @spec;
+ next;
+ }
+ }
+ push @spec, $_;
+ } elsif (/^NoSource\s*:\s*(\d+)\s*$/i) {
+ $no_source{$1} = 1;
+ }
}
-}
+ close(F);
-# expand macros in string
-sub expand($)
-{
- my $v = trim_spaces(shift);
- my $done = [];
+ shift @spec;
+} # }}}
- foreach my $e ( expand_r($v, 20) ) {
- $e = expand_tr($e);
- push @{$done}, $e;
- error("unexpanded macros in $e")
- if ($e =~ /\%[^0-9]/);
- }
- return $done;
-}
-# define given macro
-sub define($$)
+sub find_closing($$)
{
- my ($n, $v) = @_;
- $macro{$n} = [] unless exists $macro{$n};
- push @{$macro{$n}}, trim_spaces($v);
+ my ($spec, $end) = @_;
+ my $level = 0;
+ local $_;
+ while ($_ = shift @{$spec}) {
+ if (/^\s*\%($end)\s*$/ and $level <= 0) {
+ return;
+ } elsif (/^\s*\%if/) {
+ $level++;
+ } elsif (/^\s*\%endif\s*$/) {
+ $level--;
+ }
+ }
}
-# sets hash of macros defined with %define or %global
-# also define %{name}, %{version} and %{source_N}
-sub parse_defines($)
+my $total = 0;
+
+sub cont($$);
+sub cont($$) # {{{
{
- open(F, "< $_[0]") or die;
- while (<F>) {
- chomp;
- if (/^\s*\%(define|global)\s+([^\s]+)\s+([^\s].*)$/) {
- define($2, $3);
+ my ($spec, $macros) = @_;
+ local $_;
+ while ($_ = shift @{$spec}) {
+ if (/^\s*\%if/) { # if, ifarch, ifos
+
+ # split spec parsing
+ my @speccopy = @{$spec};
+ my %macroscopy = %{$macros};
+ cont(\@speccopy, \%macroscopy);
+
+ find_closing($spec, "else|endif");
+ # continue parsing
+
+ } elsif (/^\s*\%else\s*$/) {
+
+ # %else happens only when %if was interpreted
+ # so skip until %endif
+
+ find_closing($spec, "endif");
+
+ } elsif (/^\s*\%(define|global)\s+([^\s]+)\s+([^\s].*)$/) {
+ $macros->{$2} = $3;
} elsif (/^Version\s*:\s*(.*)/i) {
- define("version", $1);
+ $macros->{"version"} = $1;
} elsif (/^Name\s*:\s*(.*)/i) {
- define("name", $1);
- } elsif (/^Patch(\d+)\s*:\s*(.*)/i) {
- define("patch_$1", expand($2));
- } elsif (/^NoSource\s*:\s*(\d+)\s*$/i) {
- define("no_source_$1", "1");
+ $macros->{"name"} = $1;
+ } elsif (!/\%(endif|undef|bcond)/) {
+ warn "unrecognised line: $_\n";
}
}
- close(F);
-}
+
+ # the end, yuppie !
+ foreach my $s (@sources) {
+ print_source( $s->[0], $s->[1], expand( $s->[2], $macros ) );
+ }
+
+ if (++$total > 10000) {
+ error("maximum number of bcond posibilities exceeded");
+ exit 0;
+ }
+} # }}}
my %printed;
sub print_once($)
@@ -164,8 +201,10 @@
}
}
-sub print_source($$$) {
+sub print_source($$$) # {{{
+{
my ($no, $md5, $s) = @_;
+
if ($s =~ /^([a-z0-9A-Z:\=\?\@\+\~\.\-\/_]|\%[0-9])+$/) {
if ($s =~ /^(ftp|http|https):\/\//) {
if ($s =~ /\/$/) {
@@ -185,10 +224,9 @@
} else {
error("source $no url $s is ill-formatted");
}
+} # }}}
-}
-
-sub print_md5($)
+sub add_md5_to_print($) # {{{
{
open(F, "< $_[0]") or die;
my $sourceno = undef;
@@ -197,32 +235,34 @@
chomp;
if (/^Source(\d+)\s*:\s*(.*)/i) {
$sourceno = $1;
- $source = expand($2);
+ $source = $2;
} elsif (/^\s*#\s*source(\d+)-md5\s*:\s*([a-f0-9]{32})/i) {
my $no = $1;
my $md5 = $2;
- if (defined $macro{"no_source_$no"}) {
+ if (defined $no_source{$no}) {
error("both NoSource: $no and md5 given");
- } elsif (defined $sourceno and ($sourceno == $no)) {
- foreach my $s (@{$source}) {
- print_source($no, $md5, $s);
+ } if (defined $sourceno) {
+ if ($sourceno == $no) {
+ push @sources, [$no, $md5, $source];
+ } else {
+ error("found md5 for source $no, but last defined source is $sourceno");
}
- } elsif (defined $sourceno) {
- error("found md5 for source $no, but last defined source is $sourceno");
} else {
error("source $no not defined");
}
+
$sourceno = undef;
$source = undef;
}
}
close(F);
-}
+} # }}}
next_spec(shift);
-parse_defines($spec);
-print_md5($spec);
+preparse_spec($spec);
+add_md5_to_print($spec);
+cont( \@spec, { "nil" => "" } );
exit(0);
-# vim: ts=4:sw=4
+# vim: ts=4:sw=4:fdm=marker
================================================================
---- CVS-web:
http://cvs.pld-linux.org/admin/distfiles/specparser.pl?r1=1.13.2.2&r2=1.13.2.3&f=u
More information about the pld-cvs-commit
mailing list