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