Fixed some issues found by winapi_check.
[wine] / tools / winapi / c_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 c_parser;
20
21 use strict;
22
23 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
24 require Exporter;
25
26 @ISA = qw(Exporter);
27 @EXPORT = qw();
28 @EXPORT_OK = qw();
29
30 use options qw($options);
31 use output qw($output);
32
33 use c_function;
34 use c_type;
35
36 ########################################################################
37 # new
38 #
39 sub new {
40     my $proto = shift;
41     my $class = ref($proto) || $proto;
42     my $self  = {};
43     bless ($self, $class);
44
45     my $file = \${$self->{FILE}};
46     my $create_function = \${$self->{CREATE_FUNCTION}};
47     my $create_type = \${$self->{CREATE_TYPE}};
48     my $found_comment = \${$self->{FOUND_COMMENT}};
49     my $found_declaration = \${$self->{FOUND_DECLARATION}};
50     my $found_function = \${$self->{FOUND_FUNCTION}};
51     my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
52     my $found_line = \${$self->{FOUND_LINE}};
53     my $found_preprocessor = \${$self->{FOUND_PREPROCESSOR}};
54     my $found_statement = \${$self->{FOUND_STATEMENT}};
55     my $found_type = \${$self->{FOUND_TYPE}};
56     my $found_variable = \${$self->{FOUND_VARIABLE}};
57
58     $$file = shift;
59
60     $$create_function = sub { return new c_function; };
61     $$create_type = sub { return new c_type; };
62     $$found_comment = sub { return 1; };
63     $$found_declaration = sub { return 1; };
64     $$found_function = sub { return 1; };
65     $$found_function_call = sub { return 1; };
66     $$found_line = sub { return 1; };
67     $$found_preprocessor = sub { return 1; };
68     $$found_statement = sub { return 1; };
69     $$found_type = sub { return 1; };
70     $$found_variable = sub { return 1; };
71
72     return $self;
73 }
74
75 ########################################################################
76 # set_found_comment_callback
77 #
78 sub set_found_comment_callback {
79     my $self = shift;
80
81     my $found_comment = \${$self->{FOUND_COMMENT}};
82
83     $$found_comment = shift;
84 }
85
86 ########################################################################
87 # set_found_declaration_callback
88 #
89 sub set_found_declaration_callback {
90     my $self = shift;
91
92     my $found_declaration = \${$self->{FOUND_DECLARATION}};
93
94     $$found_declaration = shift;
95 }
96
97 ########################################################################
98 # set_found_function_callback
99 #
100 sub set_found_function_callback {
101     my $self = shift;
102
103     my $found_function = \${$self->{FOUND_FUNCTION}};
104
105     $$found_function = shift;
106 }
107
108 ########################################################################
109 # set_found_function_call_callback
110 #
111 sub set_found_function_call_callback {
112     my $self = shift;
113
114     my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
115
116     $$found_function_call = shift;
117 }
118
119 ########################################################################
120 # set_found_line_callback
121 #
122 sub set_found_line_callback {
123     my $self = shift;
124
125     my $found_line = \${$self->{FOUND_LINE}};
126
127     $$found_line = shift;
128 }
129
130 ########################################################################
131 # set_found_preprocessor_callback
132 #
133 sub set_found_preprocessor_callback {
134     my $self = shift;
135
136     my $found_preprocessor = \${$self->{FOUND_PREPROCESSOR}};
137
138     $$found_preprocessor = shift;
139 }
140
141 ########################################################################
142 # set_found_statement_callback
143 #
144 sub set_found_statement_callback {
145     my $self = shift;
146
147     my $found_statement = \${$self->{FOUND_STATEMENT}};
148
149     $$found_statement = shift;
150 }
151
152 ########################################################################
153 # set_found_type_callback
154 #
155 sub set_found_type_callback {
156     my $self = shift;
157
158     my $found_type = \${$self->{FOUND_TYPE}};
159
160     $$found_type = shift;
161 }
162
163 ########################################################################
164 # set_found_variable_callback
165 #
166 sub set_found_variable_callback {
167     my $self = shift;
168
169     my $found_variable = \${$self->{FOUND_VARIABLE}};
170
171     $$found_variable = shift;
172 }
173
174
175 ########################################################################
176 # _format_c_type
177
178 sub _format_c_type {
179     my $self = shift;
180
181     local $_ = shift;
182     s/^\s*(.*?)\s*$/$1/;
183
184     if (/^(\w+(?:\s*\*)*)\s*\(\s*\*\s*\)\s*\(\s*(.*?)\s*\)$/s) {
185         my $return_type = $1;
186         my @arguments = split(/\s*,\s*/, $2);
187         foreach my $argument (@arguments) {
188             if ($argument =~ s/^(\w+(?:\s*\*)*)\s*\w+$/$1/) { 
189                 $argument =~ s/\s+/ /g;
190                 $argument =~ s/\s*\*\s*/*/g;
191                 $argument =~ s/(\*+)$/ $1/;
192             }
193         }
194
195         $_ = "$return_type (*)(" . join(", ", @arguments) . ")";
196     }
197     
198     return $_;
199 }
200
201
202 ########################################################################
203 # _parse_c
204
205 sub _parse_c {
206     my $self = shift;
207
208     my $pattern = shift;
209     my $refcurrent = shift;
210     my $refline = shift;
211     my $refcolumn = shift;
212
213     my $refmatch = shift;
214
215     local $_ = $$refcurrent;
216     my $line = $$refline;
217     my $column = $$refcolumn;
218
219     my $match;
220     if(s/^(?:$pattern)//s) {
221         $self->_update_c_position($&, \$line, \$column);
222         $match = $&;
223     } else {
224         return 0;
225     }
226
227     $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
228
229     $$refcurrent = $_;
230     $$refline = $line;
231     $$refcolumn = $column;
232
233     $$refmatch = $match;
234
235     return 1;
236 }
237
238 ########################################################################
239 # _parse_c_error
240
241 sub _parse_c_error {
242     my $self = shift;
243
244     local $_ = shift;
245     my $line = shift;
246     my $column = shift;
247     my $context = shift;
248     my $message = shift;
249
250     $message = "parse error" if !$message;
251
252     # Why did I do this?
253     if($output->prefix) {
254         # $output->write("\n");
255         $output->prefix("");
256     }
257
258     $self->_parse_c_warning($_, $line, $column, $context, $message);
259
260     exit 1;
261 }
262
263 ########################################################################
264 # _parse_c_warning
265 #
266 # FIXME: Use caller (See man perlfunc)
267
268 sub _parse_c_warning {
269     my $self = shift;
270
271     local $_ = shift;
272     my $line = shift;
273     my $column = shift;
274     my $context = shift;
275     my $message = shift;
276
277     my $file = \${$self->{FILE}};
278
279     $message = "warning" if !$message;
280
281     my $current = "";
282     if($_) {
283         my @lines = split(/\n/, $_);
284
285         $current .= $lines[0] . "\n" if $lines[0];
286         $current .= $lines[1] . "\n" if $lines[1];
287     }
288
289     if (0) {
290         (my $package, my $filename, my $line) = caller(0);
291         $output->write("*** caller ***: $filename:$line\n");
292     }
293
294     if($current) {
295         $output->write("$$file:$line." . ($column + 1) . ": $context: $message: \\\n$current");
296     } else {
297         $output->write("$$file:$line." . ($column + 1) . ": $context: $message\n");
298     }
299 }
300
301 ########################################################################
302 # __parse_c_until_one_of
303
304 sub __parse_c_until_one_of {
305     my $self = shift;
306
307     my $characters = shift;
308     my $on_same_level = shift;
309     my $refcurrent = shift;
310     my $refline = shift;
311     my $refcolumn = shift;
312     my $match = shift;
313
314     local $_ = $$refcurrent;
315     my $line = $$refline;
316     my $column = $$refcolumn;
317
318
319     if(!defined($match)) {
320         my $blackhole;
321         $match = \$blackhole;
322     }
323
324     my $level = 0;
325     $$match = "";
326     while(/^[^$characters]/s || $level > 0) {
327         my $submatch = "";
328
329         if ($level > 0) {
330             if(s/^[^\(\)\[\]\{\}\n\t\'\"]*//s) {
331                 $submatch .= $&;
332             }
333         } elsif ($on_same_level) {
334             if(s/^[^$characters\(\)\[\]\{\}\n\t\'\"]*//s) {
335                 $submatch .= $&;
336             }
337         } else {
338             if(s/^[^$characters\n\t\'\"]*//s) {
339                 $submatch .= $&;
340             }
341         }
342
343         if(s/^\'//) {
344             $submatch .= "\'";
345             while(/^./ && !s/^\'//) {
346                 s/^([^\'\\]*)//s;
347                 $submatch .= $1;
348                 if(s/^\\//) {
349                     $submatch .= "\\";
350                     if(s/^(.)//s) {
351                         $submatch .= $1;
352                         if($1 eq "0") {
353                             s/^(\d{0,3})//s;
354                             $submatch .= $1;
355                         }
356                     }
357                 }
358             }
359             $submatch .= "\'";
360
361             $$match .= $submatch;
362             $column += length($submatch);
363         } elsif(s/^\"//) {
364             $submatch .= "\"";
365             while(/^./ && !s/^\"//) {
366                 s/^([^\"\\]*)//s;
367                 $submatch .= $1;
368                 if(s/^\\//) {
369                     $submatch .= "\\";
370                     if(s/^(.)//s) {
371                         $submatch .= $1;
372                         if($1 eq "0") {
373                             s/^(\d{0,3})//s;
374                             $submatch .= $1;
375                         }
376                     }
377                 }
378             }
379             $submatch .= "\"";
380
381             $$match .= $submatch;
382             $column += length($submatch);
383         } elsif($on_same_level && s/^[\(\[\{]//) {
384             $level++;
385
386             $submatch .= $&;
387             $$match .= $submatch;
388             $column++;
389         } elsif($on_same_level && s/^[\)\]\}]//) {
390             if ($level > 0) {
391                 $level--;
392                 
393                 $submatch .= $&;
394                 $$match .= $submatch;
395                 $column++;
396             } else {
397                 $_ = "$&$_";
398                 $$match .= $submatch;
399                 last;
400             }
401         } elsif(s/^\n//) {
402             $submatch .= "\n";
403
404             $$match .= $submatch;
405             $line++;
406             $column = 0;
407         } elsif(s/^\t//) {
408             $submatch .= "\t";
409
410             $$match .= $submatch;
411             $column = $column + 8 - $column % 8;
412         } else {
413             $$match .= $submatch;
414             $column += length($submatch);
415         }
416     }
417
418     $$refcurrent = $_;
419     $$refline = $line;
420     $$refcolumn = $column;
421     return 1;
422 }
423
424 ########################################################################
425 # _parse_c_until_one_of
426
427 sub _parse_c_until_one_of {
428     my $self = shift;
429
430     my $characters = shift;
431     my $refcurrent = shift;
432     my $refline = shift;
433     my $refcolumn = shift;
434     my $match = shift;
435
436     return $self->__parse_c_until_one_of($characters, 0, $refcurrent, $refline, $refcolumn, $match);
437 }
438
439 ########################################################################
440 # _parse_c_on_same_level_until_one_of
441
442 sub _parse_c_on_same_level_until_one_of {
443     my $self = shift;
444
445     my $characters = shift;
446     my $refcurrent = shift;
447     my $refline = shift;
448     my $refcolumn = shift;
449     my $match = shift;
450
451     return $self->__parse_c_until_one_of($characters, 1, $refcurrent, $refline, $refcolumn, $match);
452 }
453
454 ########################################################################
455 # _update_c_position
456
457 sub _update_c_position {
458     my $self = shift;
459
460     local $_ = shift;
461     my $refline = shift;
462     my $refcolumn = shift;
463
464     my $line = $$refline;
465     my $column = $$refcolumn;
466
467     while($_) {
468         if(s/^[^\n\t\'\"]*//s) {
469             $column += length($&);
470         }
471
472         if(s/^\'//) {
473             $column++;
474             while(/^./ && !s/^\'//) {
475                 s/^([^\'\\]*)//s;
476                 $column += length($1);
477                 if(s/^\\//) {
478                     $column++;
479                     if(s/^(.)//s) {
480                         $column += length($1);
481                         if($1 eq "0") {
482                             s/^(\d{0,3})//s;
483                             $column += length($1);
484                         }
485                     }
486                 }
487             }
488             $column++;
489         } elsif(s/^\"//) {
490             $column++;
491             while(/^./ && !s/^\"//) {
492                 s/^([^\"\\]*)//s;
493                 $column += length($1);
494                 if(s/^\\//) {
495                     $column++;
496                     if(s/^(.)//s) {
497                         $column += length($1);
498                         if($1 eq "0") {
499                             s/^(\d{0,3})//s;
500                             $column += length($1);
501                         }
502                     }
503                 }
504             }
505             $column++;
506         } elsif(s/^\n//) {
507             $line++;
508             $column = 0;
509         } elsif(s/^\t//) {
510             $column = $column + 8 - $column % 8;
511         }
512     }
513
514     $$refline = $line;
515     $$refcolumn = $column;
516 }
517
518 ########################################################################
519 # parse_c_block
520
521 sub parse_c_block {
522     my $self = shift;
523
524     my $refcurrent = shift;
525     my $refline = shift;
526     my $refcolumn = shift;
527
528     my $refstatements = shift;
529     my $refstatements_line = shift;
530     my $refstatements_column = shift;
531
532     local $_ = $$refcurrent;
533     my $line = $$refline;
534     my $column = $$refcolumn;
535
536     $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
537
538     my $statements;
539     if(s/^\{//) {
540         $column++;
541         $statements = "";
542     } else {
543         return 0;
544     }
545
546     $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
547
548     my $statements_line = $line;
549     my $statements_column = $column;
550
551     my $plevel = 1;
552     while($plevel > 0) {
553         my $match;
554         $self->_parse_c_until_one_of("\\{\\}", \$_, \$line, \$column, \$match);
555
556         $column++;
557
558         $statements .= $match;
559         if(s/^\}//) {
560             $plevel--;
561             if($plevel > 0) {
562                 $statements .= "}";
563             }
564         } elsif(s/^\{//) {
565             $plevel++;
566             $statements .= "{";
567         } else {
568             return 0;
569         }
570     }
571
572     $$refcurrent = $_;
573     $$refline = $line;
574     $$refcolumn = $column;
575     $$refstatements = $statements;
576     $$refstatements_line = $statements_line;
577     $$refstatements_column = $statements_column;
578
579     return 1;
580 }
581
582 ########################################################################
583 # parse_c_declaration
584
585 sub parse_c_declaration {
586     my $self = shift;
587
588     my $found_declaration = \${$self->{FOUND_DECLARATION}};
589     my $found_function = \${$self->{FOUND_FUNCTION}};
590
591     my $refcurrent = shift;
592     my $refline = shift;
593     my $refcolumn = shift;
594
595     local $_ = $$refcurrent;
596     my $line = $$refline;
597     my $column = $$refcolumn;
598
599     $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
600
601     my $begin_line = $line;
602     my $begin_column = $column + 1;
603
604     my $end_line = $begin_line;
605     my $end_column = $begin_column;
606     $self->_update_c_position($_, \$end_line, \$end_column);
607
608     if(!&$$found_declaration($begin_line, $begin_column, $end_line, $end_column, $_)) {
609         return 1;
610     }
611
612     # Function
613     my $function = shift;
614
615     my $linkage = shift;
616     my $calling_convention = shift;
617     my $return_type = shift;
618     my $name = shift;
619     my @arguments = shift;
620     my @argument_lines = shift;
621     my @argument_columns = shift;
622
623     # Variable
624     my $type;
625
626     if(0) {
627         # Nothing
628     } elsif(s/^WINE_(?:DEFAULT|DECLARE)_DEBUG_CHANNEL\s*\(\s*(\w+)\s*\)\s*//s) { # FIXME: Wine specific kludge
629         $self->_update_c_position($&, \$line, \$column);
630     } elsif(s/^__ASM_GLOBAL_FUNC\(\s*(\w+)\s*,\s*//s) { # FIXME: Wine specific kludge
631         $self->_update_c_position($&, \$line, \$column);
632         $self->_parse_c_until_one_of("\)", \$_, \$line, \$column);
633         if(s/\)//) {
634             $column++;
635         }
636     } elsif(s/^(?:DECLARE_OLD_HANDLE|DEFINE_AVIGUID|DEFINE_OLEGUID)\s*(?=\()//s) { # FIXME: Wine specific kludge
637         $self->_update_c_position($&, \$line, \$column);
638
639         my @arguments;
640         my @argument_lines;
641         my @argument_columns;
642
643         if(!$self->parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
644             return 0;
645         }
646     } elsif(s/^DEFINE_COMMON_NOTIFICATIONS\(\s*(\w+)\s*,\s*(\w+)\s*\)//s) { # FIXME: Wine specific kludge
647         $self->_update_c_position($&, \$line, \$column);
648     } elsif(s/^MAKE_FUNCPTR\(\s*(\w+)\s*\)//s) { # FIXME: Wine specific kludge
649         $self->_update_c_position($&, \$line, \$column);
650     } elsif(s/^START_TEST\(\s*(\w+)\s*\)\s*{//s) { # FIXME: Wine specific kludge
651         $self->_update_c_position($&, \$line, \$column);
652     } elsif(s/^int\s*_FUNCTION_\s*{//s) { # FIXME: Wine specific kludge
653         $self->_update_c_position($&, \$line, \$column);
654     } elsif(s/^(?:jump|strong)_alias//s) { # FIXME: GNU C library specific kludge
655         $self->_update_c_position($&, \$line, \$column);
656     } elsif(s/^(?:__asm__|asm)\s*\(//) {
657         $self->_update_c_position($&, \$line, \$column);
658     } elsif($self->parse_c_typedef(\$_, \$line, \$column)) {
659         # Nothing
660     } elsif($self->parse_c_variable(\$_, \$line, \$column, \$linkage, \$type, \$name)) {
661         # Nothing
662     } elsif($self->parse_c_function(\$_, \$line, \$column, \$function)) {
663         if(&$$found_function($function))
664         {
665             my $statements = $function->statements;
666             my $statements_line = $function->statements_line;
667             my $statements_column = $function->statements_column;
668
669             if(defined($statements)) {
670                 if(!$self->parse_c_statements(\$statements, \$statements_line, \$statements_column)) {
671                     return 0;
672                 }
673             }
674         }
675     } else {
676         $self->_parse_c_error($_, $line, $column, "declaration");
677     }
678
679     $$refcurrent = $_;
680     $$refline = $line;
681     $$refcolumn = $column;
682
683     return 1;
684 }
685
686 ########################################################################
687 # parse_c_declarations
688
689 sub parse_c_declarations {
690     my $self = shift;
691
692     my $refcurrent = shift;
693     my $refline = shift;
694     my $refcolumn = shift;
695
696     return 1;
697 }
698
699 ########################################################################
700 # parse_c_expression
701
702 sub parse_c_expression {
703     my $self = shift;
704
705     my $refcurrent = shift;
706     my $refline = shift;
707     my $refcolumn = shift;
708
709     my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
710
711     local $_ = $$refcurrent;
712     my $line = $$refline;
713     my $column = $$refcolumn;
714
715     $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
716
717     while($_) {
718         if(s/^(.*?)(\w+\s*\()/$2/s) {
719             $self->_update_c_position($1, \$line, \$column);
720
721             my $begin_line = $line;
722             my $begin_column = $column + 1;
723
724             my $name;
725             my @arguments;
726             my @argument_lines;
727             my @argument_columns;
728             if(!$self->parse_c_function_call(\$_, \$line, \$column, \$name, \@arguments, \@argument_lines, \@argument_columns)) {
729                 return 0;
730             }
731
732             if(&$$found_function_call($begin_line, $begin_column, $line, $column, $name, \@arguments))
733             {
734                 while(defined(my $argument = shift @arguments) &&
735                       defined(my $argument_line = shift @argument_lines) &&
736                       defined(my $argument_column = shift @argument_columns))
737                 {
738                     $self->parse_c_expression(\$argument, \$argument_line, \$argument_column);
739                 }
740             }
741         } else {
742             $_ = "";
743         }
744     }
745
746     $self->_update_c_position($_, \$line, \$column);
747
748     $$refcurrent = $_;
749     $$refline = $line;
750     $$refcolumn = $column;
751
752     return 1;
753 }
754
755 ########################################################################
756 # parse_c_file
757
758 sub parse_c_file {
759     my $self = shift;
760
761     my $found_comment = \${$self->{FOUND_COMMENT}};
762     my $found_line = \${$self->{FOUND_LINE}};
763
764     my $refcurrent = shift;
765     my $refline = shift;
766     my $refcolumn = shift;
767
768     local $_ = $$refcurrent;
769     my $line = $$refline;
770     my $column = $$refcolumn;
771
772     my $declaration = "";
773     my $declaration_line = $line;
774     my $declaration_column = $column;
775
776     my $previous_line = 0;
777     my $previous_column = -1;
778
779     my $if = 0;
780     my $if0 = 0;
781     my $extern_c = 0;
782
783     my $blevel = 1;
784     my $plevel = 1;
785     while($plevel > 0 || $blevel > 0) {
786         my $match;
787         $self->_parse_c_until_one_of("#/\\(\\)\\[\\]\\{\\};", \$_, \$line, \$column, \$match);
788
789         if($line != $previous_line) {
790             &$$found_line($line);
791         } elsif(0 && $column == $previous_column) {
792             $self->_parse_c_error($_, $line, $column, "file", "no progress");
793         } else {
794             # &$$found_line("$line.$column");
795         }
796         $previous_line = $line;
797         $previous_column = $column;
798
799         if($match !~ /^\s+$/s && $options->debug) {
800             $self->_parse_c_warning($_, $line, $column, "file", "$plevel $blevel: '$declaration' '$match'");
801         }
802
803         if(!$declaration && $match =~ s/^\s+//s) {
804             $self->_update_c_position($&, \$declaration_line, \$declaration_column);
805         }
806
807         if(!$if0) {
808             $declaration .= $match;
809
810             # FIXME: Kludge
811             if ($declaration =~ s/^extern\s*\"C\"//s) {
812                 if (s/^\{//) {
813                     $self->_update_c_position($&, \$line, \$column);
814                     $declaration = "";
815                     $declaration_line = $line;
816                     $declaration_column = $column;
817
818                     $extern_c = 1;
819                     next;
820                 }
821             } elsif ($extern_c && $blevel == 1 && $plevel == 1 && !$declaration) {
822                 if (s/^\}//) {
823                     $self->_update_c_position($&, \$line, \$column);
824                     $declaration = "";
825                     $declaration_line = $line;
826                     $declaration_column = $column;
827                     
828                     $extern_c = 0;
829                     next;
830                 }
831             } elsif($declaration =~ s/^(?:__DEFINE_(?:GET|SET)_SEG|OUR_GUID_ENTRY)\s*(?=\()//sx) { # FIXME: Wine specific kludge
832                 my $prefix = $&;
833                 if ($plevel > 2 || !s/^\)//) {
834                     $declaration = "$prefix$declaration";
835                 } else {
836                     $plevel--;
837                     $self->_update_c_position($&, \$line, \$column);
838                     $declaration .= $&;
839
840                     my @arguments;
841                     my @argument_lines;
842                     my @argument_columns;
843
844                     if(!$self->parse_c_tuple(\$declaration, \$declaration_line, \$declaration_column,
845                                              \@arguments, \@argument_lines, \@argument_columns)) 
846                     {
847                         $self->_parse_c_error($declaration, $declaration_line, $declaration_column, "file", "tuple expected");
848                     }
849
850                     $declaration = "";
851                     $declaration_line = $line;
852                     $declaration_column = $column;
853                     
854                     next;
855                 }
856             } elsif ($declaration =~ s/^(?:DEFINE_SHLGUID)\s*\(.*?\)//s) {
857                 $self->_update_c_position($&, \$declaration_line, \$declaration_column);
858             } elsif ($declaration =~ s/^(?:DECL_WINELIB_TYPE_AW|DECLARE_HANDLE(?:16)?|TYPE_MARSHAL)\(\s*(\w+)\s*\)\s*//s) {
859                 $self->_update_c_position($&, \$declaration_line, \$declaration_column);
860             } elsif ($declaration =~ s/^ICOM_DEFINE\(\s*(\w+)\s*,\s*(\w+)\s*\)\s*//s) {
861                 $self->_update_c_position($&, \$declaration_line, \$declaration_column);
862             }
863         } else {
864             my $blank_lines = 0;
865
866             local $_ = $match;
867             while(s/^.*?\n//) { $blank_lines++; }
868
869             if(!$declaration) {
870                 $declaration_line = $line;
871                 $declaration_column = $column;
872             } else {
873                 $declaration .= "\n" x $blank_lines;
874             }
875
876         }
877
878         if(/^[\#\/]/) {
879             my $blank_lines = 0;
880             if(s/^\#\s*//) {
881                 my $preprocessor_line = $line;
882                 my $preprocessor_column = $column;
883
884                 my $preprocessor = $&;
885                 while(s/^(.*?)\\\s*\n//) {
886                     $blank_lines++;
887                     $preprocessor .= "$1\n";
888                 }
889                 if(s/^(.*?)(\/\*.*?\*\/)(.*?)\n//) {
890                     $_ = "$2\n$_";
891                     if(defined($3)) {
892                         $preprocessor .= "$1$3";
893                     } else {
894                         $preprocessor .= $1;
895                     }
896                 } elsif(s/^(.*?)(\/[\*\/].*?)?\n//) {
897                     if(defined($2)) {
898                         $_ = "$2\n$_";
899                     } else {
900                         $blank_lines++;
901                     }
902                     $preprocessor .= $1;
903                 }
904
905                 if($if0 && $preprocessor =~ /^\#\s*endif/) {
906                     if($if0 > 0) {
907                         if($if > 0) {
908                             $if--;
909                         } else {
910                             $if0--;
911                         }
912                     }
913                 } elsif($preprocessor =~ /^\#\s*if/) {
914                     if($preprocessor =~ /^\#\s*if\s*0/) {
915                         $if0++;
916                     } elsif($if0 > 0) {
917                         $if++;
918                     }
919                 }
920
921                 if(!$self->parse_c_preprocessor(\$preprocessor, \$preprocessor_line, \$preprocessor_column)) {
922                      return 0;
923                 }
924             }
925
926             if(s/^\/\*.*?\*\///s) {
927                 &$$found_comment($line, $column + 1, $&);
928                 local $_ = $&;
929                 while(s/^.*?\n//) {
930                     $blank_lines++;
931                 }
932                 if($_) {
933                     $column += length($_);
934                 }
935             } elsif(s/^\/\/(.*?)\n//) {
936                 &$$found_comment($line, $column + 1, $&);
937                 $blank_lines++;
938             } elsif(s/^\///) {
939                 if(!$if0) {
940                     $declaration .= $&;
941                     $column++;
942                 }
943             }
944
945             $line += $blank_lines;
946             if($blank_lines > 0) {
947                 $column = 0;
948             }
949
950             if(!$declaration) {
951                 $declaration_line = $line;
952                 $declaration_column = $column;
953             } elsif($blank_lines > 0) {
954                 $declaration .= "\n" x $blank_lines;
955             }
956
957             next;
958         }
959
960         $column++;
961
962         if($if0) {
963             s/^.//;
964             next;
965         }
966
967         if(s/^[\(\[]//) {
968             $plevel++;
969             $declaration .= $&;
970         } elsif(s/^\]//) {
971             $plevel--;
972             $declaration .= $&;
973         } elsif(s/^\)//) {
974             $plevel--;
975             if($blevel <= 0) {
976                 $self->_parse_c_error($_, $line, $column, "file", ") without (");
977             }
978             $declaration .= $&;
979             if($plevel == 1 && $declaration =~ /^__ASM_GLOBAL_FUNC/) {
980                 if(!$self->parse_c_declaration(\$declaration, \$declaration_line, \$declaration_column)) {
981                     return 0;
982                 }
983                 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
984                 $declaration = "";
985                 $declaration_line = $line;
986                 $declaration_column = $column;
987             }
988         } elsif(s/^\{//) {
989             $blevel++;
990             $declaration .= $&;
991         } elsif(s/^\}//) {
992             $blevel--;
993             if($blevel <= 0) {
994                 $self->_parse_c_error($_, $line, $column, "file", "} without {");
995             }
996
997             $declaration .= $&;
998
999             if($declaration =~ /^typedef/s ||
1000                $declaration =~ /^(?:const\s+|extern\s+|static\s+)*(?:struct|union)(?:\s+\w+)?\s*\{/s)
1001             {
1002                 # Nothing
1003             } elsif($plevel == 1 && $blevel == 1) {
1004                 if(!$self->parse_c_declaration(\$declaration, \$declaration_line, \$declaration_column)) {
1005                     return 0;
1006                 }
1007                 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1008                 $declaration = "";
1009                 $declaration_line = $line;
1010                 $declaration_column = $column;
1011             } elsif($column == 1 && !$extern_c) {
1012                 $self->_parse_c_error("", $line, $column, "file", "inner } ends on column 1");
1013             }
1014         } elsif(s/^;//) {
1015             $declaration .= $&;
1016             if(0 && $blevel == 1 &&
1017                $declaration !~ /^typedef/ &&
1018                $declaration !~ /^(?:const\s+|extern\s+|static\s+)?(?:struct|union)(?:\s+\w+)?\s*\{/s &&
1019                $declaration =~ /^(?:\w+(?:\s*\*)*\s+)*(\w+)\s*\(\s*(?:(?:\w+\s*,\s*)*(\w+))?\s*\)\s*(.*?);$/s &&
1020                $1 ne "ICOM_VTABLE" && defined($2) && $2 ne "void" && $3) # K&R
1021             {
1022                 $self->_parse_c_warning("", $line, $column, "file", "function $1: warning: function has K&R format");
1023             } elsif($plevel == 1 && $blevel == 1) {
1024                 $declaration =~ s/\s*;$//;
1025                 if($declaration && !$self->parse_c_declaration(\$declaration, \$declaration_line, \$declaration_column)) {
1026                     return 0;
1027                 }
1028                 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1029                 $declaration = "";
1030                 $declaration_line = $line;
1031                 $declaration_column = $column;
1032             }
1033         } elsif(/^\s*$/ && $declaration =~ /^\s*$/ && $match =~ /^\s*$/) {
1034             $plevel = 0;
1035             $blevel = 0;
1036         } else {
1037             $self->_parse_c_error($_, $line, $column, "file", "parse error: '$declaration' '$match'");
1038         }
1039     }
1040
1041     $$refcurrent = $_;
1042     $$refline = $line;
1043     $$refcolumn = $column;
1044
1045     return 1;
1046 }
1047
1048 ########################################################################
1049 # parse_c_function
1050
1051 sub parse_c_function {
1052     my $self = shift;
1053
1054     my $file = \${$self->{FILE}};
1055     my $create_function = \${$self->{CREATE_FUNCTION}};
1056
1057     my $refcurrent = shift;
1058     my $refline = shift;
1059     my $refcolumn = shift;
1060
1061     my $reffunction = shift;
1062
1063     local $_ = $$refcurrent;
1064     my $line = $$refline;
1065     my $column = $$refcolumn;
1066
1067     my $linkage = "";
1068     my $calling_convention = "";
1069     my $return_type;
1070     my $name;
1071     my @arguments;
1072     my @argument_lines;
1073     my @argument_columns;
1074     my $statements;
1075     my $statements_line;
1076     my $statements_column;
1077
1078     $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1079
1080     my $begin_line = $line;
1081     my $begin_column = $column + 1;
1082
1083     if(0) {
1084         # Nothing
1085     } elsif($self->_parse_c('__declspec\((?:dllexport|dllimport|naked)\)|INTERNETAPI|RPCRTAPI', \$_, \$line, \$column)) {
1086         # Nothing
1087     }
1088
1089     # $self->_parse_c_warning($_, $line, $column, "function", "");
1090
1091     my $match;
1092     while($self->_parse_c('(?:const|inline|extern(?:\s+\"C\")?|EXTERN_C|static|volatile|' .
1093                           'signed(?=\s+char\b|\s+int\b|\s+long(?:\s+long)?\b|\s+short\b)|' .
1094                           'unsigned(?=\s+char\b|\s+int\b|\s+long(?:\s+long)?\b|\s+short\b)|' .
1095                           'long(?=\s+double\b|\s+int\b|\s+long\b))(?=\b)',
1096                           \$_, \$line, \$column, \$match))
1097     {
1098         if($match =~ /^extern|static$/) {
1099             if(!$linkage) {
1100                 $linkage = $match;
1101             }
1102         }
1103     }
1104
1105     if(0) {
1106         # Nothing
1107     } elsif($self->_parse_c('DECL_GLOBAL_CONSTRUCTOR', \$_, \$line, \$column, \$name)) { # FIXME: Wine specific kludge
1108         # Nothing
1109     } elsif($self->_parse_c('WINE_EXCEPTION_FILTER\(\w+\)', \$_, \$line, \$column, \$name)) { # FIXME: Wine specific kludge
1110         # Nothing
1111     } else {
1112         if(!$self->parse_c_type(\$_, \$line, \$column, \$return_type)) {
1113             return 0;
1114         }
1115
1116         $self->_parse_c('inline|FAR', \$_, \$line, \$column);
1117
1118         $self->_parse_c("__cdecl|__stdcall|__RPC_STUB|" .
1119                         "CALLBACK|CDECL|PASCAL|" .
1120                         "RPC_ENTRY|RPC_VAR_ENTRY|" .
1121                         "VFWAPIV|VFWAPI|WINAPIV|WINAPI|" .
1122                         "WINE_UNUSED",
1123                         \$_, \$line, \$column, \$calling_convention);
1124
1125
1126         # FIXME: ???: Old variant of __attribute((const))
1127         $self->_parse_c('const', \$_, \$line, \$column);
1128
1129         if(!$self->_parse_c('(?:operator\s*!=|(?:MSVCRT|WS)\(\s*\w+\s*\)|\w+)', \$_, \$line, \$column, \$name)) {
1130             return 0;
1131         }
1132
1133         my $p = 0;
1134         if(s/^__P\s*\(//) {
1135             $self->_update_c_position($&, \$line, \$column);
1136             $p = 1;
1137         }
1138
1139         if(!$self->parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
1140             return 0;
1141         }
1142
1143         if($p) {
1144             if (s/^\)//) {
1145                 $self->_update_c_position($&, \$line, \$column);
1146             } else {
1147                 $self->_parse_c_error($_, $line, $column, "function");
1148             }
1149         }
1150     }
1151
1152
1153     if (0) {
1154         # Nothing
1155     } elsif($self->_parse_c('__attribute__\s*\(\s*\(\s*(?:constructor|destructor)\s*\)\s*\)', \$_, \$line, \$column)) {
1156         # Nothing
1157     }
1158
1159     my $kar;
1160     # FIXME: Implement proper handling of K&R C functions
1161     $self->_parse_c_until_one_of("{", \$_, \$line, \$column, $kar);
1162
1163     if($kar) {
1164         $output->write("K&R: $kar\n");
1165     }
1166
1167     if($_ && !$self->parse_c_block(\$_, \$line, \$column, \$statements, \$statements_line, \$statements_column)) {
1168         return 0;
1169     }
1170
1171     my $end_line = $line;
1172     my $end_column = $column;
1173
1174     $$refcurrent = $_;
1175     $$refline = $line;
1176     $$refcolumn = $column;
1177
1178     my $function = &$$create_function;
1179
1180     $function->file($$file);
1181     $function->begin_line($begin_line);
1182     $function->begin_column($begin_column);
1183     $function->end_line($end_line);
1184     $function->end_column($end_column);
1185     $function->linkage($linkage);
1186     $function->return_type($return_type);
1187     $function->calling_convention($calling_convention);
1188     $function->name($name);
1189     # if(defined($argument_types)) {
1190     #     $function->argument_types([@$argument_types]);
1191     # }
1192     # if(defined($argument_names)) {
1193     #     $function->argument_names([@$argument_names]);
1194     # }
1195     $function->statements_line($statements_line);
1196     $function->statements_column($statements_column);
1197     $function->statements($statements);
1198
1199     $$reffunction = $function;
1200
1201     return 1;
1202 }
1203
1204 ########################################################################
1205 # parse_c_function_call
1206
1207 sub parse_c_function_call {
1208     my $self = shift;
1209
1210     my $refcurrent = shift;
1211     my $refline = shift;
1212     my $refcolumn = shift;
1213
1214     my $refname = shift;
1215     my $refarguments = shift;
1216     my $refargument_lines = shift;
1217     my $refargument_columns = shift;
1218
1219     local $_ = $$refcurrent;
1220     my $line = $$refline;
1221     my $column = $$refcolumn;
1222
1223     my $name;
1224     my @arguments;
1225     my @argument_lines;
1226     my @argument_columns;
1227
1228     if(s/^(\w+)(\s*)(?=\()//s) {
1229         $self->_update_c_position($&, \$line, \$column);
1230
1231         $name = $1;
1232
1233         if(!$self->parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
1234             return 0;
1235         }
1236     } else {
1237         return 0;
1238     }
1239
1240     $$refcurrent = $_;
1241     $$refline = $line;
1242     $$refcolumn = $column;
1243
1244     $$refname = $name;
1245     @$refarguments = @arguments;
1246     @$refargument_lines = @argument_lines;
1247     @$refargument_columns = @argument_columns;
1248
1249     return 1;
1250 }
1251
1252 ########################################################################
1253 # parse_c_preprocessor
1254
1255 sub parse_c_preprocessor {
1256     my $self = shift;
1257
1258     my $found_preprocessor = \${$self->{FOUND_PREPROCESSOR}};
1259
1260     my $refcurrent = shift;
1261     my $refline = shift;
1262     my $refcolumn = shift;
1263
1264     local $_ = $$refcurrent;
1265     my $line = $$refline;
1266     my $column = $$refcolumn;
1267
1268     $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1269
1270     my $begin_line = $line;
1271     my $begin_column = $column + 1;
1272
1273     if(!&$$found_preprocessor($begin_line, $begin_column, "$_")) {
1274         return 1;
1275     }
1276
1277     if(0) {
1278         # Nothing
1279     } elsif(/^\#\s*define\s*(.*?)$/s) {
1280         $self->_update_c_position($_, \$line, \$column);
1281     } elsif(/^\#\s*else/s) {
1282         $self->_update_c_position($_, \$line, \$column);
1283     } elsif(/^\#\s*endif/s) {
1284         $self->_update_c_position($_, \$line, \$column);
1285     } elsif(/^\#\s*(?:if|ifdef|ifndef)?\s*(.*?)$/s) {
1286         $self->_update_c_position($_, \$line, \$column);
1287     } elsif(/^\#\s*include\s+(.*?)$/s) {
1288         $self->_update_c_position($_, \$line, \$column);
1289     } elsif(/^\#\s*undef\s+(.*?)$/s) {
1290         $self->_update_c_position($_, \$line, \$column);
1291     } else {
1292         $self->_parse_c_error($_, $line, $column, "preprocessor");
1293     }
1294
1295     $$refcurrent = $_;
1296     $$refline = $line;
1297     $$refcolumn = $column;
1298
1299     return 1;
1300 }
1301
1302 ########################################################################
1303 # parse_c_statement
1304
1305 sub parse_c_statement {
1306     my $self = shift;
1307
1308     my $refcurrent = shift;
1309     my $refline = shift;
1310     my $refcolumn = shift;
1311
1312     my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
1313
1314     local $_ = $$refcurrent;
1315     my $line = $$refline;
1316     my $column = $$refcolumn;
1317
1318     $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1319
1320     $self->_parse_c('(?:case\s+)?(\w+)\s*:\s*', \$_, \$line, \$column);
1321
1322     # $output->write("$line.$column: statement: '$_'\n");
1323
1324     if(/^$/) {
1325         # Nothing
1326     } elsif(/^\{/) {
1327         my $statements;
1328         my $statements_line;
1329         my $statements_column;
1330         if(!$self->parse_c_block(\$_, \$line, \$column, \$statements, \$statements_line, \$statements_column)) {
1331             return 0;
1332         }
1333         if(!$self->parse_c_statements(\$statements, \$statements_line, \$statements_column)) {
1334             return 0;
1335         }
1336     } elsif(s/^(for|if|switch|while)\s*(?=\()//) {
1337         $self->_update_c_position($&, \$line, \$column);
1338
1339         my $name = $1;
1340
1341         my @arguments;
1342         my @argument_lines;
1343         my @argument_columns;
1344         if(!$self->parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
1345             return 0;
1346         }
1347
1348         $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1349         if(!$self->parse_c_statement(\$_, \$line, \$column)) {
1350             return 0;
1351         }
1352         $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1353
1354         while(defined(my $argument = shift @arguments) &&
1355               defined(my $argument_line = shift @argument_lines) &&
1356               defined(my $argument_column = shift @argument_columns))
1357         {
1358             $self->parse_c_expression(\$argument, \$argument_line, \$argument_column);
1359         }
1360     } elsif(s/^else//) {
1361         $self->_update_c_position($&, \$line, \$column);
1362         if(!$self->parse_c_statement(\$_, \$line, \$column)) {
1363             return 0;
1364         }
1365     } elsif(s/^return//) {
1366         $self->_update_c_position($&, \$line, \$column);
1367         $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1368         if(!$self->parse_c_expression(\$_, \$line, \$column)) {
1369             return 0;
1370         }
1371     } elsif($self->parse_c_expression(\$_, \$line, \$column)) {
1372         # Nothing
1373     } else {
1374         # $self->_parse_c_error($_, $line, $column, "statement");
1375     }
1376
1377     $self->_update_c_position($_, \$line, \$column);
1378
1379     $$refcurrent = $_;
1380     $$refline = $line;
1381     $$refcolumn = $column;
1382
1383     return 1;
1384 }
1385
1386 ########################################################################
1387 # parse_c_statements
1388
1389 sub parse_c_statements {
1390     my $self = shift;
1391
1392     my $refcurrent = shift;
1393     my $refline = shift;
1394     my $refcolumn = shift;
1395
1396     my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
1397
1398     local $_ = $$refcurrent;
1399     my $line = $$refline;
1400     my $column = $$refcolumn;
1401
1402     $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1403
1404     # $output->write("$line.$column: statements: '$_'\n");
1405
1406     my $statement = "";
1407     my $statement_line = $line;
1408     my $statement_column = $column;
1409
1410     my $previous_line = -1;
1411     my $previous_column = -1;
1412
1413     my $blevel = 1;
1414     my $plevel = 1;
1415     while($plevel > 0 || $blevel > 0) {
1416         my $match;
1417         $self->_parse_c_until_one_of("\\(\\)\\[\\]\\{\\};", \$_, \$line, \$column, \$match);
1418
1419         if($previous_line == $line && $previous_column == $column) {
1420             $self->_parse_c_error($_, $line, $column, "statements", "no progress");
1421         }
1422         $previous_line = $line;
1423         $previous_column = $column;
1424
1425         # $output->write("'$match' '$_'\n");
1426
1427         $statement .= $match;
1428         $column++;
1429         if(s/^[\(\[]//) {
1430             $plevel++;
1431             $statement .= $&;
1432         } elsif(s/^[\)\]]//) {
1433             $plevel--;
1434             if($plevel <= 0) {
1435                 $self->_parse_c_error($_, $line, $column, "statements");
1436             }
1437             $statement .= $&;
1438         } elsif(s/^\{//) {
1439             $blevel++;
1440             $statement .= $&;
1441         } elsif(s/^\}//) {
1442             $blevel--;
1443             $statement .= $&;
1444             if($blevel == 1) {
1445                 if(!$self->parse_c_statement(\$statement, \$statement_line, \$statement_column)) {
1446                     return 0;
1447                 }
1448                 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1449                 $statement = "";
1450                 $statement_line = $line;
1451                 $statement_column = $column;
1452             }
1453         } elsif(s/^;//) {
1454             if($plevel == 1 && $blevel == 1) {
1455                 if(!$self->parse_c_statement(\$statement, \$statement_line, \$statement_column)) {
1456                     return 0;
1457                 }
1458
1459                 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1460                 $statement = "";
1461                 $statement_line = $line;
1462                 $statement_column = $column;
1463             } else {
1464                 $statement .= $&;
1465             }
1466         } elsif(/^\s*$/ && $statement =~ /^\s*$/ && $match =~ /^\s*$/) {
1467             $plevel = 0;
1468             $blevel = 0;
1469         } else {
1470             $self->_parse_c_error($_, $line, $column, "statements");
1471         }
1472     }
1473
1474     $self->_update_c_position($_, \$line, \$column);
1475
1476     $$refcurrent = $_;
1477     $$refline = $line;
1478     $$refcolumn = $column;
1479
1480     return 1;
1481 }
1482
1483 ########################################################################
1484 # parse_c_tuple
1485
1486 sub parse_c_tuple {
1487     my $self = shift;
1488
1489     my $refcurrent = shift;
1490     my $refline = shift;
1491     my $refcolumn = shift;
1492
1493     # FIXME: Should not write directly
1494     my $items = shift;
1495     my $item_lines = shift;
1496     my $item_columns = shift;
1497
1498     local $_ = $$refcurrent;
1499
1500     my $line = $$refline;
1501     my $column = $$refcolumn;
1502
1503     my $item;
1504     if(s/^\(//) {
1505         $column++;
1506         $item = "";
1507     } else {
1508         return 0;
1509     }
1510
1511     my $item_line = $line;
1512     my $item_column = $column + 1;
1513
1514     my $plevel = 1;
1515     while($plevel > 0) {
1516         my $match;
1517         $self->_parse_c_until_one_of("\\(,\\)", \$_, \$line, \$column, \$match);
1518
1519         $column++;
1520
1521         $item .= $match;
1522         if(s/^\)//) {
1523             $plevel--;
1524             if($plevel == 0) {
1525                 push @$item_lines, $item_line;
1526                 push @$item_columns, $item_column;
1527                 push @$items, $item;
1528                 $item = "";
1529             } else {
1530                 $item .= ")";
1531             }
1532         } elsif(s/^\(//) {
1533             $plevel++;
1534             $item .= "(";
1535         } elsif(s/^,//) {
1536             if($plevel == 1) {
1537                 push @$item_lines, $item_line;
1538                 push @$item_columns, $item_column;
1539                 push @$items, $item;
1540                 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1541                 $item_line = $line;
1542                 $item_column = $column + 1;
1543                 $item = "";
1544             } else {
1545                 $item .= ",";
1546             }
1547         } else {
1548             return 0;
1549         }
1550     }
1551
1552     $$refcurrent = $_;
1553     $$refline = $line;
1554     $$refcolumn = $column;
1555
1556     return 1;
1557 }
1558
1559 ########################################################################
1560 # parse_c_type
1561
1562 sub parse_c_type {
1563     my $self = shift;
1564
1565     my $refcurrent = shift;
1566     my $refline = shift;
1567     my $refcolumn = shift;
1568
1569     my $reftype = shift;
1570
1571     local $_ = $$refcurrent;
1572     my $line = $$refline;
1573     my $column = $$refcolumn;
1574
1575     my $type;
1576
1577     $self->_parse_c("const", \$_, \$line, \$column);
1578
1579     if(0) {
1580         # Nothing
1581     } elsif($self->_parse_c('ICOM_VTABLE\(.*?\)', \$_, \$line, \$column, \$type)) {
1582         # Nothing
1583     } elsif($self->_parse_c('(?:enum\s+|struct\s+|union\s+)?(?:(?:MSVCRT|WS)\(\s*\w+\s*\)|\w+)\s*(\*\s*)*',
1584                             \$_, \$line, \$column, \$type))
1585     {
1586         # Nothing
1587     } else {
1588         return 0;
1589     }
1590     $type =~ s/\s//g;
1591
1592     $$refcurrent = $_;
1593     $$refline = $line;
1594     $$refcolumn = $column;
1595
1596     $$reftype = $type;
1597
1598     return 1;
1599 }
1600
1601 ########################################################################
1602 # parse_c_typedef
1603
1604 sub parse_c_typedef {
1605     my $self = shift;
1606
1607     my $create_type = \${$self->{CREATE_TYPE}};
1608     my $found_type = \${$self->{FOUND_TYPE}};
1609
1610     my $refcurrent = shift;
1611     my $refline = shift;
1612     my $refcolumn = shift;
1613
1614     my $reftype = shift;
1615
1616     local $_ = $$refcurrent;
1617     my $line = $$refline;
1618     my $column = $$refcolumn;
1619
1620     my $type;
1621
1622     if (0) {
1623         # Nothing
1624     } elsif (s/^(?:typedef\s+)?(enum\s+|struct\s+|union\s+)((?:MSVCRT|WS)\(\s*\w+\s*\)|\w+)?\s*\{\s*//s) {
1625         $self->_update_c_position($&, \$line, \$column);
1626
1627         my $kind = $1;
1628         my $_name = $2 || "";
1629
1630         $kind =~ s/\s+//g;
1631
1632         if ($kind =~ /^struct|union$/) {
1633             my $name = "";
1634             my @field_types = ();
1635             my @field_names = ();
1636
1637             my $match;
1638             while ($self->_parse_c_on_same_level_until_one_of(';', \$_, \$line, \$column, \$match))
1639             {
1640                 my $field_linkage;
1641                 my $field_type;
1642                 my $field_name;         
1643
1644                 if ($self->parse_c_variable(\$match, \$line, \$column, \$field_linkage, \$field_type, \$field_name)) {
1645                     $field_type =~ s/\s+/ /g;
1646
1647                     push @field_types, $field_type;
1648                     push @field_names, $field_name;
1649                     # $output->write("$kind:$_name:$field_type:$field_name\n");
1650                 }
1651
1652                 if ($self->_parse_c(';', \$_, \$line, \$column)) {
1653                     next;
1654                 } elsif ($self->_parse_c('}', \$_, \$line, \$column)) {
1655                     # FIXME: Kludge
1656                     my $tuple = "($_)";
1657                     my $tuple_line = $line;
1658                     my $tuple_column = $column - 1;
1659
1660                     my @arguments;
1661                     my @argument_lines;
1662                     my @argument_columns;
1663
1664                     if(!$self->parse_c_tuple(\$tuple, \$tuple_line, \$tuple_column,
1665                                              \@arguments, \@argument_lines, \@argument_columns)) 
1666                     {
1667                         $self->_parse_c_error($_, $line, $column, "typedef $kind");
1668                     }
1669
1670                     # FIXME: Kludge
1671                     if ($#arguments >= 0) {
1672                         $name = $arguments[0];
1673                     }
1674
1675                     last;
1676                 } else {
1677                     $self->_parse_c_error($_, $line, $column, "typedef $kind");
1678                 }
1679             }
1680
1681             my $type = &$$create_type();
1682
1683             $type->kind($kind);
1684             $type->_name($_name);
1685             $type->name($name);
1686             $type->field_types([@field_types]);
1687             $type->field_names([@field_names]);
1688
1689             &$$found_type($type);
1690         } else {
1691             my $name = "";
1692
1693             my $match;
1694             while ($self->_parse_c_on_same_level_until_one_of(',', \$_, \$line, \$column, \$match)) {
1695                 if ($match) {
1696                     if ($match !~ /^(\w+)\s*(?:=\s*(.*?)\s*)?$/) {
1697                         $self->_parse_c_error($_, $line, $column, "typedef $kind");
1698                     }
1699                     my $enum_name = $1;
1700                     my $enum_value = $2 || "";
1701
1702                     # $output->write("$kind:$_name:$enum_name:$enum_value\n");
1703                 }
1704
1705                 if ($self->_parse_c(',', \$_, \$line, \$column)) {
1706                     next;
1707                 } elsif ($self->_parse_c('}', \$_, \$line, \$column)) {
1708                     # FIXME: Kludge
1709                     my $tuple = "($_)";
1710                     my $tuple_line = $line;
1711                     my $tuple_column = $column - 1;
1712
1713                     my @arguments;
1714                     my @argument_lines;
1715                     my @argument_columns;
1716
1717                     if(!$self->parse_c_tuple(\$tuple, \$tuple_line, \$tuple_column,
1718                                              \@arguments, \@argument_lines, \@argument_columns)) 
1719                     {
1720                         $self->_parse_c_error($_, $line, $column, "typedef $kind");
1721                     }
1722
1723                     # FIXME: Kludge
1724                     if ($#arguments >= 0) {
1725                         $name = $arguments[0];
1726                     }
1727
1728                     last;
1729                 } else {
1730                     $self->_parse_c_error($_, $line, $column, "typedef $kind");
1731                 }
1732             }
1733
1734             # FIXME: Not correct
1735             # $output->write("typedef:$name:$_name\n");
1736         }
1737
1738     } elsif ($self->_parse_c("typedef", \$_, \$line, \$column)) {
1739         # Nothing
1740     } else {
1741         return 0;
1742     }
1743
1744     $$refcurrent = $_;
1745     $$refline = $line;
1746     $$refcolumn = $column;
1747
1748     $$reftype = $type;
1749
1750     return 1;
1751 }
1752
1753 ########################################################################
1754 # parse_c_variable
1755
1756 sub parse_c_variable {
1757     my $self = shift;
1758
1759     my $found_variable = \${$self->{FOUND_VARIABLE}};
1760
1761     my $refcurrent = shift;
1762     my $refline = shift;
1763     my $refcolumn = shift;
1764
1765     my $reflinkage = shift;
1766     my $reftype = shift;
1767     my $refname = shift;
1768
1769     local $_ = $$refcurrent;
1770     my $line = $$refline;
1771     my $column = $$refcolumn;
1772
1773     $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1774
1775     my $begin_line = $line;
1776     my $begin_column = $column + 1;
1777
1778     my $linkage = "";
1779     my $type = "";
1780     my $name = "";
1781
1782     # $self->_parse_c_warning($_, $line, $column, "variable");
1783
1784     my $match;
1785     while($self->_parse_c('(?:const|inline|extern(?:\s+\"C\")?|EXTERN_C|static|volatile|' .
1786                           'signed(?=\s+char\b|\s+int\b|\s+long(?:\s+long)?\b|\s+short\b)|' .
1787                           'unsigned(?=\s+char\b|\s+int\b|\s+long(?:\s+long)?\b|\s+short\b)|' .
1788                           'long(?=\s+double\b|\s+int\b|\s+long\b))(?=\b)',
1789                           \$_, \$line, \$column, \$match))
1790     {
1791         if($match =~ /^extern|static$/) {
1792             if(!$linkage) {
1793                 $linkage = $match;
1794             }
1795         }
1796     }
1797
1798     my $finished = 0;
1799
1800     if($finished) {
1801         # Nothing
1802     } elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+\s*(?:\*\s*)*)(\w+)$//s) {
1803         $type = $self->_format_c_type($1);
1804         $name = $2;
1805
1806         $finished = 1;
1807     } elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+\s*(?:\*\s*)*\(\s*(?:\*\s*)*)(\w+)\s*(\)\(.*?\))$//s) {
1808         $type = $self->_format_c_type("$1$3");
1809         $name = $2;
1810
1811         $finished = 1;
1812     }
1813
1814     if($finished) {
1815         # Nothing
1816     } elsif($self->_parse_c('SEQ_DEFINEBUF', \$_, \$line, \$column, \$match)) { # Linux specific
1817         $type = $match;
1818         $finished = 1;
1819     } elsif($self->_parse_c('DEFINE_GUID', \$_, \$line, \$column, \$match)) { # Windows specific
1820         $type = $match;
1821         $finished = 1;
1822     } elsif($self->_parse_c('DEFINE_REGS_ENTRYPOINT_\w+|DPQ_DECL_\w+|HANDLER_DEF|IX86_ONLY', # Wine specific
1823                             \$_, \$line, \$column, \$match))
1824     {
1825         $type = $match;
1826         $finished = 1;
1827     } elsif($self->_parse_c('(?:struct\s+)?ICOM_VTABLE\s*\(\w+\)', \$_, \$line, \$column, \$match)) {
1828         $type = $match;
1829         $finished = 1;
1830     } elsif(s/^(?:enum\s+|struct\s+|union\s+)(\w+)?\s*\{.*?\}\s*//s) {
1831         $self->_update_c_position($&, \$line, \$column);
1832
1833         if(defined($1)) {
1834             $type = "struct $1 { }";
1835         } else {
1836             $type = "struct { }";
1837         }
1838         if(defined($2)) {
1839             my $stars = $2;
1840             $stars =~ s/\s//g;
1841             if($stars) {
1842                 $type .= " $type";
1843             }
1844         }
1845     } elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+)\s*(?:\*\s*)*//s) {
1846         $type = $&;
1847         $type =~ s/\s//g;
1848     } else {
1849         return 0;
1850     }
1851
1852     # $output->write("*** $type: '$_'\n");
1853
1854     # $self->_parse_c_warning($_, $line, $column, "variable2", "");
1855
1856     if($finished) {
1857         # Nothing
1858     } elsif(s/^WINAPI\s*//) {
1859         $self->_update_c_position($&, \$line, \$column);
1860     } elsif(s/^WINE_UNUSED\s*//) {
1861         $self->_update_c_position($&, \$line, \$column);
1862     }
1863
1864     if($finished) {
1865         # Nothing
1866     } elsif(s/^(\((?:__cdecl|PASCAL|WINAPI)?\s*\*?\s*(?:__cdecl|PASCAL|WINAPI)?\w+\s*(?:\[[^\]]*\]\s*)*\))\s*\(//) {
1867         $self->_update_c_position($&, \$line, \$column);
1868
1869         $name = $1;
1870         $name =~ s/\s//g;
1871
1872         $self->_parse_c_until_one_of("\\)", \$_, \$line, \$column);
1873         if(s/^\)//) { $column++; }
1874         $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1875
1876         if(!s/^(?:=\s*|,\s*|$)//) {
1877             return 0;
1878         }
1879     } elsif(s/^(?:\*\s*)*(?:const\s+)?(\w+)\s*(?:\[[^\]]*\]\s*)*\s*(?:=\s*|,\s*|$)//) {
1880         $self->_update_c_position($&, \$line, \$column);
1881
1882         $name = $1;
1883         $name =~ s/\s//g;
1884     } elsif(/^$/) {
1885         $name = "";
1886     } else {
1887         return 0;
1888     }
1889
1890     # $output->write("$type: $name: '$_'\n");
1891
1892     if(1) {
1893         # Nothing
1894     } elsif($self->_parse_c('(?:struct\s+)?ICOM_VTABLE\s*\(.*?\)', \$_, \$line, \$column, \$match)) {
1895         $type = "<type>";
1896         $name = "<name>";
1897     } elsif(s/^((?:enum\s+|struct\s+|union\s+)?\w+)\s*
1898                 (?:\*\s*)*(\w+|\s*\*?\s*\w+\s*\))\s*(?:\[[^\]]*\]|\([^\)]*\))?
1899                 (?:,\s*(?:\*\s*)*(\w+)\s*(?:\[[^\]]*\])?)*
1900             \s*(?:=|$)//sx)
1901     {
1902         $self->_update_c_position($&, \$line, \$column);
1903
1904         $type = $1;
1905         $name = $2;
1906
1907         $type =~ s/\s//g;
1908         $type =~ s/^struct/struct /;
1909     } elsif(/^(?:enum|struct|union)(?:\s+(\w+))?\s*\{.*?\}\s*((?:\*\s*)*)(\w+)\s*(?:=|$)/s) {
1910         $self->_update_c_position($&, \$line, \$column);
1911
1912         if(defined($1)) {
1913             $type = "struct $1 { }";
1914         } else {
1915             $type = "struct { }";
1916         }
1917         my $stars = $2;
1918         $stars =~ s/\s//g;
1919         if($stars) {
1920             $type .= " $type";
1921         }
1922
1923         $name = $3;
1924     } else {
1925         return 0;
1926     }
1927
1928     if(!$name) {
1929         $name = "<name>";
1930     }
1931
1932     $$refcurrent = $_;
1933     $$refline = $line;
1934     $$refcolumn = $column;
1935
1936     $$reflinkage = $linkage;
1937     $$reftype = $type;
1938     $$refname = $name;
1939
1940     if(&$$found_variable($begin_line, $begin_column, $linkage, $type, $name))
1941     {
1942         # Nothing
1943     }
1944
1945     return 1;
1946 }
1947
1948 1;