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