Add commented out TESTS. Check for location of gtkdoc-check.
[gtk-doc.git] / gtkdoc-scan.in
blob43215038dca41989a332de122f1554368a981739
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) = ();
186     
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;
249     
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             # MACROS
330             if (m/^\s*#\s*define\s+(\w+)/) {
331                 $symbol = $1;
332                 # We assume all macros which start with '_' are private, but
333                 # we accept '_' itself which is the standard gettext macro.
334                 # We also try to skip the first macro if it looks like the
335                 # standard #ifndef HEADER_FILE #define HEADER_FILE etc.
336                 # And we only want TRUE & FALSE defined in GLib (libdefs.h in
337                 # libgnome also defines them if they are not already defined).
338                 if (($symbol !~ m/^_/
339                      && ($previous_line !~ m/#ifndef\s+$symbol/
340                          || $first_macro == 0)
341                      && (($symbol ne 'TRUE' && $symbol ne 'FALSE')
342                          || $MODULE eq 'glib'))
343                     || $symbol eq "_") {
344                     $decl = $_;
345                     $in_declaration = "macro";
346                 }
347                 $first_macro = 0;
350             # TYPEDEF'D FUNCTIONS (i.e. user functions)
352             } elsif (m/^\s*typedef\s+((const\s+|G_CONST_RETURN\s+)?\w+)\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/) {
353                 $ret_type = "$1 $3";
354                 $symbol = $4;
355                 $decl = $';
356                 $in_declaration = "user_function";
359             # ENUMS
361             } elsif (s/^\s*enum\s+_(\w+)\s+\{/enum $1 {/) {
362                 # We assume that 'enum _<enum_name> {' is really the
363                 # declaration of enum <enum_name>.
364                 $symbol = $1;
365 #               print "DEBUG: plain enum: $symbol\n";
366                 $decl = $_;
367                 $in_declaration = "enum";
369             } elsif (m/^\s*typedef\s+enum\s+_(\w+)\s+\1\s*;/) {
370                 # We skip 'typedef <enum_name> _<enum_name>;' as the enum will
371                 # be declared elsewhere.
372 #               print "DEBUG: skipping enum typedef: $1\n";
374             } elsif (m/^\s*typedef\s+enum/) {
375                 $symbol = "";
376 #               print "DEBUG: typedef enum: -\n";
377                 $decl = $_;
378                 $in_declaration = "enum";
381             # STRUCTS
383             } elsif (m/^\s*typedef\s+struct\s+_(\w+)\s+\1\s*;/) {
384                 # We've found a 'typedef struct _<name> <name>;'
385                 # This could be an opaque data structure, so we output an
386                 # empty declaration. If the structure is actually found that
387                 # will override this.
388 #               print "DEBUG: struct typedef: $1\n";
389                 &AddSymbolToList (\$list, $1);
390                 print DECL "<STRUCT>\n<NAME>$1</NAME>\n$deprecated</STRUCT>\n";
392             } elsif (m/^\s*struct\s+_(\w+)\s*;/) {
393                 # Skip private structs.
395             } elsif (m/^\s*struct\s+(\w+)\s*;/) {
396                 # Do a similar thing for normal structs as for typedefs above.
397                 # But we output the declaration as well in this case, so we
398                 # can differentiate it from a typedef.
399                 &AddSymbolToList (\$list, $1);
400                 print DECL "<STRUCT>\n<NAME>$1</NAME>\n$_$deprecated</STRUCT>\n";
402             } elsif (m/^\s*typedef\s+struct\s*\w*\s*{/) {
403                 $symbol = "";
404                 $decl = $_;
405                 $level = 0;
406                 $in_declaration = "struct";
408             } elsif (m/^\s*struct\s+_?(\w+)/) {
409                 # We assume that 'struct _<struct_name>' is really the
410                 # declaration of struct <struct_name>.
411                 $symbol = $1;
412                 $decl = $_;
413                 $level = 0;
414                 $in_declaration = "struct";
417             # UNIONS
419             } elsif (s/^\s*union\s+_(\w+)/union $1/) {
420                 $symbol = $1;
421                 $decl = $_;
422                 $in_declaration = "union";
425             # OTHER TYPEDEFS
427             } elsif (m/^\s*typedef\s+struct\s+\w+[\s\*]+(\w+)\s*;/) {
428 #               print "Found struct* typedef: $_";
429                 &AddSymbolToList (\$list, $1);
430                 print DECL "<TYPEDEF>\n<NAME>$1</NAME>\n$deprecated$_</TYPEDEF>\n";
432             } elsif (m/^\s*(G_GNUC_EXTENSION\s+)?typedef\s+(.+[\s\*])(\w+)(\s*\[[^\]]+\])*\s*;/) {
433                 if ($2 !~ m/^struct\s/ && $2 !~ m/^union\s/) {
434 #                   print "Found typedef: $_";
435                     &AddSymbolToList (\$list, $3);
436                     print DECL "<TYPEDEF>\n<NAME>$3</NAME>\n$deprecated$_</TYPEDEF>\n";
437                 }
438             } elsif (m/^\s*typedef\s+/) {
439 #               print "Skipping typedef: $_";
442             # VARIABLES (extern'ed variables)
444             } elsif (m/^\s*(extern|[A-Za-z_]+VAR)\s+((const\s+|unsigned\s+)*\w+)(\s+\*+|\*+|\s)\s*([A-Za-z]\w*)\s*;/) {
445                 $symbol = $5;
446                 s/^\s*([A-Za-z_]+VAR)\b/extern/;
447 #               print "Possible extern: $_";
448                 &AddSymbolToList (\$list, $symbol);
449                 print DECL "<VARIABLE>\n<NAME>$symbol</NAME>\n$deprecated$_</VARIABLE>\n";
452             # FUNCTIONS
454             # We assume that functions which start with '_' are private, so
455             # we skip them.
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*\(/) {
457                 $ret_type = $1;
458                 $symbol = $2;
459                 $decl = $';
461 #               print "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 = $';
472                 if ($previous_line !~ m/^\s*G_INLINE_FUNC/
473                     && $previous_line !~ m/^\s*static\s+/) {
474                     if ($previous_line =~ m/^\s*(?:\b(?:extern|${IGNORE_DECORATORS})\b\s*)*((?:const\s+|G_CONST_RETURN\s+|unsigned\s+|enum\s+)?\w+)(\s*\*+)?\s*$/) {
475                         $ret_type = $1;
476                         if (defined ($2)) { $ret_type .= " $2"; }
477 #                       print "Function: $symbol, Returns: $ret_type\n";
478                         $in_declaration = "function";
479                     }
480                 }
482             # Try to catch function declarations with the return type and name
483             # on the previous line(s), and the start of the parameters on this.
484             } elsif (m/^\s*\(/) {
485                 $decl = $';
486                 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*$/) {
487                     $ret_type = "$1 $2";
488                     $symbol = $3;
489 #                   print "Function: $symbol, Returns: $ret_type\n";
490                     $in_declaration = "function";
492                 } elsif ($previous_line =~ m/^\s*\w+\s*$/
493                          && $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*$/) {
494                         $ret_type = $1;
495                         $ret_type =~ s/\s*\n//;
496                         $in_declaration = "function";
498                         $symbol = $previous_line;
499                         $symbol =~ s/^\s+//;
500                         $symbol =~ s/\s*\n//;
501 #                       print "Function: $symbol, Returns: $ret_type\n";
502                 }
504 #           } elsif (m/^extern\s+/) {
505 #               print "Skipping extern: $_";
507             }
508         } else {
509             # If we were already in the middle of a declaration, we simply add
510             # the current line onto the end of it.
511             $decl .= $_;
512         }
514         # Note that sometimes functions end in ') G_GNUC_PRINTF (2, 3);' or
515         # ') __attribute__ (...);'.
516         if ($in_declaration eq 'function') {
517             if ($decl =~ s/\)\s*(G_GNUC_.*|__attribute__\s*\(.*\)\s*)?;.*$//) {
518                 $decl =~ s%/\*.*?\*/%%gs;       # remove comments.
519 #               $decl =~ s/^\s+//;              # remove leading whitespace.
520 #               $decl =~ s/\s+$//;              # remove trailing whitespace.
521                 $decl =~ s/\s*\n\s*//g;         # remove whitespace at start
522                                                 # and end of lines.
523                 $ret_type =~ s%/\*.*?\*/%%g;    # remove comments in ret type.
524                 &AddSymbolToList (\$list, $symbol);
525                 print DECL "<FUNCTION>\n<NAME>$symbol</NAME>\n$deprecated<RETURNS>$ret_type</RETURNS>\n$decl\n</FUNCTION>\n";
526                 $in_declaration = "";
527             }
528         }
530         if ($in_declaration eq 'user_function') {
531             if ($decl =~ s/\).*$//) {
532                 &AddSymbolToList (\$list, $symbol);
533                 print DECL "<USER_FUNCTION>\n<NAME>$symbol</NAME>\n$deprecated<RETURNS>$ret_type</RETURNS>\n$decl</USER_FUNCTION>\n";
534                 $in_declaration = "";
535             }
536         }
538         if ($in_declaration eq 'macro') {
539             if ($decl !~ m/\\\s*$/) {
540                 &AddSymbolToList (\$list, $symbol);
541                 print DECL "<MACRO>\n<NAME>$symbol</NAME>\n$deprecated$decl</MACRO>\n";
542                 $in_declaration = "";
543             }
544         }
546         if ($in_declaration eq 'enum') {
547             if ($decl =~ m/\}\s*(\w+)?;\s*$/) {
548                 if ($symbol eq "") {
549                     $symbol = $1;
550                 }
551                 &AddSymbolToList (\$list, $symbol);
552                 print DECL "<ENUM>\n<NAME>$symbol</NAME>\n$deprecated$decl</ENUM>\n";
553                 $in_declaration = "";
554             }
555         }
557         # We try to handle nested stucts/unions, but unmatched brackets in
558         # comments will cause problems.
559         if ($in_declaration eq 'struct') {
560             if ($level <= 1 && $decl =~ m/\}\s*(\w*);\s*$/) {
561                 if ($symbol eq "") {
562                     $symbol = $1;
563                 }
565                 if ($symbol =~ m/^(\S+)Class/) {
566 #                   print "Found object: $1\n";
567                     $list .= "<TITLE>$1</TITLE>\n$1\n";
568                     push (@objects, $1);
569                 }
570                 &AddSymbolToList (\$list, $symbol);
572                 print DECL "<STRUCT>\n<NAME>$symbol</NAME>\n$deprecated$decl</STRUCT>\n";
573                 $in_declaration = "";
574             } else {
575                 # We use tr to count the brackets in the line, and adjust
576                 # $level accordingly.
577                 $level += tr/{//;
578                 $level -= tr/}//;
579             }
580         }
582         if ($in_declaration eq 'union') {
583             if ($decl =~ m/\}\s*;\s*$/) {
584                 &AddSymbolToList (\$list, $symbol);
585                 print DECL "<UNION>\n<NAME>$symbol</NAME>\n$deprecated$decl</UNION>\n";
586                 $in_declaration = "";
587             }
588         }
590         $pre_previous_line = $previous_line;
591         $previous_line = $_;
592     }
593     close(INPUT);
595     # Take out any object structs from the list of declarations as we don't
596     # want them included.
597     my ($object);
598     foreach $object (@objects) {
599         $list =~ s/^$object\n//m;
600         $list =~ s/^${object}Class\n//m;
601     }
604     # Try to separate the standard macros and functions, placing them at the
605     # end of the current section, in a subsection named 'Standard'.
606     my ($class) = "";
607     my ($standard_decl) = "";
608     if ($list =~ m/^\S+_IS_(\S*)_CLASS/m) {
609         $class = $1;
610     } elsif ($list =~ m/^\S+_IS_(\S*)/m) {
611         $class = $1;
612     }
614     if ($REBUILD_TYPES) {
615       while ($list =~ m/^\S+_.*_get_type\n/mg) {
616 #        print "Adding get-type: $&\tfrom $input_file\n";
617         print TYPES $&;
618       }
619     }
621     if ($class ne "") {
622         if ($list =~ s/^\S+_IS_$class\n//m)          { $standard_decl .= $&; }
623         if ($list =~ s/^\S+_TYPE_$class\n//m)        { $standard_decl .= $&; }
624         if ($list =~ s/^\S+_.*_get_type\n//m)        { $standard_decl .= $&; }
625         if ($list =~ s/^\S+_${class}_CLASS\n//m)     { $standard_decl .= $&; }
626         if ($list =~ s/^\S+_IS_${class}_CLASS\n//m)  { $standard_decl .= $&; }
627         if ($list =~ s/^\S+_${class}_GET_CLASS\n//m) { $standard_decl .= $&; }
628         if ($list =~ s/^\S+_${class}_GET_IFACE\n//m) { $standard_decl .= $&; }
630         # We do this one last, otherwise it tends to be caught by the IS_$class macro
631         if ($list =~ s/^\S+_$class\n//m)             { $standard_decl = $& . $standard_decl; }
633         if ($standard_decl ne "") {
634             $list .= "<SUBSECTION Standard>\n$standard_decl";
635         }
637         $$object_list .= "<SECTION>\n<FILE>$file_basename</FILE>\n$list</SECTION>\n\n";
638     } else {
639         $$main_list .= "<SECTION>\n<FILE>$file_basename</FILE>\n$list</SECTION>\n\n";
640     }
644 #############################################################################
645 # Function    : AddSymbolToList
646 # Description : This adds the symbol to the list of declarations, but only if
647 #               it is not already in the list.
648 # Arguments   : $list - reference to the list of symbols, one on each line.
649 #               $symbol - the symbol to add to the list.
650 #############################################################################
652 sub AddSymbolToList {
653     my ($list, $symbol) = @_;
655     if ($$list =~ m/\b\Q$symbol\E\b/) {
656 #       print "Symbol $symbol already in list. skipping\n";
657         return;
658     }
659     $$list .= "$symbol\n";