tools: Add a script to help synchronize spec files that share an implementation.
[wine] / tools / winapi / make_parser.pm
1 #
2 # Copyright 1999, 2000, 2001 Patrik Stridvall
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 #
18
19 package make_parser;
20
21 use strict;
22
23 use setup qw($current_dir $wine_dir $winapi_dir);
24
25 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
26 require Exporter;
27
28 @ISA = qw(Exporter);
29 @EXPORT = qw();
30 @EXPORT_OK = qw($directory $tool $file $line $message);
31
32 use vars qw($directory $tool $file $line $message);
33
34 use output qw($output);
35 use options qw($options);
36
37
38 #sub command($);
39 #sub gcc_output($$);
40 #sub ld_output($$);
41 #sub make_output($$);
42 #sub winebuild_output($$);
43 #sub wmc_output($$);
44 #sub wrc_output($$);
45
46
47 ########################################################################
48 # global
49 ########################################################################
50
51 my $current;
52 my $function;
53
54 ########################################################################
55 # error
56 ########################################################################
57
58 sub error($) {
59     my $where = shift;
60
61     if(!defined($where)) {
62         $where = "";
63     }
64
65     my $context;
66     if($tool) {
67         $context = "$tool";
68         if($where) {
69             $context .= "<$where>";
70         }
71     } else {
72         if($where) {
73             $context = "<$where>";
74         } else {
75             $context = "<>";
76         }
77     }
78
79     if(defined($tool)) {
80         $output->write("$directory: $context: can't parse output: '$current'\n");
81     } else {
82         $output->write("$directory: $context: can't parse output: '$current'\n");
83     }
84     exit 1;
85 }
86
87 ########################################################################
88 # make_output
89 ########################################################################
90
91 sub make_output($$) {
92     my $level = shift;
93     local $_ = shift;
94
95     $file = "";
96     $message = "";
97
98     if(/^\*\*\* \[(.*?)\] Error (\d+)$/) {
99         # Nothing
100     } elsif(/^\*\*\* Error code (\d+)$/) {
101         # Nothing
102     } elsif(/^\*\*\* Warning:\s+/) { #
103         if(/^File \`(.+?)\' has modification time in the future \((.+?) > \(.+?\)\)$/) {
104             # Nothing
105         } else {
106             error("make_output");
107         }
108     } elsif(/^\`(.*?)\' is up to date.$/) {
109         # Nothing
110     } elsif(/^\[(.*?)\] Error (\d+) \(ignored\)$/) {
111         # Nothing
112     } elsif(/^don\'t know how to make (.*?)\. Stop$/) {
113         $message = "$_";
114     } elsif(/^(Entering|Leaving) directory \`(.*?)\'$/) {
115         if($1 eq "Entering") {
116             $directory = $2;
117         } else {
118             $directory = "";
119         }
120
121         my @components;
122         foreach my $component (split(/\//, $directory)) {
123             if($component eq "wine") {
124                 @components = ();
125             } else {
126                 push @components, $component;
127             }
128         }
129         $directory = join("/", @components);
130     } elsif(/^(.*?) is older than (.*?), please rerun (.*?)\$/) {
131         # Nothing
132     } elsif(/^Nothing to be done for \`(.*?)\'\.$/) {
133         # Nothing
134     } elsif(s/^warning:\s+//) {
135         if(/^Clock skew detected.  Your build may be incomplete.$/) {
136             # Nothing
137         } else {
138             error("make_output");
139         }
140     } elsif(/^Stop in (.*?)\.$/) {
141         # Nothing
142     } elsif(/^\s*$/) {
143         # Nothing
144     } else {
145         error("make_output");
146     }
147
148 }
149
150 ########################################################################
151 # ar_command
152 ########################################################################
153
154 sub ar_command($) {
155     local $_ = shift;
156
157     my $read_files;
158     my $write_files;
159
160     if(/rc\s+(\S+)(\s+\S+)+$/) {
161         $write_files = [$1];
162         $read_files = $2;
163         $read_files =~ s/^\s*//;
164         $read_files = [split(/\s+/, $read_files)];
165     } else {
166         error("ar_command");
167     }
168
169     return ($read_files, $write_files);
170 }
171
172 ########################################################################
173 # as_command
174 ########################################################################
175
176 sub as_command($) {
177     local $_ = shift;
178
179     my $read_files;
180     my $write_files;
181
182     if(/-o\s+(\S+)\s+(\S+)$/) {
183         $write_files = [$1];
184         $read_files = [$2];
185     } else {
186         error("as_command");
187     }
188
189     return ($read_files, $write_files);
190 }
191
192 ########################################################################
193 # bision_command
194 ########################################################################
195
196 sub bison_command($) {
197     local $_ = shift;
198
199     return ([], []);
200 }
201
202 ########################################################################
203 # cd_command
204 ########################################################################
205
206 sub cd_command($) {
207     local $_ = shift;
208
209     return ([], []);
210 }
211
212 ########################################################################
213 # cd_output
214 ########################################################################
215
216 sub cd_output($) {
217     local $_ = shift;
218
219     if(/^(.*?): No such file or directory/) {
220         $message = "directory '$1' doesn't exist";
221     }
222 }
223
224 ########################################################################
225 # flex_command
226 ########################################################################
227
228 sub flex_command($) {
229     local $_ = shift;
230
231     return ([], []);
232 }
233
234 ########################################################################
235 # for_command
236 ########################################################################
237
238 sub for_command($) {
239     local $_ = shift;
240
241     return ([], []);
242 }
243
244 ########################################################################
245 # gcc_command
246 ########################################################################
247
248 sub gcc_command($) {
249     my $read_files;
250     my $write_files;
251
252     if(/-o\s+(\S+)\s+(\S+)$/) {
253         my $write_file = $1;
254         my $read_file = $2;
255
256         $write_file =~ s%^\./%%;
257         $read_file =~ s%^\./%%;
258
259         $write_files = [$write_file];
260         $read_files = [$read_file];
261     } elsif(/-o\s+(\S+)/) {
262         my $write_file = $1;
263
264         $write_file =~ s%^\./%%;
265
266         $write_files = [$write_file];
267         $read_files = ["<???>"];
268     } elsif(/^-shared.*?-o\s+(\S+)/) {
269         my $write_file = $1;
270
271         $write_file =~ s%^\./%%;
272
273         $write_files = [$write_file];
274         $read_files = ["<???>"];
275     } else {
276         error("gcc_command");
277     }
278
279     return ($read_files, $write_files);
280 }
281
282 ########################################################################
283 # gcc_output
284 ########################################################################
285
286 sub gcc_output($$) {
287     $file = shift;
288     local $_ = shift;
289
290     if(s/^(\d+):\s+//) {
291         $line = $1;
292         if(s/^warning:\s+//) {
293             my $suppress = 0;
294
295             if(/^((?:signed |unsigned )?(?:int|long)) format, (different type|\S+) arg \(arg (\d+)\)$/) {
296                 my $type = $2;
297                 if($type =~ /^(?:
298                    HACCEL|HACMDRIVER|HANDLE|HBITMAP|HBRUSH|HCALL|HCURSOR|HDC|HDRVR|HDESK|HDRAWDIB
299                    HGDIOBJ|HKL|HGLOBAL|HIMC|HINSTANCE|HKEY|HLOCAL|
300                    HMENU|HMIDISTRM|HMIDIIN|HMIDIOUT|HMIXER|HMIXEROBJ|HMMIO|HMODULE|
301                    HLINE|HPEN|HPHONE|HPHONEAPP|
302                    HRASCONN|HRGN|HRSRC|HWAVEIN|HWAVEOUT|HWINSTA|HWND|
303                    SC_HANDLE|WSAEVENT|handle_t|pointer)$/x)
304                 {
305                     $suppress = 1;
306                 } else {
307                     $suppress = 0;
308                 }
309             } elsif(/^\(near initialization for \`(.*?)\'\)$/) {
310                 $suppress = 0;
311             } elsif(/^\`(.*?)\' defined but not used$/) {
312                 $suppress = 0;
313             } elsif(/^\`(.*?)\' is not at beginning of declaration$/) {
314                 $suppress = 0;
315             } elsif(/^\`%x\' yields only last 2 digits of year in some locales$/) {
316                 $suppress = 1;
317             } elsif(/^assignment makes integer from pointer without a cast$/) {
318                 $suppress = 0;
319             } elsif(/^assignment makes pointer from integer without a cast$/) {
320                 $suppress = 0;
321             } elsif(/^assignment from incompatible pointer type$/) {
322                 $suppress = 0;
323             } elsif(/^cast from pointer to integer of different size$/) {
324                 $suppress = 0;
325             } elsif(/^comparison between pointer and integer$/) {
326                 $suppress = 0;
327             } elsif(/^comparison between signed and unsigned$/) {
328                 $suppress = 0;
329             } elsif(/^comparison of unsigned expression < 0 is always false$/) {
330                 $suppress = 0;
331             } elsif(/^comparison of unsigned expression >= 0 is always true$/) {
332                 $suppress = 0;
333             } elsif(/^conflicting types for built-in function \`(.*?)\'$/) {
334                 $suppress = 0;
335             } elsif(/^empty body in an if-statement$/) {
336                 $suppress = 0;
337             } elsif(/^empty body in an else-statement$/) {
338                 $suppress = 0;
339             } elsif(/^implicit declaration of function \`(.*?)\'$/) {
340                 $suppress = 0;
341             } elsif(/^initialization from incompatible pointer type$/) {
342                 $suppress = 0;
343             } elsif(/^initialization makes pointer from integer without a cast$/) {
344                 $suppress = 0;
345             } elsif(/^missing initializer$/) {
346                 $suppress = 0;
347             } elsif(/^ordered comparison of pointer with integer zero$/) {
348                 $suppress = 0;
349             } elsif(/^passing arg (\d+) of (?:pointer to function|\`(\S+)\') from incompatible pointer type$/) {
350                 $suppress = 0;
351             } elsif(/^passing arg (\d+) of (?:pointer to function|\`(\S+)\') makes integer from pointer without a cast$/) {
352                 $suppress = 0;
353             } elsif(/^passing arg (\d+) of (?:pointer to function|\`(\S+)\') makes pointer from integer without a cast$/) {
354                 $suppress = 0;
355             } elsif(/^return makes integer from pointer without a cast$/) {
356                 $suppress = 0;
357             } elsif(/^return makes pointer from integer without a cast$/) {
358                 $suppress = 0;
359             } elsif(/^type of \`(.*?)\' defaults to \`(.*?)\'$/) {
360                 $suppress = 0;
361             } elsif(/^unused variable \`(.*?)\'$/) {
362                 $suppress = 0;
363             } elsif(!$options->pedantic) {
364                 $suppress = 0;
365             } else {
366                 error("gcc_output");
367             }
368
369             if(!$suppress) {
370                 if($function) {
371                     $message = "function $function: warning: $_";
372                 } else {
373                     $message = "warning: $_";
374                 }
375             } else {
376                 $message = "";
377             }
378         } elsif(/^\`(.*?)\' undeclared \(first use in this function\)$/) {
379             $message = "$_";
380         } elsif(/^\(Each undeclared identifier is reported only once$/) {
381             $message = "$_";
382         } elsif(/^conflicting types for \`(.*?)\'$/) {
383             $message = "$_";
384         } elsif(/^for each function it appears in.\)$/) {
385             $message = "$_";
386         } elsif(/^too many arguments to function$/) {
387             $message = "$_";
388         } elsif(/^previous declaration of \`(.*?)\'$/) {
389             $message = "$_";
390         } elsif(/^parse error before `(.*?)'$/) {
391             $message = "$_";
392         } elsif(!$options->pedantic) {
393             $message = "$_";
394         } else {
395             error("gcc_output");
396         }
397     } elsif(/^In function \`(.*?)\':$/) {
398         $function = $1;
399     } elsif(/^At top level:$/) {
400         $function = "";
401     } else {
402         error("gcc_output");
403     }
404 }
405
406 ########################################################################
407 # install_command
408 ########################################################################
409
410 sub install_command($) {
411     local $_ = shift;
412
413     return ([], []);
414 }
415
416 ########################################################################
417 # ld_command
418 ########################################################################
419
420 sub ld_command($) {
421     local $_ = shift;
422
423     my $read_files;
424     my $write_files;
425
426     if(/-r\s+(.*?)\s+-o\s+(\S+)$/) {
427         $write_files = [$2];
428         $read_files = [split(/\s+/, $1)];
429     } else {
430         error("ld_command");
431     }
432
433     return ($read_files, $write_files);
434 }
435
436 ########################################################################
437 # ld_output
438 ########################################################################
439
440 sub ld_output($$) {
441     $file = shift;
442     local $_ = shift;
443
444     if(/^In function \`(.*?)\':$/) {
445         $function = $1;
446     } elsif(/^more undefined references to \`(.*?)\' follow$/) {
447         # Nothing
448     } elsif(/^the use of \`(.+?)\' is dangerous, better use \`(.+?)\'$/) {
449         # Nothing
450     } elsif(/^undefined reference to \`(.*?)\'$/) {
451         # Nothing
452     } elsif(/^warning: (.*?)\(\) possibly used unsafely; consider using (.*?)\(\)$/) {
453         # Nothing
454     } elsif(/^warning: type and size of dynamic symbol \`(.*?)\' are not defined$/) {
455         $message = "$_";
456     } else {
457         $message = "$_";
458     }
459 }
460
461 ########################################################################
462 # ldconfig_command
463 ########################################################################
464
465 sub ldconfig_command($) {
466     local $_ = shift;
467
468     return ([], []);
469 }
470
471 ########################################################################
472 # makedep_command
473 ########################################################################
474
475 sub makedep_command($) {
476     local $_ = shift;
477
478     return ([], []);
479 }
480
481 ########################################################################
482 # mkdir_command
483 ########################################################################
484
485 sub mkdir_command($) {
486     local $_ = shift;
487
488     return ([], []);
489 }
490
491 ########################################################################
492 # ranlib_command
493 ########################################################################
494
495 sub ranlib_command($) {
496     local $_ = shift;
497
498     my $read_files;
499     my $write_files;
500
501     $read_files = [split(/\s+/)];
502     $write_files = [];
503
504     return ($read_files, $write_files);
505 }
506
507 ########################################################################
508 # rm_command
509 ########################################################################
510
511 sub rm_command($) {
512     local $_ = shift;
513     s/^-f\s*//;
514     return ([], [], [split(/\s+/, $_)]);
515 }
516
517 ########################################################################
518 # sed_command
519 ########################################################################
520
521 sub sed_command($) {
522     local $_ = shift;
523
524     return ([], []);
525 }
526
527 ########################################################################
528 # strip_command
529 ########################################################################
530
531 sub strip_command($) {
532     local $_ = shift;
533
534     return ([], []);
535 }
536
537 ########################################################################
538 # winebuild_command
539 ########################################################################
540
541 sub winebuild_command($) {
542     local $_ = shift;
543
544     return ([], []);
545 }
546
547 ########################################################################
548 # winebuild_output
549 ########################################################################
550
551 sub winebuild_output($$) {
552     $file = shift;
553     local $_ = shift;
554
555     $message = $_;
556 }
557
558 ########################################################################
559 # wmc_command
560 ########################################################################
561
562 sub wmc_command($) {
563     local $_ = shift;
564
565     my $read_files;
566     my $write_files;
567
568     if(/\s+(\S+)$/) {
569         my $mc_file = $1;
570
571         my $rc_file = $mc_file;
572         $rc_file =~ s/\.mc$/.rc/;
573
574         $write_files = [$rc_file];
575         $read_files = [$mc_file];
576     } else {
577         error("wmc_command");
578     }
579
580     return ($read_files, $write_files);
581 }
582
583 ########################################################################
584 # wmc_output
585 ########################################################################
586
587 sub wmc_output($$) {
588     $file = shift;
589     local $_ = shift;
590 }
591
592 ########################################################################
593 # wrc_command
594 ########################################################################
595
596 sub wrc_command($) {
597     local $_ = shift;
598
599     my $read_files;
600     my $write_files;
601
602     if(/\s+(\S+)$/) {
603         my $rc_file = $1;
604
605         my $o_file = $rc_file;
606         $o_file =~ s/\.rc$/.o/;
607
608         $write_files = [$o_file];
609         $read_files = [$rc_file];
610     } else {
611         error("wrc_command");
612     }
613
614     return ($read_files, $write_files);
615 }
616
617 ########################################################################
618 # wrc_output
619 ########################################################################
620
621 sub wrc_output($$) {
622     $file = shift;
623     local $_ = shift;
624 }
625
626 ########################################################################
627 # command
628 ########################################################################
629
630 sub command($) {
631     local $_ = shift;
632
633     my $tool;
634     my $file;
635     my $read_files = ["<???>"];
636     my $write_files = ["<???>"];
637     my $remove_files = [];
638
639     s/^\s*(.*?)\s*$/$1/;
640
641     if(s/^\[\s+-d\s+(.*?)\s+\]\s+\|\|\s+//) {
642         # Nothing
643     }
644
645     if(s/^ar\s+//) {
646         $tool = "ar";
647         ($read_files, $write_files) = ar_command($_);
648     } elsif(s/^as\s+//) {
649         $tool = "as";
650         ($read_files, $write_files) = as_command($_);
651     } elsif(s/^bison\s+//) {
652         $tool = "bison";
653         ($read_files, $write_files) = bison_command($_);
654     } elsif(s/^cd\s+//) {
655         $tool = "cd";
656         ($read_files, $write_files) = cd_command($_);
657     } elsif(s/^flex\s+//) {
658         $tool = "flex";
659         ($read_files, $write_files) = flex_command($_);
660     } elsif(s/^for\s+//) {
661         $tool = "for";
662         ($read_files, $write_files) = for_command($_);
663     } elsif(s/^\/usr\/bin\/install\s+//) {
664         $tool = "install";
665         ($read_files, $write_files) = install_command($_);
666     } elsif(s/^ld\s+//) {
667         $tool = "ld";
668         ($read_files, $write_files) = ld_command($_);
669     } elsif(s/^\/sbin\/ldconfig\s+//) {
670         $tool = "ldconfig";
671         ($read_files, $write_files) = ldconfig_command();
672     } elsif(s/^gcc\s+//) {
673         $tool = "gcc";
674         ($read_files, $write_files) = gcc_command($_);
675     } elsif(s/^(?:(?:\.\.\/)+|\.\/)tools\/makedep\s+//) {
676         $tool = "makedep";
677         ($read_files, $write_files) = makedep_command($_);
678     } elsif(s/^mkdir\s+//) {
679         $tool = "mkdir";
680         ($read_files, $write_files) = mkdir_command($_);
681     } elsif(s/^ranlib\s+//) {
682         $tool = "ranlib";
683         ($read_files, $write_files) = ranlib_command($_);
684     } elsif(s/^rm\s+//) {
685         $tool = "rm";
686         ($read_files, $write_files, $remove_files) = rm_command($_);
687     } elsif(s/^sed\s+//) {
688         $tool = "sed";
689         ($read_files, $write_files) = sed_command($_);
690     } elsif(s/^strip\s+//) {
691         $tool = "sed";
692         ($read_files, $write_files) = strip_command($_);
693     } elsif(s/^LD_LIBRARY_PATH="(?:(?:\.\.\/)*unicode)?:\$LD_LIBRARY_PATH"\s+(?:\.\.\/)*tools\/winebuild\/winebuild\s+//) {
694         $tool = "winebuild";
695         ($read_files, $write_files) = winebuild_command($_);
696     } elsif(s/^LD_LIBRARY_PATH="(?:(?:\.\.\/)*unicode)?:\$LD_LIBRARY_PATH"\s+(?:\.\.\/)*tools\/wmc\/wmc\s+//) {
697         $tool = "wmc";
698         ($read_files, $write_files) = wmc_command($_);
699     } elsif(s/^LD_LIBRARY_PATH="(?:(?:\.\.\/)*unicode)?:\$LD_LIBRARY_PATH"\s+(?:\.\.\/)*tools\/wrc\/wrc\s+//) {
700         $tool = "wrc";
701         ($read_files, $write_files) = wrc_command($_);
702     }
703
704     return ($tool, $read_files, $write_files, $remove_files);
705 }
706
707 ########################################################################
708 # line
709 ########################################################################
710
711 sub line($) {
712     local $_ = shift;
713
714     $file = "";
715     $line = "";
716     $message = "";
717
718     $current = $_;
719
720     my ($new_tool, $read_files, $write_files, $remove_files) = command($_);
721     if(defined($new_tool)) {
722         $tool = $new_tool;
723
724         $function = "";
725
726         my $progress = "";
727         if($directory && $directory ne ".") {
728             $progress .= "$directory: ";
729         }
730         if($tool) {
731             $progress .= "$tool: ";
732         }
733
734         if($tool =~ /^(?:cd|make)$/) {
735             # Nothing
736         } elsif($tool eq "ld"/) {
737             foreach my $file (@{$read_files}) {
738                 $output->lazy_progress("${progress}reading '$file'");
739             }
740             my $file = $$write_files[0];
741             $output->progress("$progress: writing '$file'");
742         } elsif($tool eq "rm") {
743             foreach my $file (@{$remove_files}) {
744                 $output->lazy_progress("${progress}removing '$file'");
745             }
746         } else {
747             if($#$read_files >= 0) {
748                 $progress .= "read[" . join(" ", @{$read_files}) . "]";
749             }
750             if($#$write_files >= 0) {
751                 if($#$read_files >= 0) {
752                     $progress .= ", ";
753                 }
754                 $progress .= "write[" . join(" ", @{$write_files}) . "]";
755             }
756             if($#$remove_files >= 0) {
757                 if($#$read_files >= 0 || $#$write_files >= 0) {
758                     $progress .= ", ";
759                 }
760                 $progress .= "remove[" . join(" ", @{$remove_files}) . "]";
761             }
762
763             $output->progress($progress);
764         }
765
766         return 0;
767     }
768
769     my $make = $options->make;
770
771     if(/^Wine build complete\.$/) {
772         # Nothing
773     } elsif(/^(.*?) is newer than (.*?), please rerun (.*?)\!$/) {
774         $message = "$_";
775     } elsif(/^(.*?) is older than (.*?), please rerun (.*?)$/) {
776         $message = "$_";
777     } elsif(/^\`(.*?)\' is up to date.$/) {
778         $tool = "make";
779         make_output($1, $_);
780     } elsif(s/^$make(?:\[(\d+)\])?:\s*//) {
781         $tool = "make";
782         make_output($1, $_);
783     } elsif(!defined($tool)) {
784         error("line");
785     } elsif($tool eq "make") {
786         make_output($1, $_);
787     } elsif($tool eq "bison" && /^conflicts:\s+\d+\s+shift\/reduce$/) {
788         # Nothing
789     } elsif($tool eq "gcc" && /^(?:In file included |\s*)from (.+?):(\d+)[,:]$/) {
790         # Nothing
791     } elsif($tool =~ /^(?:gcc|ld)$/ && s/^(.+?\.s?o)(?:\(.*?\))?:\s*//) {
792         $tool = "ld";
793         ld_output($1, $_)
794     } elsif($tool =~ /^(?:gcc|ld)$/ && s/^(.*?)ld:\s*//) {
795         $tool = "ld";
796         ld_output("", $_)
797     } elsif($tool =~ /^(?:gcc|ld)$/ && s/^collect2:\s*//) {
798         $tool = "ld";
799         ld_output("collect2", $_);
800     } elsif($tool eq "gcc" && s/^(.+?\.[chly]):\s*//) {
801         gcc_output($1, $_);
802     } elsif($tool eq "ld" && s/^(.+?\.c):(?:\d+:)?\s*//) {
803         ld_output($1, $_);
804     } elsif($tool eq "winebuild" && s/^(.+?\.spec):\s*//) {
805         winebuild_output($1, $_);
806     } elsif($tool eq "wmc" && s/^(.+?\.mc):\s*//) {
807         wmc_output($1, $_);
808     } elsif($tool eq "wrc" && s/^(.+?\.rc):\s*//) {
809         wrc_output($1, $_);
810     } elsif($tool eq "cd" && s/^\/bin\/sh:\s*cd:\s*//) {
811         parse_cd_output($_);
812     } elsif(/^\s*$/) {
813         # Nothing
814     } else {
815         error("line");
816     }
817
818     $file =~ s/^\.\///;
819
820     return 1;
821 }
822
823 1;