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