4 # USAGE: specparser.pl file.spec
11 # except for lines prefixed with: ERROR:
14 # 2 - cannot open spec file
30 $base_spec =~ s|.*/||;
35 print_once( "ERROR: $base_spec: $_[0]" );
40 print "ERROR: $base_spec: $_[0]\n";
53 # expand macros in string
56 my $v = trim_spaces(shift);
57 my $macrotree = shift;
60 while ($v =~ /\%\{([^\}]+)\}/) {
62 if (defined $macrotree->{$1}) {
63 $value = $macrotree->{$1};
65 error("undefined macro $1");
69 $v =~ s/\%\{([^\}]+)\}/$value/;
71 return $v if (length $v > 1000 or $cnt-- <= 0)
74 while ($v =~ s/\%\(\s*echo\s+([^\|]+?)\s*\|\s*tr\s*(-d|)\s+([^\)]+?)\s*\)/\@\@tr-me\@\@/) {
75 my ($what, $d_opt, $how) = ($1, $2, $3);
76 my ($from, $to) = ($how, "");
77 ($from, $to) = ($1, $2)
78 if $how =~ /^([^\s]+)\s+([^\s]+)$/;
79 if ($d_opt and $to ne "") {
80 error("tr -d with second string)");
81 } elsif (($from . $to) =~ /^[a-zA-Z0-9\+_\-\.]+$/) {
83 eval "\$what =~ tr/$from//d;";
85 eval "\$what =~ tr/$from/$to/;";
88 error("illegal characters in tr string(s) '$from' '$to'");
90 $v =~ s/\@\@tr-me\@\@/$what/;
92 return $v if (length $v > 1000 or $cnt-- <= 0)
95 error("unexpanded macros in $v")
96 if ($v =~ /\%[^0-9]/);
101 sub preparse_spec($) # {{{
105 open(F, "< $_[0]") or die("failed opening: " . $_[0]);
108 if (/^\s*(\%(description|package|prep|install|pre|post|files)|BuildRoot|URL)/) {
110 } elsif (/^\s*(\%if.*|\%else|\%endif|\%define\s+.*|Version.*|Name.*)\s*$/) {
112 if ($spec[$#spec] =~ /\%if/) {
114 next; # don't include empty %if-%else
115 } elsif (/\%endif/) {
116 # remove empty %if-%endif
122 } elsif (/^NoSource\s*:\s*(\d+)\s*$/i) {
123 $no_source{ "source" . $1 } = 1;
137 my ($spec, $macros) = @_;
139 while ($_ = shift @{$spec}) {
140 if (0 <= index $_, '%if') { # if, ifarch, ifos
143 my @speccopy = @{$spec};
144 my %macroscopy = %{$macros};
145 cont(\@speccopy, \%macroscopy);
148 while ($_ = shift @{$spec}) {
149 if ($level <= 0 and ($_ eq '%else' or $_ eq '%endif')) {
151 } elsif (0 <= index $_, '%if') {
153 } elsif ($_ eq '%endif') {
159 } elsif ($_ eq '%else') {
161 # %else happens only when %if was interpreted
162 # so skip until %endif
165 while ($_ = shift @{$spec}) {
166 if ($level <= 0 and $_ eq '%endif') {
168 } elsif (0 <= index $_, '%if') {
170 } elsif ($_ eq '%endif') {
175 } elsif (/^\s*\%(define|global)\s+([^\s]+)\s+([^\s].*?)\s*$/) {
178 } elsif (/^Version\s*:\s*(.*?)\s*$/i) {
179 $macros->{"version"} = $1;
180 } elsif (/^Name\s*:\s*(.*?)\s*$/i) {
181 $macros->{"name"} = $1;
182 } elsif (!/\%endif/) {
183 warn "unrecognised line: $_\n";
188 foreach my $s (@sources) {
189 my $src = expand( $s->[2], $macros );
192 unless (exists $tried{$src}) {
193 print_source( $s->[0], $s->[1], $src );
199 if (++$total > 10000) {
200 error("maximum number of bcond posibilities exceeded");
209 unless (exists $printed{$l}) {
215 sub print_source($$$) # {{{
217 my ($no, $md5, $s) = @_;
219 if ($s =~ /^([a-z0-9A-Z;:\=\?&\@\+\~\.,\-\/_]|\%[0-9])+(#\/[a-zA-Z0-9\._-]+)?$/) {
220 if ($s =~ /^(ftp|http|https):\/\//) {
222 error("source $no ($s) is directory");
224 if ($s =~ /:\/\/distfiles\.pld-linux\.org\/src/) {
226 print_once( "$md5 no-url-copy://$s" );
228 print_once( "$md5 $s" );
233 print_once( "$md5 no-url://$s");
236 error("source $no url $s is ill-formatted");
240 sub add_md5_to_print($) # {{{
242 open(F, "< $_[0]") or die("failed opening: " . $_[0]);
246 if (/^((?:Source|Patch)\d+)\s*:\s*(.*)/i) {
247 my $sourceno = lc $1;
249 # master.dl is outdated currently
250 # $source =~ s/dl.sourceforge.net/master.dl.sourceforge.net/;
251 $sourcemap{ $sourceno } = $source;
252 } elsif (/^\s*#\s*((?:source|patch)\d+)-md5\s*:\s*([a-f0-9]{32})/i) {
255 if (defined $no_source{$no}) {
256 error("both NoSource: $no and md5 given");
257 } elsif (defined $sourcemap{ $no} ) {
258 my $source = $sourcemap{ $no };
259 push @sources, [$no, $md5, $source];
261 error("source $no not defined (# SourceN-md5: has to be placed just after SourceN:)");
263 } elsif (/^\s*BuildRequires:\s*digest\(%((?:SOURCE|PATCH)\d+)\)\s*=\s*([a-f0-9]{32})/i) {
266 if (defined $no_source{ $no }) {
267 error("both NoSource: $no and md5 given");
268 } elsif (defined $sourcemap{ $no }) {
269 my $source = $sourcemap{ $no };
270 push @sources, [$no, $md5, $source];
272 error("source $no not defined (# Source digest has to be placed after SourceN:)");
280 preparse_spec($spec);
281 add_md5_to_print($spec);
282 cont( \@spec, { "nil" => "" } );
286 # vim: ts=4:sw=4:fdm=marker