Current release notes.
[gtk-doc.git] / gtkdoc-scan.in
blob53b85e8ad11d09ff826696ab4f113889e41bd9b8
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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;
42 unshift @INC, '@PACKAGE_DATA_DIR@';
43 require "gtkdoc-common.pl";
45 # Options
47 # name of documentation module
48 my $MODULE;
49 my $OUTPUT_DIR;
50 my @SOURCE_DIRS;
51 my $IGNORE_HEADERS = "";
52 my $REBUILD_TYPES;
53 my $REBUILD_SECTIONS;
54 my $PRINT_VERSION;
55 my $PRINT_HELP;
56 # regexp matching cpp symbols which surround deprecated stuff
57 # e.g. 'GTK_ENABLE_BROKEN|GTK_DISABLE_DEPRECATED'
58 # these are detected if they are used as #if FOO, #ifndef FOO, or #ifdef FOO
59 my $DEPRECATED_GUARDS;
60 # regexp matching decorators that should be ignored
61 my $IGNORE_DECORATORS;
63 my %optctl = (module => \$MODULE,
64               'source-dir' => \@SOURCE_DIRS,
65               'ignore-headers' => \$IGNORE_HEADERS,
66               'output-dir' => \$OUTPUT_DIR,
67               'rebuild-types' => \$REBUILD_TYPES,
68               'rebuild-sections' => \$REBUILD_SECTIONS,
69               'version' => \$PRINT_VERSION,
70               'help' => \$PRINT_HELP,
71               'deprecated-guards' => \$DEPRECATED_GUARDS,
72               'ignore-decorators' => \$IGNORE_DECORATORS);
73 GetOptions(\%optctl, "module=s", "source-dir:s", "ignore-headers:s",
74            "output-dir:s", "rebuild-types", "rebuild-sections", "version",
75            "help", "deprecated-guards:s", "ignore-decorators:s");
77 if ($PRINT_VERSION) {
78     print "@VERSION@\n";
79     exit 0;
82 if (!$MODULE) {
83     $PRINT_HELP = 1;
86 if ($PRINT_HELP) {
87     print "gtkdoc-scan version @VERSION@\n";
88     print "\n--module=MODULE_NAME       Name of the doc module being parsed";
89     print "\n--source-dir=DIRNAME       Directories containing the source files to scan";
90     print "\n--ignore-headers=FILES     A space-separated list of header files not to scan";
91     print "\n--output-dir=DIRNAME       The directory where the results are stored";
92     print "\n--deprecated-guards=GUARDS A |-separated list of symbols used as deprecation guards";
93     print "\n--ignore-decorators=DECS   A |-separated list of addition decorators in declarations that should be ignored";
94     print "\n--rebuild-sections         Rebuild (overwrite) the MODULE-sections.txt file";
95     print "\n--rebuild-types            Automatically recreate the MODULE.types file using all the *_get_type() functions found";
96     print "\n--version                  Print the version of this program";
97     print "\n--help                     Print this help\n";
98     exit 0;
101 $DEPRECATED_GUARDS = $DEPRECATED_GUARDS ? $DEPRECATED_GUARDS : "does_not_match_any_cpp_symbols_at_all_nope";
103 $IGNORE_DECORATORS = $IGNORE_DECORATORS || "(?=no)match";
105 $OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
107 if (!-d ${OUTPUT_DIR}) {
108     mkdir($OUTPUT_DIR, 0755) || die "Cannot create $OUTPUT_DIR: $!";
111 my $old_decl_list = "${OUTPUT_DIR}/$MODULE-decl-list.txt";
112 my $new_decl_list = "${OUTPUT_DIR}/$MODULE-decl-list.new";
113 my $old_decl = "${OUTPUT_DIR}/$MODULE-decl.txt";
114 my $new_decl = "${OUTPUT_DIR}/$MODULE-decl.new";
115 my $old_types = "${OUTPUT_DIR}/$MODULE.types";
116 my $new_types = "${OUTPUT_DIR}/$MODULE.types.new";
117 my $sections_file = "${OUTPUT_DIR}/$MODULE-sections.txt";
119 # If this is the very first run then we create the .types file automatically.
120 if (! -e $sections_file && ! -e $old_types) {
121     $REBUILD_TYPES = 1;
124 open (DECLLIST, ">$new_decl_list")
125     || die "Can't open $new_decl_list";
126 open (DECL, ">$new_decl")
127     || die "Can't open $new_decl";
128 if ($REBUILD_TYPES) {
129     open (TYPES, ">$new_types")
130         || die "Can't open $new_types";
133 my $main_list = "";
134 my $object_list = "";
135 my $file;
137 # The header files to scan are passed in as command-line args.
138 for $file (@ARGV) {
139     &ScanHeader ($file, \$object_list, \$main_list);
142 for my $dir (@SOURCE_DIRS) {
143     &ScanHeaders ($dir, \$object_list, \$main_list);
146 print DECLLIST $object_list, $main_list;
147 close (DECLLIST);
148 close (DECL);
149 close (TYPES) if ($REBUILD_TYPES);
151 &UpdateFileIfChanged ($old_decl_list, $new_decl_list, 1);
152 &UpdateFileIfChanged ($old_decl, $new_decl, 1);
153 &UpdateFileIfChanged ($old_types, $new_types, 1) if ($REBUILD_TYPES);
155 # If there is no MODULE-sections.txt file yet or we are asked to rebuild it,
156 # we copy the MODULE-decl-list.txt file into its place. The user can tweak it
157 # later if they want.
158 if ($REBUILD_SECTIONS || ! -e $sections_file) {
159   `cp $old_decl_list $sections_file`;
162 # If there is no MODULE-overrides.txt file we create an empty one.
163 my $overrides_file = "${OUTPUT_DIR}/$MODULE-overrides.txt";
164 if (! -e $overrides_file) {
165   `touch $overrides_file`;
170 #############################################################################
171 # Function    : ScanHeaders
172 # Description : This scans a directory tree looking for header files.
174 # Arguments   : $source_dir - the directory to scan.
175 #               $object_list - a reference to the list of object functions &
176 #                       declarations.
177 #               $main_list - a reference to the list of other declarations.
178 #############################################################################
180 sub ScanHeaders {
181     my ($source_dir, $object_list, $main_list) = @_;
182 #    print "Scanning source directory: $source_dir\n";
184     # This array holds any subdirectories found.
185     my (@subdirs) = ();
187     opendir (SRCDIR, $source_dir)
188         || die "Can't open source directory $source_dir: $!";
189     my $file;
190     foreach $file (readdir (SRCDIR)) {
191         if ($file eq '.' || $file eq '..' || $file =~ /^\./) {
192             next;
193         } elsif (-d "$source_dir/$file") {
194             push (@subdirs, $file);
195         } elsif ($file =~ m/\.h$/) {
196             &ScanHeader ("$source_dir/$file", $object_list, $main_list);
197         }
198     }
199     closedir (SRCDIR);
201     # Now recursively scan the subdirectories.
202     my $dir;
203     foreach $dir (@subdirs) {
204         next if ($IGNORE_HEADERS =~ m/(\s|^)\Q${dir}\E(\s|$)/);
205         &ScanHeaders ("$source_dir/$dir", $object_list, $main_list);
206     }
210 #############################################################################
211 # Function    : ScanHeader
212 # Description : This scans a header file, looking for declarations of
213 #               functions, macros, typedefs, structs and unions, which it
214 #               outputs to the DECL file.
215 # Arguments   : $input_file - the header file to scan.
216 #               $object_list - a reference to the list of object functions &
217 #                       declarations.
218 #               $main_list - a reference to the list of other declarations.
219 # Returns     : it adds declarations to the appropriate list.
220 #############################################################################
222 sub ScanHeader {
223     my ($input_file, $object_list, $main_list) = @_;
224 #    print "DEBUG: Scanning $input_file\n";
226     my $list = "";                # Holds the resulting list of declarations.
227     my ($in_comment) = 0;         # True if we are in a comment.
228     my ($in_declaration) = "";    # The type of declaration we are in, e.g.
229                                   #   'function' or 'macro'.
230     my ($symbol);                 # The current symbol being declared.
231     my ($decl);                   # Holds the declaration of the current symbol.
232     my ($ret_type);               # For functions and function typedefs this
233                                   #   holds the function's return type.
234     my ($pre_previous_line) = ""; # The pre-previous line read in - some Gnome
235                                   #   functions have the return type on one
236                                   #   line, the function name on the next,
237                                   #   and the rest of the declaration after.
238     my ($previous_line) = "";     # The previous line read in - some Gnome
239                                   #   functions have the return type on one line
240                                   #   and the rest of the declaration after.
241     my ($first_macro) = 1;        # Used to try to skip the standard #ifdef XXX
242                                   #   #define XXX at the start of headers.
243     my ($level);                  # Used to handle structs which contain nested
244                                   #   structs or unions.
245     my @objects = ();             # Holds declarations that look like GtkObject
246                                   #   subclasses, which we remove from the list.
248     my $file_basename;
250     my $deprecated_conditional_nest = 0;
252     my $deprecated = "";
254     if ($input_file =~ m/^.*[\/\\](.*)\.h$/) {
255         $file_basename = $1;
256     } else {
257         print "WARNING: Can't find basename of file $input_file\n";
258         $file_basename = $input_file;
259     }
261     # Check if the basename is in the list of headers to ignore.
262     if ($IGNORE_HEADERS =~ m/(\s|^)\Q${file_basename}\E\.h(\s|$)/) {
263 #       print "DEBUG: File ignored: $input_file\n";
264         return;
265     }
267     if (! -f $input_file) {
268         print "File doesn't exist: $input_file\n";
269         return;
270     }
272     open(INPUT, $input_file)
273         || die "Can't open $input_file: $!";
274     while(<INPUT>) {
275         # If this is a private header, skip it.
276         if (m%^\s*/\*\s*<\s*private_header\s*>\s*\*/%) {
277             close(INPUT);
278             return;
279         }
281         # Skip to the end of the current comment.
282         if ($in_comment) {
283 #           print "Comment: $_";
284             if (m%\*/%) {
285                 $in_comment = 0;
286             }
287             next;
288         }
290         # Keep a count of #if, #ifdef, #ifndef nesting,
291         # and if we enter a deprecation-symbol-bracketed
292         # zone, take note.
293         if (m/^\s*#\s*if(?:n?def\b|\s+!?\s*defined\s*\()\s*(\w+)/) {
294             if ($deprecated_conditional_nest == 0 and $1 =~ /$DEPRECATED_GUARDS/) {
295                  $deprecated_conditional_nest = 1;
296             } elsif ($deprecated_conditional_nest > 0) {
297                  $deprecated_conditional_nest += 1;
298             }
299         } elsif (m/^\s*#\sif/) {
300             if ($deprecated_conditional_nest > 0) {
301                  $deprecated_conditional_nest += 1;
302             }
303         } elsif (m/^\s*#endif/) {
304             if ($deprecated_conditional_nest > 0) {
305                 $deprecated_conditional_nest -= 1;
306             }
307         }
309         # set global that affects AddSymbolToList
310         if ($deprecated_conditional_nest > 0) {
311             $deprecated = "<DEPRECATED/>\n";
312         } else {
313             $deprecated = "";
314         }
316         if (!$in_declaration) {
317             # Skip top-level comments.
318             if (s%^\s*/\*%%) {
319                 if (m%\*/%) {
320                     #print "Found one-line comment: $_";
321                 } else {
322                     $in_comment = 1;
323                     #print "Found start of comment: $_";
324                 }
325                 next;
326             }
328             #print "0: $_";
330             # MACROS
332             if (m/^\s*#\s*define\s+(\w+)/) {
333                 $symbol = $1;
334                 # We assume all macros which start with '_' are private, but
335                 # we accept '_' itself which is the standard gettext macro.
336                 # We also try to skip the first macro if it looks like the
337                 # standard #ifndef HEADER_FILE #define HEADER_FILE etc.
338                 # And we only want TRUE & FALSE defined in GLib (libdefs.h in
339                 # libgnome also defines them if they are not already defined).
340                 if (($symbol !~ m/^_/
341                      && ($previous_line !~ m/#ifndef\s+$symbol/
342                          || $first_macro == 0)
343                      && (($symbol ne 'TRUE' && $symbol ne 'FALSE')
344                          || $MODULE eq 'glib'))
345                     || $symbol eq "_") {
346                     $decl = $_;
347                     $in_declaration = "macro";
348                 }
349                 $first_macro = 0;
350                 #print "DEBUG: Macro: $symbol\n";
353             # TYPEDEF'D FUNCTIONS (i.e. user functions)
355             } elsif (m/^\s*typedef\s+((const\s+|G_CONST_RETURN\s+)?\w+)\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/) {
356                 $ret_type = "$1 $3";
357                 $symbol = $4;
358                 $decl = $';
359                 $in_declaration = "user_function";
360                 #print "DEBUG: user function: $symbol\n";
363             # ENUMS
365             } elsif (s/^\s*enum\s+_(\w+)\s+\{/enum $1 {/) {
366                 # We assume that 'enum _<enum_name> {' is really the
367                 # declaration of enum <enum_name>.
368                 $symbol = $1;
369                 #print "DEBUG: plain enum: $symbol\n";
370                 $decl = $_;
371                 $in_declaration = "enum";
373             } elsif (m/^\s*typedef\s+enum\s+_(\w+)\s+\1\s*;/) {
374                 # We skip 'typedef <enum_name> _<enum_name>;' as the enum will
375                 # be declared elsewhere.
376                 #print "DEBUG: skipping enum typedef: $1\n";
378             } elsif (m/^\s*typedef\s+enum/) {
379                 $symbol = "";
380                 #print "DEBUG: typedef enum: -\n";
381                 $decl = $_;
382                 $in_declaration = "enum";
385             # STRUCTS
387             } elsif (m/^\s*typedef\s+struct\s+_(\w+)\s+\1\s*;/) {
388                 # We've found a 'typedef struct _<name> <name>;'
389                 # This could be an opaque data structure, so we output an
390                 # empty declaration. If the structure is actually found that
391                 # will override this.
392                 #print "DEBUG: struct typedef: $1\n";
393                 &AddSymbolToList (\$list, $1);
394                 print DECL "<STRUCT>\n<NAME>$1</NAME>\n$deprecated</STRUCT>\n";
396             } elsif (m/^\s*struct\s+_(\w+)\s*;/) {
397                 # Skip private structs.
398                 #print "DEBUG: private struct\n";
400             } elsif (m/^\s*struct\s+(\w+)\s*;/) {
401                 # Do a similar thing for normal structs as for typedefs above.
402                 # But we output the declaration as well in this case, so we
403                 # can differentiate it from a typedef.
404                 #print "DEBUG: struct: $1\n";
405                 &AddSymbolToList (\$list, $1);
406                 print DECL "<STRUCT>\n<NAME>$1</NAME>\n$_$deprecated</STRUCT>\n";
408             } elsif (m/^\s*typedef\s+struct\s*\w*\s*{/) {
409                 $symbol = "";
410                 $decl = $_;
411                 $level = 0;
412                 $in_declaration = "struct";
413                 #print "DEBUG: struct\n";
415             # OTHER TYPEDEFS
417             } elsif (m/^\s*typedef\s+struct\s+\w+[\s\*]+(\w+)\s*;/) {
418                 #print "DEBUG: Found struct* typedef: $_";
419                 &AddSymbolToList (\$list, $1);
420                 print DECL "<TYPEDEF>\n<NAME>$1</NAME>\n$deprecated$_</TYPEDEF>\n";
422             } elsif (m/^\s*(G_GNUC_EXTENSION\s+)?typedef\s+(.+[\s\*])(\w+)(\s*\[[^\]]+\])*\s*;/) {
423                 if ($2 !~ m/^struct\s/ && $2 !~ m/^union\s/) {
424                     #print "DEBUG: Found typedef: $_";
425                     &AddSymbolToList (\$list, $3);
426                     print DECL "<TYPEDEF>\n<NAME>$3</NAME>\n$deprecated$_</TYPEDEF>\n";
427                 }
428             } elsif (m/^\s*typedef\s+/) {
429                 #print "DEBUG: Skipping typedef: $_";
432             # VARIABLES (extern'ed variables)
434             } elsif (m/^\s*(extern|[A-Za-z_]+VAR)\s+((const\s+|unsigned\s+)*\w+)(\s+\*+|\*+|\s)\s*([A-Za-z]\w*)\s*;/) {
435                 $symbol = $5;
436                 s/^\s*([A-Za-z_]+VAR)\b/extern/;
437                 #print "DEBUG: Possible extern: $_";
438                 &AddSymbolToList (\$list, $symbol);
439                 print DECL "<VARIABLE>\n<NAME>$symbol</NAME>\n$deprecated$_</VARIABLE>\n";
442             # FUNCTIONS
444             # We assume that functions which start with '_' are private, so
445             # we skip them.
446             #                                                                        $1                                                                                                                                 $2
447             } elsif (m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|unsigned\s+|struct\s+|enum\s+)*\w+(?:\**\s+\**(?:const|G_CONST_RETURN))?(?:\s+|\s*\*+))\s*\(\s*\*+\s*([A-Za-z]\w*)\s*\)\s*\(/o) {
448                 $ret_type = $1;
449                 $symbol = $2;
450                 $decl = $';
452                 #print "DEBUG: FunctionPointer: $symbol, Returns: $ret_type\n";
454                 $in_declaration = "function";
456             } elsif (m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|unsigned\s+|struct\s+|enum\s+)*\w+(?:\**\s+\**(?:const|G_CONST_RETURN))?(?:\s+|\s*\*+))\s*([A-Za-z]\w*)\s*\(/o) {
457                 $ret_type = $1;
458                 $symbol = $2;
459                 $decl = $';
461                 #print "DEBUG: Function: $symbol, Returns: $ret_type\n";
463                 $in_declaration = "function";
465             # Try to catch function declarations which have the return type on
466             # the previous line. But we don't want to catch complete functions
467             # which have been declared G_INLINE_FUNC, e.g. g_bit_nth_lsf in
468             # glib, or 'static inline' functions.
469             } elsif (m/^\s*([A-Za-z]\w*)\s*\(/) {
470                 $symbol = $1;
471                 $decl = $';
473                 if ($previous_line !~ m/^\s*G_INLINE_FUNC/
474                     && $previous_line !~ m/^\s*static\s+/) {
475                     if ($previous_line =~ m/^\s*(?:\b(?:extern|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|unsigned\s+|struct\s+|enum\s+)?\w+)((?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*$/o) {
476                         $ret_type = $1;
477                         if (defined ($2)) { $ret_type .= " $2"; }
478                         #print "DEBUG: Function: $symbol, Returns: $ret_type\n";
479                         $in_declaration = "function";
480                     }
481                 }
483             # Try to catch function declarations with the return type and name
484             # on the previous line(s), and the start of the parameters on this.
485             } elsif (m/^\s*\(/) {
486                 $decl = $';
487                 if ($previous_line =~ m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|unsigned\s+|enum\s+)*\w+)(\s+\*+|\*+|\s)\s*([A-Za-z]\w*)\s*$/o) {
488                     $ret_type = "$1 $2";
489                     $symbol = $3;
490                     #print "DEBUG: Function: $symbol, Returns: $ret_type\n";
491                     $in_declaration = "function";
493                 } elsif ($previous_line =~ m/^\s*\w+\s*$/
494                          && $pre_previous_line =~ m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|unsigned\s+|struct\s+|enum\s+)*\w+(?:\**\s+\**(?:const|G_CONST_RETURN))?(?:\s+|\s*\*+))\s*$/o) {
495                         $ret_type = $1;
496                         $ret_type =~ s/\s*\n//;
497                         $in_declaration = "function";
499                         $symbol = $previous_line;
500                         $symbol =~ s/^\s+//;
501                         $symbol =~ s/\s*\n//;
502                         #print "DEBUG: Function: $symbol, Returns: $ret_type\n";
503                 }
505             #} elsif (m/^extern\s+/) {
506                 #print "DEBUG: Skipping extern: $_";
509             # STRUCTS
511             } elsif (m/^\s*struct\s+_(\w+)/) {
512                 # We assume that 'struct _<struct_name>' is really the
513                 # declaration of struct <struct_name>.
514                 $symbol = $1;
515                 $decl = $_;
516                 if (m/^\s*struct\s+_(\w+)\s*{/) {
517                     $level = 1;
518                 } else {
519                     $level = 0;
520                 }
521                 $in_declaration = "struct";
522                 #print "DEBUG: Struct(_): $symbol\n";
525             # UNIONS
527             } elsif (s/^\s*union\s+_(\w+)/union $1/) {
528                 $symbol = $1;
529                 $decl = $_;
530                 $in_declaration = "union";
531                 #print "DEBUG: Union: $symbol\n";
532             }
534         } else {
535             #print "1: $_";
536             # If we were already in the middle of a declaration, we simply add
537             # the current line onto the end of it.
538             $decl .= $_;
539         }
541         #if ($in_declaration ne '') {
542         #    print "= $decl\n";
543         #}
545         # Note that sometimes functions end in ') G_GNUC_PRINTF (2, 3);' or
546         # ') __attribute__ (...);'.
547         if ($in_declaration eq 'function') {
548             if ($decl =~ s/\)\s*(G_GNUC_.*|__attribute__\s*\(.*\)\s*)?;.*$//) {
549                 $decl =~ s%/\*.*?\*/%%gs;       # remove comments.
550 #               $decl =~ s/^\s+//;              # remove leading whitespace.
551 #               $decl =~ s/\s+$//;              # remove trailing whitespace.
552                 $decl =~ s/\s*\n\s*//g;         # remove whitespace at start
553                                                 # and end of lines.
554                 $ret_type =~ s%/\*.*?\*/%%g;    # remove comments in ret type.
555                 &AddSymbolToList (\$list, $symbol);
556                 print DECL "<FUNCTION>\n<NAME>$symbol</NAME>\n$deprecated<RETURNS>$ret_type</RETURNS>\n$decl\n</FUNCTION>\n";
557                 $in_declaration = "";
558             }
559         }
561         if ($in_declaration eq 'user_function') {
562             if ($decl =~ s/\).*$//) {
563                 &AddSymbolToList (\$list, $symbol);
564                 print DECL "<USER_FUNCTION>\n<NAME>$symbol</NAME>\n$deprecated<RETURNS>$ret_type</RETURNS>\n$decl</USER_FUNCTION>\n";
565                 $in_declaration = "";
566             }
567         }
569         if ($in_declaration eq 'macro') {
570             if ($decl !~ m/\\\s*$/) {
571                 &AddSymbolToList (\$list, $symbol);
572                 print DECL "<MACRO>\n<NAME>$symbol</NAME>\n$deprecated$decl</MACRO>\n";
573                 $in_declaration = "";
574             }
575         }
577         if ($in_declaration eq 'enum') {
578             if ($decl =~ m/\}\s*(\w+)?;\s*$/) {
579                 if ($symbol eq "") {
580                     $symbol = $1;
581                 }
582                 &AddSymbolToList (\$list, $symbol);
583                 print DECL "<ENUM>\n<NAME>$symbol</NAME>\n$deprecated$decl</ENUM>\n";
584                 $in_declaration = "";
585             }
586         }
588         # We try to handle nested stucts/unions, but unmatched brackets in
589         # comments will cause problems.
590         if ($in_declaration eq 'struct') {
591             if ($level <= 1 && $decl =~ m/\}\s*(\w*);\s*$/) {
592                 if ($symbol eq "") {
593                     $symbol = $1;
594                 }
596                 if ($symbol =~ m/^(\S+)Class/) {
597 #                   print "Found object: $1\n";
598                     $list .= "<TITLE>$1</TITLE>\n$1\n";
599                     push (@objects, $1);
600                 }
601                 #print "Store struct: $symbol\n";
602                 &AddSymbolToList (\$list, $symbol);
604                 print DECL "<STRUCT>\n<NAME>$symbol</NAME>\n$deprecated$decl</STRUCT>\n";
605                 $in_declaration = "";
606             } else {
607                 # We use tr to count the brackets in the line, and adjust
608                 # $level accordingly.
609                 $level += tr/{//;
610                 $level -= tr/}//;
611             }
612         }
614         if ($in_declaration eq 'union') {
615             if ($decl =~ m/\}\s*;\s*$/) {
616                 &AddSymbolToList (\$list, $symbol);
617                 print DECL "<UNION>\n<NAME>$symbol</NAME>\n$deprecated$decl</UNION>\n";
618                 $in_declaration = "";
619             }
620         }
622         $pre_previous_line = $previous_line;
623         $previous_line = $_;
624     }
625     close(INPUT);
627     # Take out any object structs from the list of declarations as we don't
628     # want them included.
629     my ($object);
630     foreach $object (@objects) {
631         $list =~ s/^$object\n//m;
632         $list =~ s/^${object}Class\n//m;
633     }
636     # Try to separate the standard macros and functions, placing them at the
637     # end of the current section, in a subsection named 'Standard'.
638     my ($class) = "";
639     my ($standard_decl) = "";
640     if ($list =~ m/^\S+_IS_(\S*)_CLASS/m) {
641         $class = $1;
642     } elsif ($list =~ m/^\S+_IS_(\S*)/m) {
643         $class = $1;
644     }
646     if ($REBUILD_TYPES) {
647       while ($list =~ m/^\S+_.*_get_type\n/mg) {
648 #        print "Adding get-type: $&\tfrom $input_file\n";
649         print TYPES $&;
650       }
651     }
653     if ($class ne "") {
654         if ($list =~ s/^\S+_IS_$class\n//m)          { $standard_decl .= $&; }
655         if ($list =~ s/^\S+_TYPE_$class\n//m)        { $standard_decl .= $&; }
656         if ($list =~ s/^\S+_.*_get_type\n//m)        { $standard_decl .= $&; }
657         if ($list =~ s/^\S+_${class}_CLASS\n//m)     { $standard_decl .= $&; }
658         if ($list =~ s/^\S+_IS_${class}_CLASS\n//m)  { $standard_decl .= $&; }
659         if ($list =~ s/^\S+_${class}_GET_CLASS\n//m) { $standard_decl .= $&; }
660         if ($list =~ s/^\S+_${class}_GET_IFACE\n//m) { $standard_decl .= $&; }
662         # We do this one last, otherwise it tends to be caught by the IS_$class macro
663         if ($list =~ s/^\S+_$class\n//m)             { $standard_decl = $& . $standard_decl; }
665         if ($standard_decl ne "") {
666             $list .= "<SUBSECTION Standard>\n$standard_decl";
667         }
669         $$object_list .= "<SECTION>\n<FILE>$file_basename</FILE>\n$list</SECTION>\n\n";
670     } else {
671         $$main_list .= "<SECTION>\n<FILE>$file_basename</FILE>\n$list</SECTION>\n\n";
672     }
676 #############################################################################
677 # Function    : AddSymbolToList
678 # Description : This adds the symbol to the list of declarations, but only if
679 #               it is not already in the list.
680 # Arguments   : $list - reference to the list of symbols, one on each line.
681 #               $symbol - the symbol to add to the list.
682 #############################################################################
684 sub AddSymbolToList {
685     my ($list, $symbol) = @_;
687     if ($$list =~ m/\b\Q$symbol\E\b/) {
688 #       print "Symbol $symbol already in list. skipping\n";
689         return;
690     }
691     $$list .= "$symbol\n";