Updated Spanish translation
[gtk-doc.git] / gtkdoc-scan.in
blob048e5c91c5b91f4b02c3bbe54463e4ee91d4c8ec
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 @get_types = ();
66 # do not read files twice; checking it here permits to give both srcdir and
67 # builddir as --source-dir without fear of duplicities
68 my %seen_headers;
71 run() unless caller; # Run program unless loaded as a module
74 sub run {
75     my %optctl = (module => \$MODULE,
76                   'source-dir' => \@SOURCE_DIRS,
77                   'ignore-headers' => \$IGNORE_HEADERS,
78                   'output-dir' => \$OUTPUT_DIR,
79                   'rebuild-types' => \$REBUILD_TYPES,
80                   'rebuild-sections' => \$REBUILD_SECTIONS,
81                   'version' => \$PRINT_VERSION,
82                   'help' => \$PRINT_HELP,
83                   'deprecated-guards' => \$DEPRECATED_GUARDS,
84                   'ignore-decorators' => \$IGNORE_DECORATORS);
85     GetOptions(\%optctl, "module=s", "source-dir:s", "ignore-headers:s",
86                "output-dir:s", "rebuild-types", "rebuild-sections", "version",
87                "help", "deprecated-guards:s", "ignore-decorators:s");
88     
89     if ($PRINT_VERSION) {
90         print "@VERSION@\n";
91         exit 0;
92     }
93     
94     if (!$MODULE) {
95         $PRINT_HELP = 1;
96     }
97     
98     if ($PRINT_HELP) {
99         print <<EOF;
100 gtkdoc-scan version @VERSION@ - scan header files for public symbols
102 --module=MODULE_NAME       Name of the doc module being parsed
103 --source-dir=DIRNAME       Directories containing the source files to scan
104 --ignore-headers=FILES     A space-separated list of header files/dirs not to
105                            scan
106 --output-dir=DIRNAME       The directory where the results are stored
107 --deprecated-guards=GUARDS A |-separated list of symbols used as deprecation
108                            guards
109 --ignore-decorators=DECS   A |-separated list of addition decorators in
110                            declarations that should be ignored
111 --rebuild-sections         Rebuild (overwrite) the MODULE-sections.txt file
112 --rebuild-types            Automatically recreate the MODULE.types file using
113                            all the *_get_type() functions found
114 --version                  Print the version of this program
115 --help                     Print this help
117         exit 0;
118     }
119     
120     $DEPRECATED_GUARDS = $DEPRECATED_GUARDS ? $DEPRECATED_GUARDS : "does_not_match_any_cpp_symbols_at_all_nope";
121     
122     $IGNORE_DECORATORS = $IGNORE_DECORATORS || "(?=no)match";
123     
124     $OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
125     
126     if (!-d ${OUTPUT_DIR}) {
127         mkdir($OUTPUT_DIR, 0755) || die "Cannot create $OUTPUT_DIR: $!";
128     }
129     
130     my $old_decl_list = "${OUTPUT_DIR}/$MODULE-decl-list.txt";
131     my $new_decl_list = "${OUTPUT_DIR}/$MODULE-decl-list.new";
132     my $old_decl = "${OUTPUT_DIR}/$MODULE-decl.txt";
133     my $new_decl = "${OUTPUT_DIR}/$MODULE-decl.new";
134     my $old_types = "${OUTPUT_DIR}/$MODULE.types";
135     my $new_types = "${OUTPUT_DIR}/$MODULE.types.new";
136     my $sections_file = "${OUTPUT_DIR}/$MODULE-sections.txt";
137     
138     # If this is the very first run then we create the .types file automatically.
139     if (! -e $sections_file && ! -e $old_types) {
140         $REBUILD_TYPES = 1;
141     }
142     
143     open (DECLLIST, ">$new_decl_list")
144         || die "Can't open $new_decl_list";
145     open (DECL, ">$new_decl")
146         || die "Can't open $new_decl";
147     if ($REBUILD_TYPES) {
148         open (TYPES, ">$new_types")
149             || die "Can't open $new_types";
150     }
151     
152     my %section_list = ();
153     my $file;
154    
155     # The header files to scan are passed in as command-line args.
156     for $file (@ARGV) {
157         &ScanHeader ($file, \%section_list);
158     }
159     
160     for my $dir (@SOURCE_DIRS) {
161         &ScanHeaders ($dir, \%section_list);
162     }
163     
164     ## FIXME: sort by key and output
165     #print DECLLIST $section_list;
166     my $section;
167     foreach $section (sort(keys %section_list)) {
168         print DECLLIST "$section_list{$section}";
169     }
170     
171     close (DECLLIST);
172     close (DECL);
173     
174     if ($REBUILD_TYPES) {
175         my $func;
176     
177         foreach $func (sort(@get_types)) {
178            print TYPES "$func\n";
179         }
180         close (TYPES);
181         &UpdateFileIfChanged ($old_types, $new_types, 1);
182     
183         # remove the file if empty
184         if (scalar (@get_types) == 0) {
185             unlink ("$new_types");
186         }
187     }
188     
189     &UpdateFileIfChanged ($old_decl_list, $new_decl_list, 1);
190     &UpdateFileIfChanged ($old_decl, $new_decl, 1);
191     
192     # If there is no MODULE-sections.txt file yet or we are asked to rebuild it,
193     # we copy the MODULE-decl-list.txt file into its place. The user can tweak it
194     # later if they want.
195     if ($REBUILD_SECTIONS || ! -e $sections_file) {
196       `cp $old_decl_list $sections_file`;
197     }
198     
199     # If there is no MODULE-overrides.txt file we create an empty one
200     # because EXTRA_DIST in gtk-doc.make requires it.
201     my $overrides_file = "${OUTPUT_DIR}/$MODULE-overrides.txt";
202     if (! -e $overrides_file) {
203       `touch $overrides_file`;
204     }
208 #############################################################################
209 # Function    : ScanHeaders
210 # Description : This scans a directory tree looking for header files.
212 # Arguments   : $source_dir - the directory to scan.
213 #               $section_list - a reference to the hashmap of sections.
214 #############################################################################
216 sub ScanHeaders {
217     my ($source_dir, $section_list) = @_;
218     @TRACE@("Scanning source directory: $source_dir");
220     # This array holds any subdirectories found.
221     my (@subdirs) = ();
223     opendir (SRCDIR, $source_dir)
224         || die "Can't open source directory $source_dir: $!";
225     my $file;
226     foreach $file (readdir (SRCDIR)) {
227         if ($file eq '.' || $file eq '..' || $file =~ /^\./) {
228             next;
229         } elsif (-d "$source_dir/$file") {
230             push (@subdirs, $file);
231         } elsif ($file =~ m/\.h$/) {
232             &ScanHeader ("$source_dir/$file", $section_list);
233         }
234     }
235     closedir (SRCDIR);
237     # Now recursively scan the subdirectories.
238     my $dir;
239     foreach $dir (@subdirs) {
240         next if ($IGNORE_HEADERS =~ m/(\s|^)\Q${dir}\E(\s|$)/);
241         &ScanHeaders ("$source_dir/$dir", $section_list);
242     }
246 #############################################################################
247 # Function    : ScanHeader
248 # Description : This scans a header file, looking for declarations of
249 #                functions, macros, typedefs, structs and unions, which it
250 #                outputs to the DECL file.
251 # Arguments   : $input_file - the header file to scan.
252 #               $section_list - a reference to the hashmap of sections.
253 # Returns     : it adds declarations to the appropriate list.
254 #############################################################################
256 sub ScanHeader {
257     my ($input_file, $section_list) = @_;
259     my $list = "";                  # Holds the resulting list of declarations.
260     my $title = "";                 # Holds the title of the section    
261     my ($in_comment) = 0;                  # True if we are in a comment.
262     my ($in_declaration) = "";          # The type of declaration we are in, e.g.
263                                   #   'function' or 'macro'.
264     my ($skip_block) = 0;                  # True if we should skip a block.
265     my ($symbol);                  # The current symbol being declared.
266     my ($decl);                          # Holds the declaration of the current symbol.
267     my ($ret_type);                  # For functions and function typedefs this
268                                   #   holds the function's return type.
269     my ($pre_previous_line) = "";   # The pre-previous line read in - some Gnome
270                                   #   functions have the return type on one
271                                   #   line, the function name on the next,
272                                   #   and the rest of the declaration after.
273     my ($previous_line) = "";          # The previous line read in - some Gnome
274                                   #   functions have the return type on one line
275                                   #   and the rest of the declaration after.
276     my ($first_macro) = 1;          # Used to try to skip the standard #ifdef XXX
277                                   #   #define XXX at the start of headers.
278     my ($level);                          # Used to handle structs/unions which contain
279                                   #   nested structs or unions.
280     my @objects = ();                  # Holds declarations that look like GtkObject
281                                   #   subclasses, which we remove from the list.
282     my ($internal) = 0;             # Set to 1 for internal symbols, we need to
283                                     #   fully parse, but don't add them to docs
284     my %forward_decls = ();         # hashtable of forward declarations, we skip
285                                     #   them if we find the real declaration
286                                     #   later.
287     my %doc_comments = ();          # hastable of doc-comment we found. We can
288                                     # use that to put element to the right
289                                     # sction in the generated section-file 
291     my $file_basename;
293     my $deprecated_conditional_nest = 0;
294     my $ignore_conditional_nest = 0;
296     my $deprecated = "";
297     my $doc_comment = "";
299     # Don't scan headers twice
300     my $canonical_input_file = realpath $input_file;
301     if (exists $seen_headers{$canonical_input_file}) {
302         @TRACE@("File already scanned: $input_file");
303         return;
304     }
305     $seen_headers{$canonical_input_file} = 1;
307     if ($input_file =~ m/^.*[\/\\](.*)\.h+$/) {
308         $file_basename = $1;
309     } else {
310         LogWarning(__FILE__,__LINE__,"Can't find basename of file $input_file");
311         $file_basename = $input_file;
312     }
314     # Check if the basename is in the list of headers to ignore.
315     if ($IGNORE_HEADERS =~ m/(\s|^)\Q${file_basename}\E\.h(\s|$)/) {
316         @TRACE@("File ignored: $input_file");
317         return;
318     }
319     # Check if the full name is in the list of headers to ignore.
320     if ($IGNORE_HEADERS =~ m/(\s|^)\Q${input_file}\E(\s|$)/) {
321         @TRACE@("File ignored: $input_file");
322         return;
323     }
325     if (! -f $input_file) {
326         LogWarning(__FILE__,__LINE__,"File doesn't exist: $input_file");
327         return;
328     }
330     @TRACE@("Scanning $input_file");
332     open(INPUT, $input_file)
333         || die "Can't open $input_file: $!";
334     while(<INPUT>) {
335         # If this is a private header, skip it.
336         if (m%^\s*/\*\s*<\s*private_header\s*>\s*\*/%) {
337             close(INPUT);
338             return;
339         }
341         # Skip to the end of the current comment.
342         if ($in_comment) {
343             @TRACE@("Comment: $_");
344             $doc_comment .= $_;
345             if (m%\*/%) {
346                 if ($doc_comment =~ m/\* ([a-zA-Z][a-zA-Z0-9_]+):/) {
347                   $doc_comments{lc($1)} = 1;
348                 }
349                 $in_comment = 0;
350                 $doc_comment = "";
351             }
352             next;
353         }
355         # Keep a count of #if, #ifdef, #ifndef nesting,
356         # and if we enter a deprecation-symbol-bracketed
357         # zone, take note.
358         if (m/^\s*#\s*if(?:n?def\b|\s+!?\s*defined\s*\()\s*(\w+)/) {
359             my $define_name = $1;
360             if ($deprecated_conditional_nest < 1 and $define_name =~ /$DEPRECATED_GUARDS/) {
361                  $deprecated_conditional_nest = 1;
362             } elsif ($deprecated_conditional_nest >= 1) {
363                  $deprecated_conditional_nest += 1;
364             }
365             if ($ignore_conditional_nest == 0 and $define_name =~ /__GTK_DOC_IGNORE__/) {
366                  $ignore_conditional_nest = 1;
367             } elsif ($ignore_conditional_nest > 0) {
368                  $ignore_conditional_nest += 1;
369             }
370         } elsif (m/^\s*#\sif/) {
371             if ($deprecated_conditional_nest >= 1) {
372                  $deprecated_conditional_nest += 1;
373             }
374             if ($ignore_conditional_nest > 0) {
375                  $ignore_conditional_nest += 1;
376             }
377         } elsif (m/^\s*#endif/) {
378             if ($deprecated_conditional_nest >= 1) {
379                 $deprecated_conditional_nest -= 1;
380             }
381             if ($ignore_conditional_nest > 0) {
382                 $ignore_conditional_nest -= 1;
383             }
384         }
386         # If we find a line containing _DEPRECATED, we hope that this is
387         # attribute based deprecation and also treat this as a deprecation
388         # guard, unless it's a macro definition.
389         if ($deprecated_conditional_nest == 0 and m/_DEPRECATED/) {
390             unless (m/^\s*#\s*(if*|define)/ or $in_declaration eq "enum") {
391                 @TRACE@("Found deprecation annotation (decl: '$in_declaration'): $_");
392                 $deprecated_conditional_nest += 0.1;
393             }
394         }
396         # set global that is used later when we do AddSymbolToList
397         if ($deprecated_conditional_nest > 0) {
398             $deprecated = "<DEPRECATED/>\n";
399         } else {
400             $deprecated = "";
401         }
403         if($ignore_conditional_nest) {
404             next;
405         }
407         if (!$in_declaration) {
408             # Skip top-level comments.
409             if (s%^\s*/\*%%) {
410                 if (m%\*/%) {
411                     @TRACE@("Found one-line comment: $_");
412                 } else {
413                     $in_comment = 1;
414                     $doc_comment = $_;
415                     @TRACE@("Found start of comment: $_");
416                 }
417                 next;
418             }
420             @TRACE@("0: $_");
422             # MACROS
424             if (m/^\s*#\s*define\s+(\w+)/) {
425                 $symbol = $1;
426                 $decl = $_;
427                 # We assume all macros which start with '_' are private, but
428                 # we accept '_' itself which is the standard gettext macro.
429                 # We also try to skip the first macro if it looks like the
430                 # standard #ifndef HEADER_FILE #define HEADER_FILE etc.
431                 # And we only want TRUE & FALSE defined in GLib (libdefs.h in
432                 # libgnome also defines them if they are not already defined).
433                 if (($symbol !~ m/^_/
434                      && ($previous_line !~ m/#ifndef\s+$symbol/
435                          || $first_macro == 0)
436                      && (($symbol ne 'TRUE' && $symbol ne 'FALSE')
437                          || $MODULE eq 'glib'))
438                     || $symbol eq "_") {
439                     $in_declaration = "macro";
440                     @TRACE@("Macro: $symbol");
441                 } else {
442                     @TRACE@("skipping Macro: $symbol");
443                     $in_declaration = "macro";
444                     $internal = 1;
445                 }
446                 $first_macro = 0;
449             # TYPEDEF'D FUNCTIONS (i.e. user functions)
451             #                        $1                                $3            $4             $5
452             } elsif (m/^\s*typedef\s+((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/) {
453                 my $p3 = defined($3) ? $3 : "";
454                 $ret_type = "$1$p3 $4";
455                 $symbol = $5;
456                 $decl = $';
457                 $in_declaration = "user_function";
458                 @TRACE@("user function (1): $symbol, Returns: $ret_type");
460             #                                                       $1                                $3            $4             $5
461             } elsif (($previous_line =~ m/^\s*typedef\s*/) && m/^\s*((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/) {
462                 my $p3 = defined($3) ? $3 : "";
463                 $ret_type = "$1$p3 $4";
464                 $symbol = $5;
465                 $decl = $';
466                 $in_declaration = "user_function";
467                 @TRACE@("user function (2): $symbol, Returns: $ret_type");
469             #                                                       $1            $2
470             } elsif (($previous_line =~ m/^\s*typedef\s*/) && m/^\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/) {
471                 $ret_type = $1;
472                 $symbol = $2;
473                 $decl = $';
474                 #                                     $1                                $3
475                 if ($previous_line =~ m/^\s*typedef\s*((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*/) {
476                     my $p3 = defined($3) ? $3 : "";
477                     $ret_type = "$1$p3 ".$ret_type;
478                     $in_declaration = "user_function";
479                     @TRACE@("user function (3): $symbol, Returns: $ret_type");
481                 }
482             # FUNCTION POINTER VARIABLES
483             #                                                                     $1                                $3            $4             $5
484             } elsif (m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\s*)*((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/o) {
485                 my $p3 = defined($3) ? $3 : "";
486                 $ret_type = "$1$p3 $4";
487                 $symbol = $5;
488                 $decl = $';
489                 $in_declaration = "user_function";
490                 @TRACE@("function pointer variable: $symbol, Returns: $ret_type");
492             # ENUMS
494             } elsif (s/^\s*enum\s+_?(\w+)\s+\{/enum $1 {/) {
495                 # We assume that 'enum _<enum_name> {' is really the
496                 # declaration of enum <enum_name>.
497                 $symbol = $1;
498                 @TRACE@("plain enum: $symbol");
499                 $decl = $_;
500                 $in_declaration = "enum";
502             } elsif (m/^\s*typedef\s+enum\s+_?(\w+)\s+\1\s*;/) {
503                 # We skip 'typedef enum <enum_name> _<enum_name>;' as the enum will
504                 # be declared elsewhere.
505                 @TRACE@("skipping enum typedef: $1");
507             } elsif (m/^\s*typedef\s+enum/) {
508                 $symbol = "";
509                 @TRACE@("typedef enum: -");
510                 $decl = $_;
511                 $in_declaration = "enum";
514             # STRUCTS AND UNIONS
516             } elsif (m/^\s*typedef\s+(struct|union)\s+_(\w+)\s+\2\s*;/) {
517                 # We've found a 'typedef struct _<name> <name>;'
518                 # This could be an opaque data structure, so we output an
519                 # empty declaration. If the structure is actually found that
520                 # will override this.
521                 my $structsym = uc $1;
522                 @TRACE@("$structsym typedef: $2");
523                 $forward_decls{$2} = "<$structsym>\n<NAME>$2</NAME>\n$deprecated</$structsym>\n"
525             } elsif (m/^\s*(?:struct|union)\s+_(\w+)\s*;/) {
526                 # Skip private structs/unions.
527                 @TRACE@("private struct/union");
529             } elsif (m/^\s*(struct|union)\s+(\w+)\s*;/) {
530                 # Do a similar thing for normal structs as for typedefs above.
531                 # But we output the declaration as well in this case, so we
532                 # can differentiate it from a typedef.
533                 my $structsym = uc $1;
534                 @TRACE@("$structsym: $2");
535                 $forward_decls{$2} = "<$structsym>\n<NAME>$2</NAME>\n$_$deprecated</$structsym>\n";
537             } elsif (m/^\s*typedef\s+(struct|union)\s*\w*\s*{/) {
538                 $symbol = "";
539                 $decl = $_;
540                 $level = 0;
541                 $in_declaration = $1;
542                 @TRACE@("typedef struct/union $1");
544             # OTHER TYPEDEFS
546             } elsif (m/^\s*typedef\s+(?:struct|union)\s+\w+[\s\*]+(\w+)\s*;/) {
547                 @TRACE@("Found struct/union(*) typedef $1: $_");
548                 if (&AddSymbolToList (\$list, $1)) {
549                     print DECL "<TYPEDEF>\n<NAME>$1</NAME>\n$deprecated$_</TYPEDEF>\n";
550                 }
552             } elsif (m/^\s*(G_GNUC_EXTENSION\s+)?typedef\s+(.+[\s\*])(\w+)(\s*\[[^\]]+\])*\s*;/) {
553                 if ($2 !~ m/^struct\s/ && $2 !~ m/^union\s/) {
554                     @TRACE@("Found typedef: $_");
555                     if (&AddSymbolToList (\$list, $3)) {
556                         print DECL "<TYPEDEF>\n<NAME>$3</NAME>\n$deprecated$_</TYPEDEF>\n";
557                     }
558                 }
559             } elsif (m/^\s*typedef\s+/) {
560                 @TRACE@("Skipping typedef: $_");
563             # VARIABLES (extern'ed variables)
565             } elsif (m/^\s*(extern|[A-Za-z_]+VAR|${IGNORE_DECORATORS})\s+((const\s+|signed\s+|unsigned\s+|long\s+|short\s+)*\w+)(\s+\*+|\*+|\s)\s*(const\s+)*([A-Za-z]\w*)\s*;/o) {
566                 $symbol = $6;
567                 s/^\s*([A-Za-z_]+VAR)\b/extern/;
568                 $decl = $_;
569                 @TRACE@("Possible extern var $symbol: $decl");
570                 if (&AddSymbolToList (\$list, $symbol)) {
571                     print DECL "<VARIABLE>\n<NAME>$symbol</NAME>\n$deprecated$decl</VARIABLE>\n";
572                 }
575             # VARIABLES
577             } elsif (m/^\s*((const\s+|signed\s+|unsigned\s+|long\s+|short\s+)*\w+)(\s+\*+|\*+|\s)\s*(const\s+)*([A-Za-z]\w*)\s*\=/) {
578                 $symbol = $5;
579                 $decl = $_;
580                 @TRACE@("Possible global var $symbol: $decl");
581                 if (&AddSymbolToList (\$list, $symbol)) {
582                     print DECL "<VARIABLE>\n<NAME>$symbol</NAME>\n$deprecated$decl</VARIABLE>\n";
583                 }
585             # G_DECLARE_*
587             } elsif (m/.*G_DECLARE_(FINAL_TYPE|DERIVABLE_TYPE|INTERFACE)\s*\(/) {
588                 $in_declaration = "g-declare";
589                 $symbol = "G_DECLARE_$1";
590                 $decl = $';
592             # FUNCTIONS
594             # We assume that functions which start with '_' are private, so
595             # we skip them.
596             #                                                                     $1                                                                                                    $2                                                          $3
597             } elsif (m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\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) {
598                 $ret_type = $1;
599                 if (defined ($2)) { $ret_type .= " $2"; }
600                 $symbol = $3;
601                 $decl = $';
602                 @TRACE@("internal Function: $symbol, Returns: [$1][$2]");
603                 $in_declaration = "function";
604                 $internal = 1;
605                 if (m/^\s*G_INLINE_FUNC/) {
606                     @TRACE@("skip block after inline function");
607                     # now we we need to skip a whole { } block
608                     $skip_block = 1;
609                 }
611             #                                                                     $1                                                                                                    $2                                                          $3
612             } elsif (m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\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) {
613                 $ret_type = $1;
614                 if (defined ($2)) { $ret_type .= " $2"; }
615                 $symbol = $3;
616                 $decl = $';
617                 @TRACE@("Function (1): $symbol, Returns: [$1][$2]");
618                 $in_declaration = "function";
619                 if (m/^\s*G_INLINE_FUNC/) {
620                     @TRACE@("skip block after inline function");
621                     # now we we need to skip a whole { } block
622                     $skip_block = 1;
623                 }
625             # Try to catch function declarations which have the return type on
626             # the previous line. But we don't want to catch complete functions
627             # which have been declared G_INLINE_FUNC, e.g. g_bit_nth_lsf in
628             # glib, or 'static inline' functions.
629             } elsif (m/^\s*([A-Za-z]\w*)\s*\(/) {
630                 $symbol = $1;
631                 $decl = $';
633                 if ($previous_line !~ m/^\s*G_INLINE_FUNC/) {
634                     if ($previous_line !~ m/^\s*static\s+/) {
635                         #                                                                     $1                                                                                                   $2
636                         if ($previous_line =~ m/^\s*(?:\b(?:extern|${IGNORE_DECORATORS})\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) {
637                             $ret_type = $1;
638                             if (defined ($2)) { $ret_type .= " $2"; }
639                             @TRACE@("Function  (2): $symbol, Returns: $ret_type");
640                             $in_declaration = "function";
641                         }
642                     } else {
643                         @TRACE@("skip block after inline function");
644                         # now we we need to skip a whole { } block
645                         $skip_block = 1;
646                         #                                                                                  $1                                                                                                    $2
647                         if ($previous_line =~ m/^\s*(?:\b(?:extern|static|inline|${IGNORE_DECORATORS})\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) {
648                             $ret_type = $1;
649                             if (defined ($2)) { $ret_type .= " $2"; }
650                             @TRACE@("Function  (3): $symbol, Returns: $ret_type");
651                             $in_declaration = "function";
652                         }
653                     }
654                 }
655                 else {
656                     if ($previous_line !~ m/^\s*static\s+/) {
657                         @TRACE@("skip block after inline function");
658                         # now we we need to skip a whole { } block
659                         $skip_block = 1;
660                         #                                                                                  $1                                                                                                    $2
661                         if ($previous_line =~ m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\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) {
662                             $ret_type = $1;
663                             if (defined ($2)) { $ret_type .= " $2"; }
664                             @TRACE@("Function (4): $symbol, Returns: $ret_type");
665                             $in_declaration = "function";
666                         }
667                     }
668                 }
670             # Try to catch function declarations with the return type and name
671             # on the previous line(s), and the start of the parameters on this.
672             } elsif (m/^\s*\(/) {
673                 $decl = $';
674                 if ($previous_line =~ m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|enum\s+)*\w+)(\s+\*+|\*+|\s)\s*([A-Za-z]\w*)\s*$/o) {
675                     $ret_type = "$1 $2";
676                     $symbol = $3;
677                     @TRACE@("Function (5): $symbol, Returns: $ret_type");
678                     $in_declaration = "function";
680                 } elsif ($previous_line =~ m/^\s*\w+\s*$/
681                          && $pre_previous_line =~ m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\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) {
682                     $ret_type = $1;
683                     $ret_type =~ s/\s*\n//;
684                     $in_declaration = "function";
686                     $symbol = $previous_line;
687                     $symbol =~ s/^\s+//;
688                     $symbol =~ s/\s*\n//;
689                     @TRACE@("Function (6): $symbol, Returns: $ret_type");
690                 }
692             #} elsif (m/^extern\s+/) {
693                 #print "DEBUG: Skipping extern: $_";
696             # STRUCTS
698             } elsif (m/^\s*struct\s+_?(\w+)\s*\*/) {
699                 # Skip 'struct _<struct_name> *', since it could be a
700                 # return type on its own line.
702             } elsif (m/^\s*struct\s+_?(\w+)/) {
703                 # We assume that 'struct _<struct_name>' is really the
704                 # declaration of struct <struct_name>.
705                 $symbol = $1;
706                 $decl = $_;
707                  # we will find the correct level as below we do $level += tr/{//;
708                 $level = 0;
709                 $in_declaration = "struct";
710                 @TRACE@("Struct(_): $symbol");
713             # UNIONS
715             } elsif (m/^\s*union\s+_(\w+)\s*\*/) {
716                     # Skip 'union _<union_name> *' (see above)
717             } elsif (m/^\s*union\s+_(\w+)/) {
718                 $symbol = $1;
719                 $decl = $_;
720                 $level = 0;
721                 $in_declaration = "union";
722                 @TRACE@("Union(_): $symbol");
723             }
725         } else {
726             @TRACE@("1: [$skip_block] $_");
727             # If we were already in the middle of a declaration, we simply add
728             # the current line onto the end of it.
729             if ($skip_block == 0) {
730                 $decl .= $_;
731             } else {
732                 # Remove all nested pairs of curly braces.
733                 while ($_ =~ s/{[^{]*}//g) { }
734                 # Then hope at most one remains in the line...
735                 if (m%(.*?){%) {
736                     if ($skip_block == 1) {
737                         $decl .= $1;
738                     }
739                     $skip_block += 1;
740                 } elsif (m%}%) {
741                     $skip_block -= 1;
742                     if ($skip_block == 1) {
743                         # this is a hack to detect the end of declaration
744                         $decl .= ";";
745                         $skip_block = 0;
746                         @TRACE@("2: ---");
747                     }
748                 } else {
749                     if ($skip_block == 1) {
750                         $decl .= $_;
751                     }
752                 }
753             }
754         }
756         #if ($in_declaration ne '') {
757         #    print "$in_declaration = $decl\n";
758         #}
760         if ($in_declaration eq "g-declare") {
761             if ($decl =~ s/\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\).*$//) {
762                 my $ModuleObjName = $1;
763                 my $module_obj_name = $2;
764                 if ($REBUILD_TYPES) {
765                     push (@get_types, "${module_obj_name}_get_type");
766                 }
767                 $forward_decls{$ModuleObjName} = "<STRUCT>\n<NAME>$ModuleObjName</NAME>\n$deprecated</STRUCT>\n";
768                 if ($symbol =~ /^G_DECLARE_DERIVABLE/) {
769                     $forward_decls{"${ModuleObjName}Class"} = "<STRUCT>\n<NAME>${ModuleObjName}Class</NAME>\n$deprecated</STRUCT>\n";
770                 }
771                 if ($symbol =~ /^G_DECLARE_INTERFACE/) {
772                     $forward_decls{"${ModuleObjName}Interface"} = "<STRUCT>\n<NAME>${ModuleObjName}Interface</NAME>\n$deprecated</STRUCT>\n";
773                 }
774                 $in_declaration = "";
775             }
776         }
778         # Note that sometimes functions end in ') G_GNUC_PRINTF (2, 3);' or
779         # ') __attribute__ (...);'.
780         if ($in_declaration eq 'function') {
781             if ($decl =~ s/\)\s*(G_GNUC_.*|.*DEPRECATED.*|${IGNORE_DECORATORS}\s*|__attribute__\s*\(.*\)\s*)*;.*$//s) {
782                 if ($internal == 0) {
783                      $decl =~ s%/\*.*?\*/%%gs;        # remove comments.
784                      #$decl =~ s/^\s+//;                # remove leading whitespace.
785                      #$decl =~ s/\s+$//;                # remove trailing whitespace.
786                      $decl =~ s/\s*\n\s*/ /gs;        # consolidate whitespace at start
787                                                    # and end of lines.
788                      $ret_type =~ s%/\*.*?\*/%%g;        # remove comments in ret type.
789                      if (&AddSymbolToList (\$list, $symbol)) {
790                          print DECL "<FUNCTION>\n<NAME>$symbol</NAME>\n$deprecated<RETURNS>$ret_type</RETURNS>\n$decl\n</FUNCTION>\n";
791                          if ($REBUILD_TYPES) {
792                              # check if this looks like a get_type function and if so remember
793                              if (($symbol =~ m/_get_type$/) && ($ret_type =~ m/GType/) && ($decl =~ m/^(void|)$/)) {
794                                  @TRACE@("Adding get-type: [$ret_type] [$symbol] [$decl]\tfrom $input_file");
795                                  push (@get_types, $symbol);
796                              }
797                          }
798                      }
799                 } else {
800                      $internal = 0;
801                 }
802                 $deprecated_conditional_nest = int($deprecated_conditional_nest);
803                 $in_declaration = "";
804                 $skip_block = 0;
805             }
806         }
808         if ($in_declaration eq 'user_function') {
809             if ($decl =~ s/\).*$//) {
810                 if (&AddSymbolToList (\$list, $symbol)) {
811                     print DECL "<USER_FUNCTION>\n<NAME>$symbol</NAME>\n$deprecated<RETURNS>$ret_type</RETURNS>\n$decl</USER_FUNCTION>\n";
812                 }
813                 $deprecated_conditional_nest = int($deprecated_conditional_nest);
814                 $in_declaration = "";
815             }
816         }
818         if ($in_declaration eq 'macro') {
819             if ($decl !~ m/\\\s*$/) {
820                 if ($internal == 0) {
821                     if (&AddSymbolToList (\$list, $symbol)) {
822                         print DECL "<MACRO>\n<NAME>$symbol</NAME>\n$deprecated$decl</MACRO>\n";
823                     }
824                 } else {
825                     $internal = 0;
826                 }
827                 $deprecated_conditional_nest = int($deprecated_conditional_nest);
828                 $in_declaration = "";
829             }
830         }
832         if ($in_declaration eq 'enum') {
833             if ($decl =~ m/\}\s*(\w+)?;\s*$/) {
834                 if ($symbol eq "") {
835                     $symbol = $1;
836                 }
837                 if (&AddSymbolToList (\$list, $symbol)) {
838                     print DECL "<ENUM>\n<NAME>$symbol</NAME>\n$deprecated$decl</ENUM>\n";
839                 }
840                 $deprecated_conditional_nest = int($deprecated_conditional_nest);
841                 $in_declaration = "";
842             }
843         }
845         # We try to handle nested stucts/unions, but unmatched brackets in
846         # comments will cause problems.
847         if ($in_declaration eq 'struct' or $in_declaration eq 'union') {
848             if (($level <= 1) && ($decl =~ m/\n\}\s*(\w*);\s*$/)) {
849                 if ($symbol eq "") {
850                     $symbol = $1;
851                 }
853                 if ($symbol =~ m/^(\S+)(Class|Iface|Interface)\b/) {
854                     my $objectname = $1;
855                     @TRACE@("Found object: $1");
856                     $title = "<TITLE>$objectname</TITLE>\n";
857                     push (@objects, $objectname);
858                 }
859                 @TRACE@("Store struct: $symbol");
860                 if (&AddSymbolToList (\$list, $symbol)) {
861                     my $structsym = uc $in_declaration;
862                     print DECL "<$structsym>\n<NAME>$symbol</NAME>\n$deprecated$decl</$structsym>\n";
863                     if (defined($forward_decls{$symbol})) {
864                         undef($forward_decls{$symbol});
865                     }
866                 }
867                 $deprecated_conditional_nest = int($deprecated_conditional_nest);
868                 $in_declaration = "";
869             } else {
870                 # We use tr to count the brackets in the line, and adjust
871                 # $level accordingly.
872                 $level += tr/{//;
873                 $level -= tr/}//;
874                 @TRACE@("struct/union level : $level");
875             }
876         }
878         $pre_previous_line = $previous_line;
879         $previous_line = $_;
880     }
881     close(INPUT);
883     # print remaining forward declarations
884     foreach $symbol (sort(keys %forward_decls)) {
885         if (defined($forward_decls{$symbol})) {
886             &AddSymbolToList (\$list, $symbol);
887             print DECL $forward_decls{$symbol};
888         }
889     }
891     # add title
892     $list = "$title$list";
893     
894     @TRACE@("Scanning $input_file done\n");
895     
896     # Try to separate the standard macros and functions, placing them at the
897     # end of the current section, in a subsection named 'Standard'.
898     # do this in a loop to catch object, enums and flags
899     my ($class,$lclass,$prefix,$lprefix);
900     my ($standard_decl) = "";
901     do {
902         if ($list =~ m/^(\S+)_IS_(\S*)_CLASS\n/m) {
903             $prefix = $1;
904             $lprefix = lc($prefix);
905             $class = $2;
906             $lclass = lc($class);
907             @TRACE@("Found gobject type '${prefix}_$class' from is_class macro\n");
908         } elsif ($list =~ m/^(\S+)_IS_(\S*)\n/m) {
909             $prefix = $1;
910             $lprefix = lc($prefix);
911             $class = $2;
912             $lclass = lc($class);
913             @TRACE@("Found gobject type '${prefix}_$class' from is_ macro\n");
914         } elsif ($list =~ m/^(\S+?)_(\S*)_get_type\n/m) {
915             $lprefix = $1;
916             $prefix = uc($lprefix);
917             $lclass = $2;
918             $class = uc($lclass);
919             @TRACE@("Found gobject type '${prefix}_$class' from get_type function\n");
920         } else {
921           $class = $lclass = "";
922         }
923     
924         if ($class ne "") {
925             my ($cclass) = $lclass;
926             $cclass =~ s/_//g;
927             my ($type) = $lprefix.$cclass;
928             
929             if ($list =~ s/^${type}Private\n//im)               { $standard_decl .= $&; }
930             
931             # We only leave XxYy* in the normal section if they have docs 
932             if (! defined($doc_comments{$type})) {
933               @TRACE@("  Hide instance docs for $type");
934               if ($list =~ s/^${type}\n//im)                    { $standard_decl .= $&; }
935             }
936             if (! defined($doc_comments{$type."class"})) {
937               @TRACE@("  Hide class docs for $type");
938               if ($list =~ s/^${type}Class\n//im)               { $standard_decl .= $&; }
939             }
940             if (! defined($doc_comments{$type."interface"})) {
941               @TRACE@("  Hide iface docs for $type");
942               if ($list =~ s/^$type}Interface\n//im)            { $standard_decl .= $&; }
943             }
944             if (! defined($doc_comments{$type."iface"})) {
945               @TRACE@("  Hide iface docs for $type");
946               if ($list =~ s/${type}Iface\n//im)                { $standard_decl .= $&; }
947             }
948             
949             while ($list =~ s/^\S+_IS_$class\n//m)              { $standard_decl .= $&; }
950             while ($list =~ s/^\S+_TYPE_$class\n//m)            { $standard_decl .= $&; }
951             while ($list =~ s/^\S+_${lclass}_get_type\n//m)     { $standard_decl .= $&; }
952             while ($list =~ s/^\S+_${class}_CLASS\n//m)         { $standard_decl .= $&; }
953             while ($list =~ s/^\S+_IS_${class}_CLASS\n//m)      { $standard_decl .= $&; }
954             while ($list =~ s/^\S+_${class}_GET_CLASS\n//m)     { $standard_decl .= $&; }
955             while ($list =~ s/^\S+_${class}_GET_IFACE\n//m)     { $standard_decl .= $&; }
956             while ($list =~ s/^\S+_${class}_GET_INTERFACE\n//m) { $standard_decl .= $&; }
957     
958             # We do this one last, otherwise it tends to be caught by the IS_$class macro
959             while ($list =~ s/^\S+_$class\n//m)                 { $standard_decl .= $&; }
960             
961             @TRACE@("Decl '".join(",",split("\n",$list))."'\n");
962             @TRACE@("Std  '".join(",",split("\n",$standard_decl))."'\n");
963         }
964     } while ($class ne "");
965     if ($standard_decl ne "") {
966       # sort the symbols
967       $standard_decl=join("\n",sort(split("\n",$standard_decl)))."\n";
968       $list .= "<SUBSECTION Standard>\n$standard_decl";
969     }
970     if ($list ne "") {
971         $$section_list{$file_basename} .= "<SECTION>\n<FILE>$file_basename</FILE>\n$list</SECTION>\n\n";
972     }
976 #############################################################################
977 # Function    : AddSymbolToList
978 # Description : This adds the symbol to the list of declarations, but only if
979 #                it is not already in the list.
980 # Arguments   : $list - reference to the list of symbols, one on each line.
981 #                $symbol - the symbol to add to the list.
982 #############################################################################
984 sub AddSymbolToList {
985     my ($list, $symbol) = @_;
987     if ($$list =~ m/\b\Q$symbol\E\b/) {
988          #print "Symbol $symbol already in list. skipping\n";
989          # we return 0 to skip outputting another entry to -decl.txt
990          # this is to avoid redeclarations (e.g. in conditional
991          # sections).
992         return 0;
993     }
994     $$list .= "$symbol\n";
995     return 1;