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