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