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;
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) {
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') {
160 } elsif ($_ eq '%else') {
162 # %else happens only when %if was interpreted
163 # so skip until %endif
166 while ($_ = shift @{$spec}) {
167 if ($level <= 0 and $_ eq '%endif') {
169 } elsif (0 <= index $_, '%if') {
171 } elsif ($_ eq '%endif') {
176 } elsif (/^\s*\%(define|global)\s+([^\s]+)\s+([^\s].*?)\s*$/) {
179 } elsif (/^Version\s*:\s*(.*?)\s*$/i) {
180 $macros->{"version"} = $1;
181 } elsif (/^Name\s*:\s*(.*?)\s*$/i) {
182 $macros->{"name"} = $1;
183 } elsif (!/\%endif/) {
184 warn "unrecognised line: $_\n";
189 foreach my $s (@sources) {
190 my $src = expand( $s->[2], $macros );
193 unless (exists $tried{$src}) {
194 print_source( $s->[0], $s->[1], $src );
200 if (++$total > 10000) {
201 error("maximum number of bcond posibilities exceeded");
210 unless (exists $printed{$l}) {
216 sub print_source($$$) # {{{
218 my ($no, $md5, $s) = @_;
220 if ($s =~ /^([a-z0-9A-Z:\=\?\@\+\~\.,\-\/_]|\%[0-9])+$/) {
221 if ($s =~ /^(ftp|http|https):\/\//) {
223 error("source $no ($s) is directory");
225 if ($s =~ /:\/\/distfiles\.pld-linux\.org\/src/) {
227 print_once( "$md5 no-url-copy://$s" );
229 print_once( "$md5 $s" );
234 print_once( "$md5 no-url://$s");
237 error("source $no url $s is ill-formatted");
241 sub add_md5_to_print($) # {{{
243 open(F, "< $_[0]") or die;
247 if (/^Source(\d+)\s*:\s*(.*)/i) {
250 $sourcemap[$sourceno] = $source;
251 } elsif (/^\s*#\s*source(\d+)-md5\s*:\s*([a-f0-9]{32})/i) {
254 if (defined $no_source{$no}) {
255 error("both NoSource: $no and md5 given");
256 } if (defined $sourcemap[$no]) {
257 my $source = $sourcemap[$no];
258 push @sources, [$no, $md5, $source];
260 error("source $no not defined (# SourceN-md5: has to be placed just after SourceN:)");
262 } elsif (/^\s*BuildRequires:\s*digest\(%SOURCE(\d+)\)\s*=\s*([a-f0-9]{32})/i) {
265 if (defined $no_source{$no}) {
266 error("both NoSource: $no and md5 given");
267 } if (defined $sourcemap[$no]) {
268 my $source = $sourcemap[$no];
269 push @sources, [$no, $md5, $source];
271 error("source $no not defined (# Source digest has to be placed after SourceN:)");
279 preparse_spec($spec);
280 add_md5_to_print($spec);
281 cont( \@spec, { "nil" => "" } );
285 # vim: ts=4:sw=4:fdm=marker