gtkdocize fix gtkdocize to actually handle the -flat flavours
[gtk-doc.git] / gtkdoc-scan.in
blob04bfb4a088c439342ce057ff4cf1da4a829da4a0
1 #!@PERL@ -w
2 # -*- cperl -*-
4 # gtk-doc - GTK DocBook documentation generator.
5 # Copyright (C) 1998  Damon Chaplin
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #############################################################################
23 # Script      : gtkdoc-scan
24 # Description : Extracts declarations of functions, macros, enums, structs
25 #                and unions from header files.
27 #                It is called with a module name, an optional source directory,
28 #                an optional output directory, and the header files to scan.
30 #                It outputs all declarations found to a file named
31 #                '$MODULE-decl.txt', and the list of decarations to another
32 #                file '$MODULE-decl-list.txt'.
34 #                This second list file is typically copied to
35 #                '$MODULE-sections.txt' and organized into sections ready to
36 #                output the SGML pages.
37 #############################################################################
39 use strict;
40 use Getopt::Long;
41 use Cwd qw(realpath);
43 push @INC, '@PACKAGE_DATA_DIR@';
44 require "gtkdoc-common.pl";
46 # Options
48 # name of documentation module
49 my $MODULE;
50 my $OUTPUT_DIR;
51 my @SOURCE_DIRS;
52 my $IGNORE_HEADERS = "";
53 my $REBUILD_TYPES;
54 my $REBUILD_SECTIONS;
55 my $PRINT_VERSION;
56 my $PRINT_HELP;
57 # regexp matching cpp symbols which surround deprecated stuff
58 # e.g. 'GTK_ENABLE_BROKEN|GTK_DISABLE_DEPRECATED'
59 # these are detected if they are used as #if FOO, #ifndef FOO, or #ifdef FOO
60 my $DEPRECATED_GUARDS;
61 # regexp matching decorators that should be ignored
62 my $IGNORE_DECORATORS;
64 my %optctl = (module => \$MODULE,
65               'source-dir' => \@SOURCE_DIRS,
66               'ignore-headers' => \$IGNORE_HEADERS,
67               'output-dir' => \$OUTPUT_DIR,
68               'rebuild-types' => \$REBUILD_TYPES,
69               'rebuild-sections' => \$REBUILD_SECTIONS,
70               'version' => \$PRINT_VERSION,
71               'help' => \$PRINT_HELP,
72               'deprecated-guards' => \$DEPRECATED_GUARDS,
73               'ignore-decorators' => \$IGNORE_DECORATORS);
74 GetOptions(\%optctl, "module=s", "source-dir:s", "ignore-headers:s",
75            "output-dir:s", "rebuild-types", "rebuild-sections", "version",
76            "help", "deprecated-guards:s", "ignore-decorators:s");
78 if ($PRINT_VERSION) {
79     print "@VERSION@\n";
80     exit 0;
83 if (!$MODULE) {
84     $PRINT_HELP = 1;
87 if ($PRINT_HELP) {
88     print <<EOF;
89 gtkdoc-scan version @VERSION@ - scan header files for public symbols
91 --module=MODULE_NAME       Name of the doc module being parsed
92 --source-dir=DIRNAME       Directories containing the source files to scan
93 --ignore-headers=FILES     A space-separated list of header files/dirs not to
94                            scan
95 --output-dir=DIRNAME       The directory where the results are stored
96 --deprecated-guards=GUARDS A |-separated list of symbols used as deprecation
97                            guards
98 --ignore-decorators=DECS   A |-separated list of addition decorators in
99                            declarations that should be ignored
100 --rebuild-sections         Rebuild (overwrite) the MODULE-sections.txt file
101 --rebuild-types            Automatically recreate the MODULE.types file using
102                            all the *_get_type() functions found
103 --version                  Print the version of this program
104 --help                     Print this help
106     exit 0;
109 $DEPRECATED_GUARDS = $DEPRECATED_GUARDS ? $DEPRECATED_GUARDS : "does_not_match_any_cpp_symbols_at_all_nope";
111 $IGNORE_DECORATORS = $IGNORE_DECORATORS || "(?=no)match";
113 $OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
115 if (!-d ${OUTPUT_DIR}) {
116     mkdir($OUTPUT_DIR, 0755) || die "Cannot create $OUTPUT_DIR: $!";
119 my $old_decl_list = "${OUTPUT_DIR}/$MODULE-decl-list.txt";
120 my $new_decl_list = "${OUTPUT_DIR}/$MODULE-decl-list.new";
121 my $old_decl = "${OUTPUT_DIR}/$MODULE-decl.txt";
122 my $new_decl = "${OUTPUT_DIR}/$MODULE-decl.new";
123 my $old_types = "${OUTPUT_DIR}/$MODULE.types";
124 my $new_types = "${OUTPUT_DIR}/$MODULE.types.new";
125 my $sections_file = "${OUTPUT_DIR}/$MODULE-sections.txt";
127 # If this is the very first run then we create the .types file automatically.
128 if (! -e $sections_file && ! -e $old_types) {
129     $REBUILD_TYPES = 1;
132 open (DECLLIST, ">$new_decl_list")
133     || die "Can't open $new_decl_list";
134 open (DECL, ">$new_decl")
135     || die "Can't open $new_decl";
136 if ($REBUILD_TYPES) {
137     open (TYPES, ">$new_types")
138         || die "Can't open $new_types";
141 my %section_list = ();
142 my $file;
144 my @get_types = ();
147 # do not read files twice; checking it here permits to give both srcdir and
148 # builddir as --source-dir without fear of duplicities
149 my %seen_headers;
151 # The header files to scan are passed in as command-line args.
152 for $file (@ARGV) {
153     &ScanHeader ($file, \%section_list);
156 for my $dir (@SOURCE_DIRS) {
157     &ScanHeaders ($dir, \%section_list);
160 ## FIXME: sort by key and output
161 #print DECLLIST $section_list;
162 my $section;
163 foreach $section (sort(keys %section_list)) {
164     print DECLLIST "$section_list{$section}";
167 close (DECLLIST);
168 close (DECL);
170 if ($REBUILD_TYPES) {
171     my $func;
173     foreach $func (sort(@get_types)) {
174        print TYPES "$func\n";
175     }
176     close (TYPES);
177     &UpdateFileIfChanged ($old_types, $new_types, 1);
179     # remove the file if empty
180     if (scalar (@get_types) == 0) {
181         unlink ("$new_types");
182     }
185 &UpdateFileIfChanged ($old_decl_list, $new_decl_list, 1);
186 &UpdateFileIfChanged ($old_decl, $new_decl, 1);
188 # If there is no MODULE-sections.txt file yet or we are asked to rebuild it,
189 # we copy the MODULE-decl-list.txt file into its place. The user can tweak it
190 # later if they want.
191 if ($REBUILD_SECTIONS || ! -e $sections_file) {
192   `cp $old_decl_list $sections_file`;
195 # If there is no MODULE-overrides.txt file we create an empty one
196 # because EXTRA_DIST in gtk-doc.make requires it.
197 my $overrides_file = "${OUTPUT_DIR}/$MODULE-overrides.txt";
198 if (! -e $overrides_file) {
199   `touch $overrides_file`;
204 #############################################################################
205 # Function    : ScanHeaders
206 # Description : This scans a directory tree looking for header files.
208 # Arguments   : $source_dir - the directory to scan.
209 #               $section_list - a reference to the hashmap of sections.
210 #############################################################################
212 sub ScanHeaders {
213     my ($source_dir, $section_list) = @_;
214     @TRACE@("Scanning source directory: $source_dir");
216     # This array holds any subdirectories found.
217     my (@subdirs) = ();
219     opendir (SRCDIR, $source_dir)
220         || die "Can't open source directory $source_dir: $!";
221     my $file;
222     foreach $file (readdir (SRCDIR)) {
223         if ($file eq '.' || $file eq '..' || $file =~ /^\./) {
224             next;
225         } elsif (-d "$source_dir/$file") {
226             push (@subdirs, $file);
227         } elsif ($file =~ m/\.h$/) {
228             &ScanHeader ("$source_dir/$file", $section_list);
229         }
230     }
231     closedir (SRCDIR);
233     # Now recursively scan the subdirectories.
234     my $dir;
235     foreach $dir (@subdirs) {
236         next if ($IGNORE_HEADERS =~ m/(\s|^)\Q${dir}\E(\s|$)/);
237         &ScanHeaders ("$source_dir/$dir", $section_list);
238     }
242 #############################################################################
243 # Function    : ScanHeader
244 # Description : This scans a header file, looking for declarations of
245 #                functions, macros, typedefs, structs and unions, which it
246 #                outputs to the DECL file.
247 # Arguments   : $input_file - the header file to scan.
248 #               $section_list - a reference to the hashmap of sections.
249 # Returns     : it adds declarations to the appropriate list.
250 #############################################################################
252 sub ScanHeader {
253     my ($input_file, $section_list) = @_;
255     my $list = "";                  # Holds the resulting list of declarations.
256     my ($in_comment) = 0;                  # True if we are in a comment.
257     my ($in_declaration) = "";          # The type of declaration we are in, e.g.
258                                   #   'function' or 'macro'.
259     my ($skip_block) = 0;                  # True if we should skip a block.
260     my ($symbol);                  # The current symbol being declared.
261     my ($decl);                          # Holds the declaration of the current symbol.
262     my ($ret_type);                  # For functions and function typedefs this
263                                   #   holds the function's return type.
264     my ($pre_previous_line) = "";   # The pre-previous line read in - some Gnome
265                                   #   functions have the return type on one
266                                   #   line, the function name on the next,
267                                   #   and the rest of the declaration after.
268     my ($previous_line) = "";          # The previous line read in - some Gnome
269                                   #   functions have the return type on one line
270                                   #   and the rest of the declaration after.
271     my ($first_macro) = 1;          # Used to try to skip the standard #ifdef XXX
272                                   #   #define XXX at the start of headers.
273     my ($level);                          # Used to handle structs/unions which contain
274                                   #   nested structs or unions.
275     my @objects = ();                  # Holds declarations that look like GtkObject
276                                   #   subclasses, which we remove from the list.
277     my ($internal) = 0;             # Set to 1 for internal symbols, we need to
278                                     #   fully parse, but don't add them to docs
279     my %forward_decls = ();         # hashtable of forward declarations, we skip
280                                     #   them if we find the real declaration
281                                     #   later.
283     my $file_basename;
285     my $deprecated_conditional_nest = 0;
286     my $ignore_conditional_nest = 0;
288     my $deprecated = "";
290     # Don't scan headers twice
291     my $canonical_input_file = realpath $input_file;
292     if (exists $seen_headers{$canonical_input_file}) {
293         @TRACE@("File already scanned: $input_file");
294         return;
295     }
296     $seen_headers{$canonical_input_file} = 1;
298     if ($input_file =~ m/^.*[\/\\](.*)\.h+$/) {
299         $file_basename = $1;
300     } else {
301         LogWarning(__FILE__,__LINE__,"Can't find basename of file $input_file");
302         $file_basename = $input_file;
303     }
305     # Check if the basename is in the list of headers to ignore.
306     if ($IGNORE_HEADERS =~ m/(\s|^)\Q${file_basename}\E\.h(\s|$)/) {
307         @TRACE@("File ignored: $input_file");
308         return;
309     }
311     if (! -f $input_file) {
312         LogWarning(__FILE__,__LINE__,"File doesn't exist: $input_file");
313         return;
314     }
316     @TRACE@("Scanning $input_file");
318     open(INPUT, $input_file)
319         || die "Can't open $input_file: $!";
320     while(<INPUT>) {
321         # If this is a private header, skip it.
322         if (m%^\s*/\*\s*<\s*private_header\s*>\s*\*/%) {
323             close(INPUT);
324             return;
325         }
327         # Skip to the end of the current comment.
328         if ($in_comment) {
329             @TRACE@("Comment: $_");
330             if (m%\*/%) {
331                 $in_comment = 0;
332             }
333             next;
334         }
336         # Keep a count of #if, #ifdef, #ifndef nesting,
337         # and if we enter a deprecation-symbol-bracketed
338         # zone, take note.
339         if (m/^\s*#\s*if(?:n?def\b|\s+!?\s*defined\s*\()\s*(\w+)/) {
340             my $define_name = $1;
341             if ($deprecated_conditional_nest == 0 and $define_name =~ /$DEPRECATED_GUARDS/) {
342                  $deprecated_conditional_nest = 1;
343             } elsif ($deprecated_conditional_nest > 0) {
344                  $deprecated_conditional_nest += 1;
345             }
346             if ($ignore_conditional_nest == 0 and $define_name =~ /__GTK_DOC_IGNORE__/) {
347                  $ignore_conditional_nest = 1;
348             } elsif ($ignore_conditional_nest > 0) {
349                  $ignore_conditional_nest += 1;
350             }
351         } elsif (m/^\s*#\sif/) {
352             if ($deprecated_conditional_nest > 0) {
353                  $deprecated_conditional_nest += 1;
354             }
355             if ($ignore_conditional_nest > 0) {
356                  $ignore_conditional_nest += 1;
357             }
358         } elsif (m/^\s*#endif/) {
359             if ($deprecated_conditional_nest > 0) {
360                 $deprecated_conditional_nest -= 1;
361             }
362             if ($ignore_conditional_nest > 0) {
363                 $ignore_conditional_nest -= 1;
364             }
365         }
367         # set global that is used later when we do AddSymbolToList
368         if ($deprecated_conditional_nest > 0) {
369             $deprecated = "<DEPRECATED/>\n";
370         } else {
371             $deprecated = "";
372         }
374         if($ignore_conditional_nest) {
375             next;
376         }
378         if (!$in_declaration) {
379             # Skip top-level comments.
380             if (s%^\s*/\*%%) {
381                 if (m%\*/%) {
382                     @TRACE@("Found one-line comment: $_");
383                 } else {
384                     $in_comment = 1;
385                     @TRACE@("Found start of comment: $_");
386                 }
387                 next;
388             }
390             @TRACE@("0: $_");
392             # MACROS
394             if (m/^\s*#\s*define\s+(\w+)/) {
395                 $symbol = $1;
396                 $decl = $_;
397                 # We assume all macros which start with '_' are private, but
398                 # we accept '_' itself which is the standard gettext macro.
399                 # We also try to skip the first macro if it looks like the
400                 # standard #ifndef HEADER_FILE #define HEADER_FILE etc.
401                 # And we only want TRUE & FALSE defined in GLib (libdefs.h in
402                 # libgnome also defines them if they are not already defined).
403                 if (($symbol !~ m/^_/
404                      && ($previous_line !~ m/#ifndef\s+$symbol/
405                          || $first_macro == 0)
406                      && (($symbol ne 'TRUE' && $symbol ne 'FALSE')
407                          || $MODULE eq 'glib'))
408                     || $symbol eq "_") {
409                     $in_declaration = "macro";
410                     @TRACE@("Macro: $symbol");
411                 } else {
412                     @TRACE@("skipping Macro: $symbol");
413                     $in_declaration = "macro";
414                     $internal = 1;
415                 }
416                 $first_macro = 0;
419             # TYPEDEF'D FUNCTIONS (i.e. user functions)
421             #                        $1                                $3            $4             $5
422             } elsif (m/^\s*typedef\s+((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/) {
423                 my $p3 = defined($3) ? $3 : "";
424                 $ret_type = "$1$p3 $4";
425                 $symbol = $5;
426                 $decl = $';
427                 $in_declaration = "user_function";
428                 @TRACE@("user function (1): $symbol, Returns: $ret_type");
430             #                                                       $1                                $3            $4             $5
431             } elsif (($previous_line =~ m/^\s*typedef\s*/) && m/^\s*((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/) {
432                 my $p3 = defined($3) ? $3 : "";
433                 $ret_type = "$1$p3 $4";
434                 $symbol = $5;
435                 $decl = $';
436                 $in_declaration = "user_function";
437                 @TRACE@("user function (2): $symbol, Returns: $ret_type");
439             #                                                       $1            $2
440             } elsif (($previous_line =~ m/^\s*typedef\s*/) && m/^\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/) {
441                 $ret_type = $1;
442                 $symbol = $2;
443                 $decl = $';
444                 #                                     $1                                $3
445                 if ($previous_line =~ m/^\s*typedef\s*((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*/) {
446                     my $p3 = defined($3) ? $3 : "";
447                     $ret_type = "$1$p3 ".$ret_type;
448                     $in_declaration = "user_function";
449                     @TRACE@("user function (3): $symbol, Returns: $ret_type");
451                 }
452             # FUNCTION POINTER VARIABLES
453             #                                                                       $1                                $3            $4             $5
454             } elsif (m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\b\s*)*((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/o) {
455                 my $p3 = defined($3) ? $3 : "";
456                 $ret_type = "$1$p3 $4";
457                 $symbol = $5;
458                 $decl = $';
459                 $in_declaration = "user_function";
460                 @TRACE@("function pointer variable: $symbol, Returns: $ret_type");
462             # ENUMS
464             } elsif (s/^\s*enum\s+_(\w+)\s+\{/enum $1 {/) {
465                 # We assume that 'enum _<enum_name> {' is really the
466                 # declaration of enum <enum_name>.
467                 $symbol = $1;
468                 @TRACE@("plain enum: $symbol");
469                 $decl = $_;
470                 $in_declaration = "enum";
472             } elsif (m/^\s*typedef\s+enum\s+_?(\w+)\s+\1\s*;/) {
473                 # We skip 'typedef enum <enum_name> _<enum_name>;' as the enum will
474                 # be declared elsewhere.
475                 @TRACE@("skipping enum typedef: $1");
477             } elsif (m/^\s*typedef\s+enum/) {
478                 $symbol = "";
479                 @TRACE@("typedef enum: -");
480                 $decl = $_;
481                 $in_declaration = "enum";
484             # STRUCTS AND UNIONS
486             } elsif (m/^\s*typedef\s+(struct|union)\s+_(\w+)\s+\2\s*;/) {
487                 # We've found a 'typedef struct _<name> <name>;'
488                 # This could be an opaque data structure, so we output an
489                 # empty declaration. If the structure is actually found that
490                 # will override this.
491                 my $structsym = uc $1;
492                 @TRACE@("$structsym typedef: $2");
493                 $forward_decls{$2} = "<$structsym>\n<NAME>$2</NAME>\n$deprecated</$structsym>\n"
495             } elsif (m/^\s*(?:struct|union)\s+_(\w+)\s*;/) {
496                 # Skip private structs/unions.
497                 @TRACE@("private struct/union");
499             } elsif (m/^\s*(struct|union)\s+(\w+)\s*;/) {
500                 # Do a similar thing for normal structs as for typedefs above.
501                 # But we output the declaration as well in this case, so we
502                 # can differentiate it from a typedef.
503                 my $structsym = uc $1;
504                 @TRACE@("$structsym: $2");
505                 $forward_decls{$2} = "<$structsym>\n<NAME>$2</NAME>\n$_$deprecated</$structsym>\n";
507             } elsif (m/^\s*typedef\s+(struct|union)\s*\w*\s*{/) {
508                 $symbol = "";
509                 $decl = $_;
510                 $level = 0;
511                 $in_declaration = $1;
512                 @TRACE@("typedef struct/union $1");
514             # OTHER TYPEDEFS
516             } elsif (m/^\s*typedef\s+(?:struct|union)\s+\w+[\s\*]+(\w+)\s*;/) {
517                 @TRACE@("Found struct/union(*) typedef $1: $_");
518                 if (&AddSymbolToList (\$list, $1)) {
519                     print DECL "<TYPEDEF>\n<NAME>$1</NAME>\n$deprecated$_</TYPEDEF>\n";
520                 }
522             } elsif (m/^\s*(G_GNUC_EXTENSION\s+)?typedef\s+(.+[\s\*])(\w+)(\s*\[[^\]]+\])*\s*;/) {
523                 if ($2 !~ m/^struct\s/ && $2 !~ m/^union\s/) {
524                     @TRACE@("Found typedef: $_");
525                     if (&AddSymbolToList (\$list, $3)) {
526                         print DECL "<TYPEDEF>\n<NAME>$3</NAME>\n$deprecated$_</TYPEDEF>\n";
527                     }
528                 }
529             } elsif (m/^\s*typedef\s+/) {
530                 @TRACE@("Skipping typedef: $_");
533             # VARIABLES (extern'ed variables)
535             } elsif (m/^\s*(extern|[A-Za-z_]+VAR)\s+((const\s+|signed\s+|unsigned\s+|long\s+|short\s+)*\w+)(\s+\*+|\*+|\s)\s*(const\s+)*([A-Za-z]\w*)\s*;/) {
536                 $symbol = $6;
537                 s/^\s*([A-Za-z_]+VAR)\b/extern/;
538                 $decl = $_;
539                 @TRACE@("Possible extern var $6: $decl");
540                 if (&AddSymbolToList (\$list, $symbol)) {
541                     print DECL "<VARIABLE>\n<NAME>$symbol</NAME>\n$deprecated$decl</VARIABLE>\n";
542                 }
545             # VARIABLES
547             } elsif (m/^\s*((const\s+|signed\s+|unsigned\s+|long\s+|short\s+)*\w+)(\s+\*+|\*+|\s)\s*(const\s+)*([A-Za-z]\w*)\s*\=/) {
548                 $symbol = $5;
549                 $decl = $_;
550                 @TRACE@("Possible global var $5: $decl");
551                 if (&AddSymbolToList (\$list, $symbol)) {
552                     print DECL "<VARIABLE>\n<NAME>$symbol</NAME>\n$deprecated$decl</VARIABLE>\n";
553                 }
556             # FUNCTIONS
558             # We assume that functions which start with '_' are private, so
559             # we skip them.
560             #                                                                       $1                                                                                                    $2                                                          $3
561             } elsif (m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s+|\*)+(?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*(_[A-Za-z]\w*)\s*\(/o) {
562                 $ret_type = $1;
563                 if (defined ($2)) { $ret_type .= " $2"; }
564                 $symbol = $3;
565                 $decl = $';
566                 @TRACE@("internal Function: $symbol, Returns: [$1][$2]");
567                 $in_declaration = "function";
568                 $internal = 1;
569                 if (m/^\s*G_INLINE_FUNC/) {
570                     @TRACE@("skip block after inline function");
571                     # now we we need to skip a whole { } block
572                     $skip_block = 1;
573                 }
575             #                                                                       $1                                                                                                    $2                                                          $3
576             } elsif (m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s+|\*)+(?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*([A-Za-z]\w*)\s*\(/o) {
577                 $ret_type = $1;
578                 if (defined ($2)) { $ret_type .= " $2"; }
579                 $symbol = $3;
580                 $decl = $';
581                 @TRACE@("Function (1): $symbol, Returns: [$1][$2]");
582                 $in_declaration = "function";
583                 if (m/^\s*G_INLINE_FUNC/) {
584                     @TRACE@("skip block after inline function");
585                     # now we we need to skip a whole { } block
586                     $skip_block = 1;
587                 }
589             # Try to catch function declarations which have the return type on
590             # the previous line. But we don't want to catch complete functions
591             # which have been declared G_INLINE_FUNC, e.g. g_bit_nth_lsf in
592             # glib, or 'static inline' functions.
593             } elsif (m/^\s*([A-Za-z]\w*)\s*\(/) {
594                 $symbol = $1;
595                 $decl = $';
597                 if ($previous_line !~ m/^\s*G_INLINE_FUNC/) {
598                     if ($previous_line !~ m/^\s*static\s+/) {
599                         #                                                                       $1                                                                                                   $2
600                         if ($previous_line =~ m/^\s*(?:\b(?:extern|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*$/o) {
601                             $ret_type = $1;
602                             if (defined ($2)) { $ret_type .= " $2"; }
603                             @TRACE@("Function  (2): $symbol, Returns: $ret_type");
604                             $in_declaration = "function";
605                         }
606                     } else {
607                         @TRACE@("skip block after inline function");
608                         # now we we need to skip a whole { } block
609                         $skip_block = 1;
610                         #                                                                                    $1                                                                                                   $2
611                         if ($previous_line =~ m/^\s*(?:\b(?:extern|static|inline|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*$/o) {
612                             $ret_type = $1;
613                             if (defined ($2)) { $ret_type .= " $2"; }
614                             @TRACE@("Function  (3): $symbol, Returns: $ret_type");
615                             $in_declaration = "function";
616                         }
617                     }
618                 }
619                 else {
620                     if ($previous_line !~ m/^\s*static\s+/) {
621                         @TRACE@("skip block after inline function");
622                         # now we we need to skip a whole { } block
623                         $skip_block = 1;
624                         #                                                                                    $1                                                                                                    $2
625                         if ($previous_line =~ m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*$/o) {
626                             $ret_type = $1;
627                             if (defined ($2)) { $ret_type .= " $2"; }
628                             @TRACE@("Function (4): $symbol, Returns: $ret_type");
629                             $in_declaration = "function";
630                         }
631                     }
632                 }
634             # Try to catch function declarations with the return type and name
635             # on the previous line(s), and the start of the parameters on this.
636             } elsif (m/^\s*\(/) {
637                 $decl = $';
638                 if ($previous_line =~ m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|enum\s+)*\w+)(\s+\*+|\*+|\s)\s*([A-Za-z]\w*)\s*$/o) {
639                     $ret_type = "$1 $2";
640                     $symbol = $3;
641                     @TRACE@("Function (5): $symbol, Returns: $ret_type");
642                     $in_declaration = "function";
644                 } elsif ($previous_line =~ m/^\s*\w+\s*$/
645                          && $pre_previous_line =~ m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|struct\s+|union\s+|enum\s+)*\w+(?:\**\s+\**(?:const|G_CONST_RETURN))?(?:\s+|\s*\*+))\s*$/o) {
646                     $ret_type = $1;
647                     $ret_type =~ s/\s*\n//;
648                     $in_declaration = "function";
650                     $symbol = $previous_line;
651                     $symbol =~ s/^\s+//;
652                     $symbol =~ s/\s*\n//;
653                     @TRACE@("Function (6): $symbol, Returns: $ret_type");
654                 }
656             #} elsif (m/^extern\s+/) {
657                 #print "DEBUG: Skipping extern: $_";
660             # STRUCTS
662             } elsif (m/^\s*struct\s+_(\w+)\s*\*/) {
663                 # Skip 'struct _<struct_name> *', since it could be a
664                 # return type on its own line.
666             } elsif (m/^\s*struct\s+_(\w+)/) {
667                 # We assume that 'struct _<struct_name>' is really the
668                 # declaration of struct <struct_name>.
669                 $symbol = $1;
670                 $decl = $_;
671                  # we will find the correct level as below we do $level += tr/{//;
672                 $level = 0;
673                 $in_declaration = "struct";
674                 @TRACE@("Struct(_): $symbol");
677             # UNIONS
679             } elsif (m/^\s*union\s+_(\w+)\s*\*/) {
680                     # Skip 'union _<union_name> *' (see above)
681             } elsif (m/^\s*union\s+_(\w+)/) {
682                 $symbol = $1;
683                 $decl = $_;
684                 $level = 0;
685                 $in_declaration = "union";
686                 @TRACE@("Union(_): $symbol");
687             }
689         } else {
690             @TRACE@("1: [$skip_block] $_");
691             # If we were already in the middle of a declaration, we simply add
692             # the current line onto the end of it.
693             if ($skip_block == 0) {
694                 $decl .= $_;
695             } else {
696                 # Remove all nested pairs of curly braces.
697                 while ($_ =~ s/{[^{]*}//g) { }
698                 # Then hope at most one remains in the line...
699                 if (m%(.*?){%) {
700                     if ($skip_block == 1) {
701                         $decl .= $1;
702                     }
703                     $skip_block += 1;
704                 } elsif (m%}%) {
705                     $skip_block -= 1;
706                     if ($skip_block == 1) {
707                         # this is a hack to detect the end of declaration
708                         $decl .= ";";
709                         $skip_block = 0;
710                         @TRACE@("2: ---");
711                     }
712                 } else {
713                     if ($skip_block == 1) {
714                         $decl .= $_;
715                     }
716                 }
717             }
718         }
720         #if ($in_declaration ne '') {
721         #    print "$in_declaration = $decl\n";
722         #}
724         # Note that sometimes functions end in ') G_GNUC_PRINTF (2, 3);' or
725         # ') __attribute__ (...);'.
726         if ($in_declaration eq 'function') {
727             if ($decl =~ s/\)\s*(G_GNUC_.*|.*DEPRECATED.*|${IGNORE_DECORATORS}\s*|__attribute__\s*\(.*\)\s*)?;.*$//) {
728                 if ($internal == 0) {
729                      $decl =~ s%/\*.*?\*/%%gs;        # remove comments.
730                      #$decl =~ s/^\s+//;                # remove leading whitespace.
731                      #$decl =~ s/\s+$//;                # remove trailing whitespace.
732                      $decl =~ s/\s*\n\s*/ /gs;        # consolidate whitespace at start
733                                                    # and end of lines.
734                      $ret_type =~ s%/\*.*?\*/%%g;        # remove comments in ret type.
735                      if (&AddSymbolToList (\$list, $symbol)) {
736                          print DECL "<FUNCTION>\n<NAME>$symbol</NAME>\n$deprecated<RETURNS>$ret_type</RETURNS>\n$decl\n</FUNCTION>\n";
737                          if ($REBUILD_TYPES) {
738                              # check if this looks like a get_type function and if so remember
739                              if (($symbol =~ m/_get_type$/) && ($ret_type =~ m/GType/) && ($decl =~ m/(void|)/)) {
740                                  @TRACE@("Adding get-type: [$ret_type] [$symbol] [$decl]\tfrom $input_file");
741                                  push (@get_types, $symbol);
742                              }
743                          }
744                      }
745                 } else {
746                      $internal = 0;
747                 }
748                 $in_declaration = "";
749                 $skip_block = 0;
750             }
751         }
753         if ($in_declaration eq 'user_function') {
754             if ($decl =~ s/\).*$//) {
755                 if (&AddSymbolToList (\$list, $symbol)) {
756                     print DECL "<USER_FUNCTION>\n<NAME>$symbol</NAME>\n$deprecated<RETURNS>$ret_type</RETURNS>\n$decl</USER_FUNCTION>\n";
757                 }
758                 $in_declaration = "";
759             }
760         }
762         if ($in_declaration eq 'macro') {
763             if ($decl !~ m/\\\s*$/) {
764                 if ($internal == 0) {
765                     if (&AddSymbolToList (\$list, $symbol)) {
766                         print DECL "<MACRO>\n<NAME>$symbol</NAME>\n$deprecated$decl</MACRO>\n";
767                     }
768                 } else {
769                     $internal = 0;
770                 }
771                 $in_declaration = "";
772             }
773         }
775         if ($in_declaration eq 'enum') {
776             if ($decl =~ m/\}\s*(\w+)?;\s*$/) {
777                 if ($symbol eq "") {
778                     $symbol = $1;
779                 }
780                 if (&AddSymbolToList (\$list, $symbol)) {
781                     print DECL "<ENUM>\n<NAME>$symbol</NAME>\n$deprecated$decl</ENUM>\n";
782                 }
783                 $in_declaration = "";
784             }
785         }
787         # We try to handle nested stucts/unions, but unmatched brackets in
788         # comments will cause problems.
789         if ($in_declaration eq 'struct' or $in_declaration eq 'union') {
790             if (($level <= 1) && ($decl =~ m/\n\}\s*(\w*);\s*$/)) {
791                 if ($symbol eq "") {
792                     $symbol = $1;
793                 }
795                 if ($symbol =~ m/^(\S+)(Class|Iface|Interface)\b/) {
796                     my $objectname = $1;
797                     @TRACE@("Found object: $1");
798                     $list = "<TITLE>$objectname</TITLE>\n$list";
799                     push (@objects, $objectname);
800                 }
801                 @TRACE@("Store struct: $symbol");
802                 if (&AddSymbolToList (\$list, $symbol)) {
803                     my $structsym = uc $in_declaration;
804                     print DECL "<$structsym>\n<NAME>$symbol</NAME>\n$deprecated$decl</$structsym>\n";
805                     if (defined($forward_decls{$symbol})) {
806                         undef($forward_decls{$symbol});
807                     }
808                 }
809                 $in_declaration = "";
810             } else {
811                 # We use tr to count the brackets in the line, and adjust
812                 # $level accordingly.
813                 $level += tr/{//;
814                 $level -= tr/}//;
815                 @TRACE@("struct/union level : $level");
816             }
817         }
819         $pre_previous_line = $previous_line;
820         $previous_line = $_;
821     }
822     close(INPUT);
824     # print remaining forward declarations
825     foreach $symbol (keys %forward_decls) {
826         if (defined($forward_decls{$symbol})) {
827             &AddSymbolToList (\$list, $symbol);
828             print DECL $forward_decls{$symbol};
829         }
830     }
832     @TRACE@("Scanning $input_file done\n");
833     
834     # sort the symbols
835     $list=join("\n",sort(split("\n",$list)))."\n";
837     # Try to separate the standard macros and functions, placing them at the
838     # end of the current section, in a subsection named 'Standard'.
839     # do this in a loop to catch object, enums and flags
840     # FIXME: we still leave XxxXxxxxClass in the normal section, it would be
841     # nice to hide it, if it is not documented and empty (only parent) 
842     my ($class,$lclass);
843     my ($standard_decl) = "";
844     do {
845         if ($list =~ m/^\S+_IS_(\S*)_CLASS\n/m) {
846             $class = $1;
847             $lclass = lc($class);
848             @TRACE@("Found gobject class '$class' from is class macro\n");
849         } elsif ($list =~ m/^\S+_IS_(\S*)\n/m) {
850             $class = $1;
851             $lclass = lc($class);
852             @TRACE@("Found gobject class '$class' from is macro\n");
853         } elsif ($list =~ m/^\S+?_(\S*)_get_type\n/m) {
854             $lclass = $1;
855             $class = uc($lclass);
856             @TRACE@("Found gobject class '$class' from get_type function\n");
857         } else {
858           $class = $lclass = "";
859         }
860     
861         if ($class ne "") {
862             my ($cclass) = $lclass;
863             $cclass =~ s/_//g;
864             
865             if ($list =~ s/^\S+${cclass}Private\n//im)          { $standard_decl .= $&; }
866             
867             while ($list =~ s/^\S+_IS_$class\n//m)              { $standard_decl .= $&; }
868             while ($list =~ s/^\S+_TYPE_$class\n//m)            { $standard_decl .= $&; }
869             while ($list =~ s/^\S+_${lclass}_get_type\n//m)     { $standard_decl .= $&; }
870             while ($list =~ s/^\S+_${class}_CLASS\n//m)         { $standard_decl .= $&; }
871             while ($list =~ s/^\S+_IS_${class}_CLASS\n//m)      { $standard_decl .= $&; }
872             while ($list =~ s/^\S+_${class}_GET_CLASS\n//m)     { $standard_decl .= $&; }
873             while ($list =~ s/^\S+_${class}_GET_IFACE\n//m)     { $standard_decl .= $&; }
874             while ($list =~ s/^\S+_${class}_GET_INTERFACE\n//m) { $standard_decl .= $&; }
875     
876             # We do this one last, otherwise it tends to be caught by the IS_$class macro
877             while ($list =~ s/^\S+_$class\n//m)                 { $standard_decl .= $&; }
878             
879             @TRACE@("Decl '".join(",",split("\n",$list))."'\n");
880             @TRACE@("Std  '".join(",",split("\n",$standard_decl))."'\n");
881         }
882     } while ($class ne "");
883     if ($standard_decl ne "") {
884       # sort the symbols
885       $standard_decl=join("\n",sort(split("\n",$standard_decl)))."\n";
886       $list .= "<SUBSECTION Standard>\n$standard_decl";
887     }
888     if ($list ne "") {
889         $$section_list{$file_basename} .= "<SECTION>\n<FILE>$file_basename</FILE>\n$list</SECTION>\n\n";
890     }
894 #############################################################################
895 # Function    : AddSymbolToList
896 # Description : This adds the symbol to the list of declarations, but only if
897 #                it is not already in the list.
898 # Arguments   : $list - reference to the list of symbols, one on each line.
899 #                $symbol - the symbol to add to the list.
900 #############################################################################
902 sub AddSymbolToList {
903     my ($list, $symbol) = @_;
905     if ($$list =~ m/\b\Q$symbol\E\b/) {
906          #print "Symbol $symbol already in list. skipping\n";
907          # we return 0 to skip outputting another entry to -decl.txt
908          # this is to avoid redeclarations (e.g. in conditional
909          # sections).
910         return 0;
911     }
912     $$list .= "$symbol\n";
913     return 1;