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*\)/[EMAIL 
PROTECTED]@[EMAIL PROTECTED]@/) {
                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([EMAIL PROTECTED], \%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:[EMAIL PROTECTED]/_]|\%[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( [EMAIL PROTECTED], { "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

_______________________________________________
pld-cvs-commit mailing list
[email protected]
http://lists.pld-linux.org/mailman/listinfo/pld-cvs-commit

Reply via email to