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