source: trunk/third/gtk-doc/gtkdoc-mktmpl.in @ 20745

Revision 20745, 42.5 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20744, which included commits to RCS files with non-trunk default branches.
  • Property svn:executable set to *
RevLine 
[20744]1#!@PERL@ -w
2# -*- cperl -*-
3#
4# gtk-doc - GTK DocBook documentation generator.
5# Copyright (C) 1998  Damon Chaplin
6#
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.
11#
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.
16#
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.
20#
21
22#############################################################################
23# Script      : gtkdoc-mktmpl
24# Description : This creates or updates the template files which contain the
25#               manually-edited documentation. (A 'template' is a simple text
26#               form which is filled in with the description of a function,
27#               macro, enum, or struct. For functions and macros it also
28#               contains fields for describing the parameters.)
29#
30#               This script reads in the existing templates, found in
31#               tmpl/*.sgml, moves these files to tmpl/*.sgml.bak, and then
32#               recreates the .sgml files according to the structure given in
33#               the file $MODULE-sections.txt.
34#
35#               Any new templates added, or new function parameters, are
36#               marked with 'FIXME' so you can do a grep to see which parts
37#               need updating.
38#
39#               Any templates which are no longer used (i.e. they are remove
40#               from $MODULE-sections.txt) are placed in the file
41#               tmpl/$MODULE-unused.txt. If they are included again later
42#               they are automatically copied back into position.
43#               If you are certain that these templates will never be used
44#               again you can delete them from $MODULE-unused.txt.
45#
46#               Any parameters to functions which are no longer used are
47#               separated from the rest of the parameters with the line
48#               '<!-- # Unused Parameters # -->'. It may be that the parameter
49#               name has just been changed, in which case you can copy the
50#               description to the parameter with the new name. You can delete
51#               the unused parameter descriptions when no longer needed.
52#############################################################################
53
54use strict;
55use Getopt::Long;
56
57unshift @INC, "@PACKAGE_DATA_DIR@";
58require "gtkdoc-common.pl";
59
60# Options
61
62# name of documentation module
63my $MODULE;
64my $TMPL_DIR;
65my $FLAG_CHANGES;
66my $PRINT_VERSION;
67my $PRINT_HELP;
68
69my %optctl = (module => \$MODULE,
70              'flag-changes' => \$FLAG_CHANGES,
71              'output-dir' => \$TMPL_DIR,
72              'version' => \$PRINT_VERSION,
73              'help' => \$PRINT_HELP);
74GetOptions(\%optctl, "module=s", "flag-changes!", "output-dir:s", "version", "help");
75
76if ($PRINT_VERSION) {
77    print "@VERSION@\n";
78    exit 0;
79}
80
81if (!$MODULE) {
82    $PRINT_HELP = 1;
83}
84
85if ($PRINT_HELP) {
86    print "gtkdoc-mktmpl version @VERSION@\n";
87    print "\n--module=MODULE_NAME Name of the doc module being parsed";
88    print "\n--flag-changes       If specified, changes in templates are flagged";
89    print "\n--output-dir=DIRNAME The directory where the results are stored";
90    print "\n--version            Print the version of this program";
91    print "\n--help               Print this help\n";
92    exit 0;
93}
94
95my $ROOT_DIR = ".";
96
97# The directory containing the template files.
98$TMPL_DIR = $TMPL_DIR ? $TMPL_DIR : "$ROOT_DIR/tmpl";
99
100# This file contains the object hierarchy.
101my $OBJECT_TREE_FILE = "$ROOT_DIR/$MODULE.hierarchy";
102
103# The file containing signal handler prototype information.
104my $SIGNALS_FILE = "$ROOT_DIR/$MODULE.signals";
105
106# The file containing Arg information.
107my $ARGS_FILE = "$ROOT_DIR/$MODULE.args";
108
109# Set the flag to indicate changes, if requested.
110my $CHANGES_FLAG = $FLAG_CHANGES ? "FIXME" : "";
111
112# These global arrays store information on signals. Each signal has an entry
113# in each of these arrays at the same index, like a multi-dimensional array.
114my @SignalObjects;      # The GtkObject which emits the signal.
115my @SignalNames;        # The signal name.
116my @SignalReturns;      # The return type.
117my @SignalPrototypes;   # The rest of the prototype of the signal handler.
118
119# These global arrays store information on Args. Each Arg has an entry
120# in each of these arrays at the same index, like a multi-dimensional array.
121my @ArgObjects;         # The GtkObject which has the Arg.
122my @ArgNames;           # The Arg name.
123my @ArgTypes;           # The Arg type - gint, GtkArrowType etc.
124my @ArgFlags;           # How the Arg can be used - readable/writable etc.
125
126# These global hashes store declaration info keyed on a symbol name.
127my %Declarations;
128my %DeclarationTypes;
129my %DeclarationConditional;
130my %DeclarationOutput;
131
132# These global hashes store the existing documentation.
133my %SymbolDocs;
134my %SymbolTypes;
135my %SymbolParams;
136
137# These global arrays store GtkObject and subclasses and the hierarchy.
138my @Objects;
139my @ObjectLevels;
140
141&ReadSignalsFile ($SIGNALS_FILE);
142&ReadArgsFile ($ARGS_FILE);
143&ReadObjectHierarchy;
144
145&ReadDeclarationsFile ("$ROOT_DIR/$MODULE-decl.txt", 0);
146if (-f "$ROOT_DIR/$MODULE-overrides.txt") {
147    &ReadDeclarationsFile ("$ROOT_DIR/$MODULE-overrides.txt", 1);
148}
149&ReadExistingTemplates;
150
151my $changed = 0;
152
153if (&UpdateTemplates ("$ROOT_DIR/$MODULE-sections.txt")) {
154  $changed = 1;
155}
156&OutputUnusedTemplates;
157if (&CheckAllDeclarationsOutput) {
158  $changed = 1;
159}
160
161if ($changed || ! -e "$ROOT_DIR/tmpl.stamp") {
162    open (TIMESTAMP, ">$ROOT_DIR/tmpl.stamp")
163        || die "Can't create $ROOT_DIR/tmpl.stamp";
164    print (TIMESTAMP "timestamp");
165    close (TIMESTAMP);
166}
167
168#############################################################################
169# Function    : ReadExistingTemplates
170# Description : This reads in all the existing documentation, into the global
171#               variables %SymbolDocs, %SymbolTypes, and %SymbolParams (a
172#               hash of arrays).
173# Arguments   : none
174#############################################################################
175
176sub ReadExistingTemplates {
177    %SymbolDocs = ();
178    %SymbolTypes = ();
179    %SymbolParams = ();
180
181    # Read the unused docs first, so they get overridden by any real docs.
182    # (though this shouldn't happen often).
183    my $unused_doc = "$TMPL_DIR/$MODULE-unused.sgml";
184    if (-e $unused_doc) {
185        &ReadTemplateFile ($unused_doc, 0);
186    }
187
188    while (<$TMPL_DIR/*.sgml>) {
189#       print "Reading $_\n";
190        if ($_ eq $unused_doc) {
191#           print "skipping $unused_doc\n";
192        } else {
193            &ReadTemplateFile ($_, 0);
194        }
195    }
196}
197
198
199#############################################################################
200# Function    : UpdateTemplates
201# Description : This collects the output for each section of the docs, and
202#               outputs each file when the end of the section is found.
203# Arguments   : $file - the file containing the sections of the docs.
204#############################################################################
205
206sub UpdateTemplates {
207    my ($file) = @_;
208#    print "Reading: $file\n";
209
210    open (INPUT, $file)
211        || die "Can't open $file";
212
213    # Create the top output directory if it doesn't exist.
214    if (! -e $TMPL_DIR) {
215        mkdir ("$TMPL_DIR", 0777)
216            || die "Can't create directory: $TMPL_DIR";
217    }
218
219    my $title = "";
220    my $subsection = "";
221    my $output;
222    my $changed = 0;
223    while (<INPUT>) {
224        if (m/^#/) {
225            next;
226
227        } elsif (m/^<SECTION>/) {
228            $output = "";
229
230        } elsif (m/^<SUBSECTION\s*(.*)>/i) {
231            $subsection = $1;
232            next;
233
234        } elsif (m/^<TITLE>(.*)<\/TITLE>/) {
235            $title = $1;
236#           print "Section: $title\n";
237
238        } elsif (m/^<FILE>(.*)<\/FILE>/) {
239            $file = $1;
240
241        } elsif (m/^<INCLUDE>(.*)<\/INCLUDE>/) {
242            next;
243
244        } elsif (m/^<\/SECTION>/) {
245            if ($title eq "") {
246                $title = $file;
247            }
248#           print "End of section: $title\n";
249
250            $file =~ s/\s/_/g;
251            $file .= ".sgml";
252
253            if (&OutputTemplateFile ($file, $title, \$output)) {
254              $changed = 1;
255            }
256
257            $title = "";
258            $subsection = "";
259
260        } elsif (m/^(\S+)/) {
261            my $symbol = $1;
262#           print "  Symbol: $symbol\n";
263
264            my $declaration = $Declarations{$1};
265            if (defined ($declaration)) {
266                # We don't want templates for standard macros/functions of
267                # GtkObjects or private declarations.
268                if ($subsection ne "Standard" && $subsection ne "Private") {
269                    $output .= &OutputDeclaration ($DeclarationTypes {$symbol},
270                                                   $symbol, $declaration);
271
272                    $output .= &OutputSignalTemplates ($symbol);
273                    $output .= &OutputArgTemplates ($symbol);
274                }
275
276                # Note that the declaration has been output.
277                $DeclarationOutput{$symbol} = 1;
278
279                if ($declaration eq '##conditional##') {
280#                   print "Conditional $DeclarationTypes{$symbol}\n";
281                }
282
283            } else {
284                print "WARNING: No declaration for: $1\n";
285            }
286        }
287    }
288    close (INPUT);
289
290    return $changed;
291}
292
293
294#############################################################################
295# Function    : CheckAllDeclarationsOutput
296# Description : This steps through all the declarations that were loaded, and
297#               makes sure that each one has been output, by checking the
298#               corresponding flag in the %DeclarationOutput hash. It is
299#               intended to check that any new declarations in new versions
300#               of GTK/Gnome get added to the $MODULE-sections.txt file.
301# Arguments   : none
302#############################################################################
303
304sub CheckAllDeclarationsOutput {
305    my $num_unused = 0;
306
307    my $old_unused_file = "$ROOT_DIR/$MODULE-unused.txt";
308    my $new_unused_file = "$ROOT_DIR/$MODULE-unused.new";
309
310    open (UNUSED, ">$new_unused_file")
311        || die "Can't open $new_unused_file";
312    my ($symbol);
313    foreach $symbol (keys (%Declarations)) {
314        if (!defined ($DeclarationOutput{$symbol})) {
315            print (UNUSED "$symbol\n");
316            $num_unused++;
317        }
318    }
319    close (UNUSED);
320    if ($num_unused != 0) {
321        print <<EOF;
322=============================================================================
323WARNING: $num_unused unused declarations.
324  These can be found in $MODULE-unused.txt.
325  They should be added to $MODULE-sections.txt in the appropriate place.
326=============================================================================
327EOF
328    }
329
330    return &UpdateFileIfChanged ($old_unused_file, $new_unused_file, 0);
331}
332
333
334#############################################################################
335# Function    : OutputDeclaration
336# Description : This returns the template for one symbol & declaration.
337#               Note that it uses the global %SymbolDocs and %SymbolParams to
338#               lookup any existing documentation.
339# Arguments   : $type - the type of the symbol ('FUNCTION'/'MACRO' etc.)
340#               $symbol - the symbol name.
341#               $declaration - the declaration of the symbol.
342#############################################################################
343
344sub OutputDeclaration {
345    my ($type, $symbol, $declaration) = @_;
346    my ($output) = "";
347
348#    print "Outputting $type: $symbol\n";
349
350    # See if symbol already has a description.
351    my ($symbol_desc) = $SymbolDocs{$symbol};
352    my ($template_exists);
353    if (defined ($symbol_desc)) {
354        $template_exists = 1;
355        $symbol_desc =~ s/\s+$//;
356    } else {
357        $template_exists = 0;
358        $symbol_desc = "<para>\n$CHANGES_FLAG\n</para>";
359    }
360
361    $output .= <<EOF;
362<!-- ##### $type $symbol ##### -->
363$symbol_desc
364
365EOF
366
367    # For functions, function typedefs and macros, we output the arguments.
368    # For functions and function typedefs we also output the return value.
369    if ($type eq "FUNCTION" || $type eq "USER_FUNCTION") {
370        # Take out the return type
371        $declaration =~ s/<RETURNS>\s*(const\s+|G_CONST_RETURN\s+|unsigned\s+)*(\w+)\s*(\**)\s*<\/RETURNS>\n//;
372        my ($ret_type) = $2;
373
374        my ($param_num) = 0;
375        my ($name);
376        while ($declaration ne "") {
377            if ($declaration =~ s/^[\s,]+//) {
378                # skip whitespace and commas
379                next;
380
381            } elsif ($declaration =~ s/^void\s*[,\n]//) {
382                if ($param_num != 0) {
383                    print "WARNING: void used as parameter in function $symbol\n";
384                }
385               
386            } elsif ($declaration =~ s/^...\s*[,\n]//) {
387                $output .= &OutputParam ($symbol, "Varargs",
388                                         $template_exists, 1, "");
389
390                # Try to match a standard parameter.
391            } elsif ($declaration =~ s/^(const\s+|G_CONST_RETURN\s+|unsigned\s+)*(struct\s+)?((?:long\s+|short\s+)?\w+)\s*(\**)\s*(const\s+)?(\**)?\s*(\w+)?\s*((?:\[\S*\])*)\s*[,\n]//) {
392                if (defined ($7)) {
393                    $name = $7;
394                } else {
395                    $name = "Param" . ($param_num + 1);
396                }
397                $output .= &OutputParam ($symbol, $name, $template_exists, 1,
398                                         "");
399
400                # Try to match parameters which are functions.
401            } elsif ($declaration =~ s/^(const\s+|G_CONST_RETURN\s+|unsigned\s+)*(struct\s+)?(\w+)\s*(\**)\s*(const\s+)?\(\s*\*\s*(\w+)\s*\)\s*\(([^)]*)\)\s*[,\n]//) {
402                $name = $6;
403                $output .= &OutputParam ($symbol, $name, $template_exists, 1,
404                                         "");
405
406            } else {
407                print "###Can't parse args for function $symbol: $declaration\n";
408                last;
409            }
410            $param_num++;
411        }
412
413   
414        if ($ret_type ne "void") {
415            $output .= &OutputParam ($symbol, "Returns", $template_exists, 1,
416                                     "");
417        }
418        $output .= &OutputParam ($symbol, "Deprecated", $template_exists, 0, "");
419        $output .= &OutputParam ($symbol, "Since", $template_exists, 0, "");
420        $output .= &OutputOldParams ($symbol);
421        $output .= "\n";
422    }
423
424    if ($type eq "MACRO") {
425        if ($declaration =~ m/^\s*#\s*define\s+\w+\(([^\)]*)\)/) {
426            my ($param);
427            foreach $param (split (/,/, $1)) {
428                $param =~ s/^\s+//;
429                $param =~ s/\s*$//;
430                if ($param =~ m/\S/) {
431                    $output .= &OutputParam ($symbol, $param, $template_exists,
432                                             1, "");
433                }
434            }
435        }
436        $output .= &OutputParam ($symbol, "Returns", $template_exists, 0, "");
437        $output .= &OutputParam ($symbol, "Deprecated", $template_exists, 0, "");
438        $output .= &OutputParam ($symbol, "Since", $template_exists, 0, "");
439        $output .= &OutputOldParams ($symbol);
440        $output .= "\n";
441    }
442
443    if ($type eq "STRUCT") {
444        my $is_object_struct = CheckIsObject ($symbol);
445        my @fields = ParseStructDeclaration($declaration, $is_object_struct);
446
447        for (my $i = 0; $i <= $#fields; $i += 2) {
448            my $field_name = $fields[$i];
449            $output .= &OutputParam ($symbol, $field_name, $template_exists, 1, "");
450        }
451        $output .= &OutputParam ($symbol, "Deprecated", $template_exists, 0, "");
452        $output .= &OutputParam ($symbol, "Since", $template_exists, 0, "");
453    }
454
455    if ($type eq "ENUM") {
456        my @members = ParseEnumDeclaration($declaration);
457
458        for my $member (@members) {
459            $output .= &OutputParam ($symbol, $member, $template_exists, 1, "");
460        }
461        $output .= &OutputParam ($symbol, "Deprecated", $template_exists, 0, "");
462        $output .= &OutputParam ($symbol, "Since", $template_exists, 0, "");
463    }
464
465    $output .= "\n";
466
467    # Remove the used docs from the hashes.
468    if ($template_exists) {
469        delete $SymbolDocs{$symbol};
470        delete $SymbolParams{$symbol};
471    }
472
473    return $output;
474}
475
476
477#############################################################################
478# Function    : OutputParam
479# Description : This outputs the part of a template for one parameter.
480#               It first checks if the parameter is already described, and if
481#               so it uses that description, and clears it so it isn't output
482#               as an old param.
483# Arguments   : $symbol - the symbol (function or macro) name.
484#               $param_to_output - the parameter to add.
485#               $template_exists - TRUE if the template already existed in
486#                 template files. If it did, then we will flag any changes
487#                 with 'FIXME'.
488#               $force_output - TRUE if the parameter should be output even
489#                 if it didn't already exist in the template. (The return
490#                 values of macros are added manually if required, and so we
491#                 never add it here - we only copy it if it already exists.)
492#               $default_description - the default description of the
493#                 parameter to be used if it doesn't already exist. (Signal
494#                 handlers have a few common parameters.)
495#############################################################################
496
497sub OutputParam {
498    my ($symbol, $param_to_output, $template_exists,
499        $force_output, $default_description) = @_;
500    my ($j);
501
502    my ($params) = $SymbolParams{$symbol};
503    if (defined ($params)) {
504        for ($j = 0; $j <= $#$params; $j += 2) {
505            my $param_name = $$params[$j];
506            my $param_desc = $$params[$j + 1];
507
508            if ($param_name eq $param_to_output) {
509                $param_desc =~ s/\s+$//;
510                $$params[$j] = "";
511                $$params[$j + 1] = "";
512                return "\@$param_name: $param_desc\n";
513            }
514        }
515    }
516
517    # If the template was already in a file, flag the new parameter.
518    # If not, the template itself will be flagged, so we don't need to flag
519    # all the new parameters as well.
520    if ($force_output) {
521        if ($default_description ne "") {
522            $default_description =~ s/\s+$//;
523            return "\@$param_to_output: $default_description\n";
524        } else {
525            if ($template_exists) {
526                return "\@$param_to_output: $CHANGES_FLAG\n";
527            } else {
528                return "\@$param_to_output: \n";
529            }
530        }
531    }
532    return "";
533}
534
535
536#############################################################################
537# Function    : OutputOldParams
538# Description : This returns all the existing documentation for parameters of
539#               the given function/macro/signal symbol which are unused, with
540#               a comment before them.
541# Arguments   : $symbol - the symbol (function/macro/signal) name.
542#############################################################################
543
544sub OutputOldParams {
545    my ($symbol) = @_;
546    my $output = "";
547
548    my ($params) = $SymbolParams{$symbol};
549    if (defined ($params)) {
550        my $j;
551        for ($j = 0; $j <= $#$params; $j += 2) {
552            my $param_name = $$params[$j];
553            my $param_desc = $$params[$j + 1];
554
555            if ($param_name ne "") {
556                $param_desc =~ s/\s+$//;
557                $output .= "\@$param_name: $param_desc\n";
558            }
559        }
560    }
561    if ($output) {
562        $output = "<!-- # Unused Parameters # -->\n" . $output;
563    }
564    return $output;
565}
566
567
568#############################################################################
569# Function    : OutputTemplateFile
570# Description : This outputs one template file.
571# Arguments   : $file - the basename of the file to output.
572#               $title - the title from the $MODULE-sections.txt file. This
573#                 will be overridden by any title given in the template file.
574#               $output - reference to the templates to output.
575#############################################################################
576
577sub OutputTemplateFile {
578    my ($file, $title, $output) = @_;
579
580    my ($short_desc, $long_desc, $see_also);
581
582    if (defined ($SymbolDocs{"$TMPL_DIR/$file:Title"})) {
583        $title = $SymbolDocs{"$TMPL_DIR/$file:Title"};
584        delete $SymbolDocs{"$TMPL_DIR/$file:Title"};
585    }
586    if (defined ($SymbolDocs{"$TMPL_DIR/$file:Short_Description"})) {
587        $short_desc = $SymbolDocs{"$TMPL_DIR/$file:Short_Description"};
588        delete $SymbolDocs{"$TMPL_DIR/$file:Short_Description"};
589    } else {
590        $short_desc = "";
591    }
592    if (defined ($SymbolDocs{"$TMPL_DIR/$file:Long_Description"})) {
593        $long_desc = $SymbolDocs{"$TMPL_DIR/$file:Long_Description"};
594        delete $SymbolDocs{"$TMPL_DIR/$file:Long_Description"};
595    } else {
596        $long_desc = "<para>\n\n</para>\n";
597    }
598    if (defined ($SymbolDocs{"$TMPL_DIR/$file:See_Also"})) {
599        $see_also = $SymbolDocs{"$TMPL_DIR/$file:See_Also"};
600        delete $SymbolDocs{"$TMPL_DIR/$file:See_Also"};
601    } else {
602        $see_also = "<para>\n\n</para>\n";
603    }
604
605    my $old_tmpl_file = "$TMPL_DIR/$file";
606    my $new_tmpl_file = "$TMPL_DIR/$file.new";
607
608    open (OUTPUT, ">$new_tmpl_file")
609        || die "Can't create $new_tmpl_file";
610
611    print (OUTPUT <<EOF);
612<!-- ##### SECTION Title ##### -->
613$title
614
615<!-- ##### SECTION Short_Description ##### -->
616$short_desc
617
618<!-- ##### SECTION Long_Description ##### -->
619$long_desc
620
621<!-- ##### SECTION See_Also ##### -->
622$see_also
623
624EOF
625
626    print (OUTPUT $$output);
627    close (OUTPUT);
628
629    return &UpdateFileIfChanged ($old_tmpl_file, $new_tmpl_file, 1);
630}
631
632
633#############################################################################
634# Function    : OutputSignalTemplates
635# Description : Outputs templates for signal handlers.
636# Arguments   : $title - the title from the $MODULE-sections.txt file. If the
637#                 file is describing a GtkObject subclass, the title should
638#                 be the name of the class, e.g. 'GtkButton'.
639#############################################################################
640
641sub OutputSignalTemplates {
642    my ($title) = @_;
643
644    my $output = "";
645    my ($i, $template_exists);
646    for ($i = 0; $i <= $#SignalObjects; $i++) {
647        if ($SignalObjects[$i] eq $title) {
648#           print "Found signal: $SignalObjects[$i]\n";
649            my ($symbol) = "$SignalObjects[$i]::$SignalNames[$i]";
650
651            # See if symbol already has a description.
652            my ($symbol_desc) = $SymbolDocs{$symbol};
653            if (defined ($symbol_desc)) {
654                $template_exists = 1;
655                $symbol_desc =~ s/\s+$//;
656                delete $SymbolDocs{$symbol};
657            } else {
658                $template_exists = 0;
659                $symbol_desc = "<para>\n$CHANGES_FLAG\n</para>";
660            }
661
662            $output .= <<EOF;
663<!-- ##### SIGNAL $symbol ##### -->
664$symbol_desc
665
666EOF
667            my $sourceparams = $SymbolParams{$symbol};
668            my @params = split ("[,\n]", $SignalPrototypes[$i]);
669            my ($j, $name);
670            for ($j = 0; $j <= $#params; $j++) {
671                my $param = $params[$j];
672                $param =~ s/^\s+//;
673                $param =~ s/\s*$//;
674                if ($param =~ m/^\s*$/) { next; }
675                if ($param =~ m/^void$/) { next; }
676
677                if ($param =~ m/^\s*(\w+)\s*(\**)\s*([\w\[\]]+)?\s*$/) {
678                    if (defined($sourceparams)) {
679                        $name = $$sourceparams[2 * $j];
680                    }
681                    elsif (defined($3)) {
682                        $name = $3;
683                    } else {
684                        $name = "Param" . ($j + 1);
685                    }
686                    if ($j == 0) {
687                        $output .= &OutputParam ($symbol, $name,
688                                                 $template_exists, 1,
689                                                 "the object which received the signal.");
690                    } else {
691                        $output .= &OutputParam ($symbol, $name,
692                                                 $template_exists, 1, "");
693                    }
694                }       
695            }
696           
697            if ($SignalReturns[$i] ne "void") {
698                $output .= &OutputParam ($symbol, "Returns", $template_exists,
699                                         1, "");
700            }
701            $output .= &OutputOldParams ($symbol);
702            $output .= "\n";
703        }
704    }
705    return $output;
706}
707
708
709#############################################################################
710# Function    : OutputArgTemplates
711# Description : Outputs templates for Args.
712# Arguments   : $title - the title from the $MODULE-sections.txt file. If the
713#                 file is describing a GtkObject subclass, the title should
714#                 be the name of the class, e.g. 'GtkButton'.
715#############################################################################
716
717sub OutputArgTemplates {
718    my ($title) = @_;
719
720    my $output = "";
721    my $i;
722    for ($i = 0; $i <= $#ArgObjects; $i++) {
723        if ($ArgObjects[$i] eq $title) {
724#           print "Found arg: $ArgObjects[$i]\n";
725            # I've only used one colon so we don't clash with signals.
726            my ($symbol) = "$ArgObjects[$i]:$ArgNames[$i]";
727
728            # See if symbol already has a description.
729            my ($symbol_desc) = $SymbolDocs{$symbol};
730            if (defined ($symbol_desc)) {
731                delete $SymbolDocs{$symbol};
732                $symbol_desc =~ s/\s+$//;
733            } else {
734                $symbol_desc = "<para>\n$CHANGES_FLAG\n</para>";
735            }
736
737            $output .= <<EOF;
738<!-- ##### ARG $symbol ##### -->
739$symbol_desc
740
741EOF
742        }
743    }
744    return $output;
745}
746
747
748#############################################################################
749# Function    : OutputUnusedTemplates
750# Description : This saves any unused documentation into $MODULE-unused.sgml.
751# Arguments   : none
752#############################################################################
753
754sub OutputUnusedTemplates {
755    my ($old_unused_file) = "$TMPL_DIR/$MODULE-unused.sgml";
756    my ($new_unused_file) = "$TMPL_DIR/$MODULE-unused.new";
757
758    open (UNUSED, ">$new_unused_file")
759        || die "Can't open file: $new_unused_file";
760
761    my $output = "";
762    my ($symbol, $symbol_desc);
763    for $symbol (sort keys %SymbolDocs) {
764        $symbol_desc = $SymbolDocs{$symbol};
765
766#       print "Unused: $symbol\n";
767
768        my $type = $SymbolTypes{$symbol};
769        if (!defined ($type)) {
770            $type = "UNKNOWN";
771            print "WARNING: Unused symbol $symbol has unknown type\n";
772        }
773
774    $output .= <<EOF;
775<!-- ##### $type $symbol ##### -->
776$symbol_desc
777
778EOF
779
780        my ($params) = $SymbolParams{$symbol};
781        if (defined ($params)) {
782            my $j;
783            for ($j = 0; $j <= $#$params; $j += 2) {
784                my $param_name = $$params[$j];
785                my $param_desc = $$params[$j + 1];
786                $param_desc =~ s/\s+$//;
787                $output .= "\@$param_name: $param_desc\n";
788            }
789        }
790        $output .= "\n";
791    }
792
793    print UNUSED $output;
794    close (UNUSED);
795
796    &UpdateFileIfChanged ($old_unused_file, $new_unused_file, 1);
797}
798
799
800#############################################################################
801# LIBRARY FUNCTIONS -   These functions are used in both gtkdoc-mkdb and
802#                       gtkdoc-mktmpl and should eventually be moved to a
803#                       separate library.
804#############################################################################
805
806#############################################################################
807# Function    : ReadDeclarationsFile
808# Description : This reads in a file containing the function/macro/enum etc.
809#               declarations.
810#               
811#               Note that in some cases there are several declarations with
812#               the same name, e.g. for conditional macros. In this case we
813#               set a flag in the %DeclarationConditional hash so the
814#               declaration is not shown in the docs.
815#
816#               If a macro and a function have the same name, e.g. for
817#               gtk_object_ref, the function declaration takes precedence.
818#
819#               Some opaque structs are just declared with 'typedef struct
820#               _name name;' in which case the declaration may be empty.
821#               The structure may have been found later in the header, so
822#               that overrides the empty declaration.
823#               
824# Arguments   : $file - the declarations file to read
825#               $override - if declarations in this file should override
826#                       any current declaration.
827#############################################################################
828
829sub ReadDeclarationsFile {
830    my ($file, $override) = @_;
831
832    if ($override == 0) {
833        %Declarations = ();
834        %DeclarationTypes = ();
835        %DeclarationConditional = ();
836        %DeclarationOutput = ();
837    }
838
839    open (INPUT, $file)
840        || die "Can't open $file";
841    my $declaration_type = "";
842    my $declaration_name;
843    my $declaration;
844    while (<INPUT>) {
845        if (!$declaration_type) {
846            if (m/^<([^>]+)>/) {
847                $declaration_type = $1;
848                $declaration_name = "";
849#               print "Found declaration: $declaration_type\n";
850                $declaration = "";
851            }
852        } else {
853            if (m%^<NAME>(.*)</NAME>%) {
854                $declaration_name = $1;
855            } elsif (m%<DEPRECATED/>%) {
856                # do nothing, just skip the line; we handle this
857                # in mkdb
858            } elsif (m%^</$declaration_type>%) {
859#               print "Found end of declaration: $declaration_name\n";
860                # Check that the declaration has a name
861                if ($declaration_name eq "") {
862                    print "ERROR: $declaration_type has no name $file:$.\n";
863                }
864
865                # Check if the symbol is already defined.
866                if (defined ($Declarations{$declaration_name})
867                    && $override == 0) {
868                    # Function declarations take precedence.
869                    if ($DeclarationTypes{$declaration_name} eq 'FUNCTION') {
870                        # Ignore it.
871                    } elsif ($declaration_type eq 'FUNCTION') {
872                        $Declarations{$declaration_name} = $declaration;
873                        $DeclarationTypes{$declaration_name} = $declaration_type;
874                    } elsif ($DeclarationTypes{$declaration_name}
875                              eq $declaration_type) {
876                        # If the existing declaration is empty override it.
877                        if ($declaration_type eq 'STRUCT') {
878                            if ($Declarations{$declaration_name} =~ m/^\s*$/) {
879                                $Declarations{$declaration_name} = $declaration;
880                            } elsif ($declaration =~ m/^\s*$/) {
881                                # Ignore an empty declaration.
882                            } else {
883                                print "WARNING: Structure has multiple definitions: $declaration_name\n";
884                            }
885
886                        } else {
887                            # set flag in %DeclarationConditional hash for
888                            # multiply defined macros/typedefs.
889                            $DeclarationConditional{$declaration_name} = 1;
890                        }
891                    } else {
892                        print "WARNING: $declaration_name has multiple definitions\n";
893                    }
894                } else {
895                    $Declarations{$declaration_name} = $declaration;
896                    $DeclarationTypes{$declaration_name} = $declaration_type;
897                }
898                $declaration_type = "";
899            } else {
900                $declaration .= $_;
901            }
902        }
903    }
904    close (INPUT);
905}
906
907
908#############################################################################
909# Function    : ReadSignalsFile
910# Description : This reads in an existing file which contains information on
911#               all GTK signals. It creates the arrays @SignalNames and
912#               @SignalPrototypes containing info on the signals. The first
913#               line of the SignalPrototype is the return type of the signal
914#               handler. The remaining lines are the parameters passed to it.
915#               The last parameter, "gpointer user_data" is always the same
916#               so is not included.
917# Arguments   : $file - the file containing the signal handler prototype
918#                       information.
919#############################################################################
920
921sub ReadSignalsFile {
922    my ($file) = @_;
923
924    my $in_signal = 0;
925    my $signal_object;
926    my $signal_name;
927    my $signal_returns;
928    my $signal_prototype;
929
930    # Reset the signal info.
931    @SignalObjects = ();
932    @SignalNames = ();
933    @SignalReturns = ();
934    @SignalPrototypes = ();
935
936    if (! -f $file) {
937        return;
938    }
939    if (!open (INPUT, $file)) {
940        warn "Can't open $file - skipping signals\n";
941        return;
942    }
943    while (<INPUT>) {
944        if (!$in_signal) {
945            if (m/^<SIGNAL>/) {
946                $in_signal = 1;
947                $signal_object = "";
948                $signal_name = "";
949                $signal_returns = "";
950                $signal_prototype = "";
951            }
952        } else {
953            if (m/^<NAME>(.*)<\/NAME>/) {
954                $signal_name = $1;
955                if ($signal_name =~ m/^(.*)::(.*)$/) {
956                    $signal_object = $1;
957                    ($signal_name = $2) =~ s/_/-/g;
958#                   print "Found signal: $signal_name\n";
959                } else {
960                    print "Invalid signal name: $signal_name\n";
961                }
962            } elsif (m/^<RETURNS>(.*)<\/RETURNS>/) {
963                $signal_returns = $1;
964            } elsif (m%^</SIGNAL>%) {
965#               print "Found end of signal: ${signal_object}::${signal_name}\nReturns: ${signal_returns}\n${signal_prototype}";
966                push (@SignalObjects, $signal_object);
967                push (@SignalNames, $signal_name);
968                push (@SignalReturns, $signal_returns);
969                push (@SignalPrototypes, $signal_prototype);
970                $in_signal = 0;
971            } else {
972                $signal_prototype .= $_;
973            }
974        }
975    }
976    close (INPUT);
977}
978
979
980#############################################################################
981# Function    : ReadTemplateFile
982# Description : This reads in the manually-edited documentation file
983#               corresponding to the file currently being created, so we can
984#               insert the documentation at the appropriate places.
985#               It outputs %SymbolTypes, %SymbolDocs and %SymbolParams, which
986#               is a hash of arrays.
987#               NOTE: This function is duplicated in gtkdoc-mkdb (but
988#               slightly different).
989# Arguments   : $docsfile - the template file to read in.
990#               $skip_unused_params - 1 if the unused parameters should be
991#                       skipped.
992#############################################################################
993
994sub ReadTemplateFile {
995    my ($docsfile, $skip_unused_params) = @_;
996
997#    print "Reading $docsfile\n";
998    if (! -f $docsfile) {
999        print "File doesn't exist: $docsfile\n";
1000        return;
1001    }
1002
1003    my $CurrentType = "";       # Type of symbol being read.
1004    my $CurrentSymbol = "";     # Name of symbol being read.
1005    my $SymbolDoc = "";         # Description of symbol being read.
1006    my @Params;                 # Parameter names and descriptions of current
1007                                #   function/macro/function typedef.
1008    my $CurrentParam = -1;      # Index of parameter currently being read.
1009                                #   Note that the param array contains pairs
1010                                #   of param name & description.
1011    my $InUnusedParameters = 0; # True if we are reading in the unused params.
1012
1013    open (DOCS, $docsfile)
1014        || die "Can't open file $docsfile: $!";
1015    while (<DOCS>) {
1016        if (m/^<!-- ##### ([A-Z_]+) (\S+) ##### -->/) {
1017            my $type = $1;
1018            my $symbol = $2;
1019            if ($symbol eq "Title"
1020                || $symbol eq "Short_Description"
1021                || $symbol eq "Long_Description"
1022                || $symbol eq "See_Also") {
1023                $symbol = $docsfile . ":" . $symbol;
1024#               print "Found symbol: $symbol\n";
1025            }
1026
1027            # Canonicalize signal and argument names to have -, not _
1028            if ($type eq "ARG" || $type eq "SIGNAL") {
1029              $symbol =~ s/_/-/g;
1030            }
1031
1032            # Store previous symbol, but remove any trailing blank lines.
1033            if ($CurrentSymbol ne "") {
1034                $SymbolDoc =~ s/\s+$//;
1035                $SymbolTypes{$CurrentSymbol} = $CurrentType;
1036                $SymbolDocs{$CurrentSymbol} = $SymbolDoc;
1037                if ($CurrentParam >= 0) {
1038                    $SymbolParams{$CurrentSymbol} = [ @Params ];
1039                } else {
1040                    # Delete any existing params in case we are overriding a
1041                    # previously read template.
1042                    delete $SymbolParams{$CurrentSymbol};
1043                }
1044            }
1045            $CurrentType = $type;
1046            $CurrentSymbol = $symbol;
1047            $CurrentParam = -1;
1048            $InUnusedParameters = 0;
1049            $SymbolDoc = "";
1050            @Params = ();
1051
1052        } elsif (m/^<!-- # Unused Parameters # -->/) {
1053            $InUnusedParameters = 1;
1054            next;
1055
1056        } else {
1057            # Check if param found
1058            if (s/^\@(\S+):\040?//) {
1059                my $param_name = $1;
1060                # Allow variations of 'Returns'
1061                if ($param_name =~ m/^[Rr]eturns?$/) {
1062                    $param_name = "Returns";
1063                }
1064#               print "Found param: $param_name\n";
1065                push (@Params, $param_name);
1066                push (@Params, $_);
1067                $CurrentParam += 2;
1068                next;
1069            }
1070
1071            # When outputting the DocBook we skip unused parameters.
1072            if (!$InUnusedParameters || !$skip_unused_params) {
1073                if ($CurrentParam >= 0) {
1074                    $Params[$CurrentParam] .= $_;
1075                } else {
1076                    $SymbolDoc .= $_;
1077                }
1078            }
1079        }
1080    }
1081
1082    # Remember to finish the current symbol doccs.
1083    if ($CurrentSymbol ne "") {
1084        $SymbolDoc =~ s/\s+$//;
1085        $SymbolTypes{$CurrentSymbol} = $CurrentType;
1086        $SymbolDocs{$CurrentSymbol} = $SymbolDoc;
1087        if ($CurrentParam >= 0) {
1088            $SymbolParams{$CurrentSymbol} = [ @Params ];
1089        } else {
1090            delete $SymbolParams{$CurrentSymbol};
1091        }
1092    }
1093
1094    close (DOCS);
1095}
1096
1097
1098#############################################################################
1099# Function    : ReadObjectHierarchy
1100# Description : This reads in the $MODULE-hierarchy.txt file containing all
1101#               the GtkObject subclasses described in this module (and their
1102#               ancestors).
1103#               It places them in the @Objects array, and places their level
1104#               in the widget hierarchy in the @ObjectLevels array, at the
1105#               same index. GtkObject, the root object, has a level of 1.
1106#   
1107#               FIXME: the version in gtkdoc-mkdb also generates tree_index.sgml
1108#               as it goes along, this should be split out into a separate
1109#               function.
1110#
1111# Arguments   : none
1112#############################################################################
1113
1114sub ReadObjectHierarchy {
1115    @Objects = ();
1116    @ObjectLevels = ();
1117
1118    if (! -f $OBJECT_TREE_FILE) {
1119        return;
1120    }
1121    if (!open (INPUT, $OBJECT_TREE_FILE)) {
1122        warn "Can't open $OBJECT_TREE_FILE - skipping object tree\n";
1123        return;
1124    }
1125    while (<INPUT>) {
1126        if (m/\S+/) {
1127            my $object = $&;
1128            my $level = (length($`)) / 2 + 1;
1129#            print ("Level: $level  Object: $object\n");
1130
1131            push (@Objects, $object);
1132            push (@ObjectLevels, $level);
1133        }
1134    }
1135
1136    close (INPUT);
1137}
1138
1139
1140#############################################################################
1141# Function    : ReadArgsFile
1142# Description : This reads in an existing file which contains information on
1143#               all GTK args. It creates the arrays @ArgObjects, @ArgNames,
1144#               @ArgTypes and @ArgFlags containing info on the args.
1145# Arguments   : $file - the file containing the arg information.
1146#############################################################################
1147
1148sub ReadArgsFile {
1149    my ($file) = @_;
1150
1151    my $in_arg = 0;
1152    my $arg_object;
1153    my $arg_name;
1154    my $arg_type;
1155    my $arg_flags;
1156
1157    # Reset the signal info.
1158    @ArgObjects = ();
1159    @ArgNames = ();
1160    @ArgTypes = ();
1161    @ArgFlags = ();
1162
1163    if (! -f $file) {
1164        return;
1165    }
1166    if (!open (INPUT, $file)) {
1167        warn "Can't open $file - skipping args\n";
1168        return;
1169    }
1170    while (<INPUT>) {
1171        if (!$in_arg) {
1172            if (m/^<ARG>/) {
1173                $in_arg = 1;
1174                $arg_object = "";
1175                $arg_name = "";
1176                $arg_type = "";
1177                $arg_flags = "";
1178            }
1179        } else {
1180            if (m/^<NAME>(.*)<\/NAME>/) {
1181                $arg_name = $1;
1182                if ($arg_name =~ m/^(.*)::(.*)$/) {
1183                    $arg_object = $1;
1184                    ($arg_name = $2) =~ s/_/-/g;
1185#                   print "Found arg: $arg_name\n";
1186                } else {
1187                    print "Invalid arg name: $arg_name\n";
1188                }
1189            } elsif (m/^<TYPE>(.*)<\/TYPE>/) {
1190                $arg_type = $1;
1191            } elsif (m/^<FLAGS>(.*)<\/FLAGS>/) {
1192                $arg_flags = $1;
1193            } elsif (m%^</ARG>%) {
1194#               print "Found end of arg: ${arg_object}::${arg_name}\n${arg_type} : ${arg_flags}\n";
1195                push (@ArgObjects, $arg_object);
1196                push (@ArgNames, $arg_name);
1197                push (@ArgTypes, $arg_type);
1198                push (@ArgFlags, $arg_flags);
1199                $in_arg = 0;
1200            }
1201        }
1202    }
1203    close (INPUT);
1204}
1205
1206
1207#############################################################################
1208# Function    : CheckIsObject
1209# Description : Returns 1 if the given name is a GtkObject or a subclass.
1210#               It uses the global @Objects array.
1211#               Note that the @Objects array only contains classes in the
1212#               current module and their ancestors - not all GTK classes.
1213# Arguments   : $name - the name to check.
1214#############################################################################
1215
1216sub CheckIsObject {
1217    my ($name) = @_;
1218
1219    my $object;
1220    foreach $object (@Objects) {
1221        if ($object eq $name) {
1222            return 1;
1223        }
1224    }
1225    return 0;
1226}
1227
1228
1229#############################################################################
1230# Function    : ParseStructDeclaration
1231# Description : This function takes a structure declaration and
1232#               breaks it into individual type declarations.
1233# Arguments   : $declaration - the declaration to parse
1234#               $is_object - true if this is an object structure
1235#               $typefunc - function reference to apply to type
1236#               $namefunc - function reference to apply to name
1237#############################################################################
1238
1239sub ParseStructDeclaration {
1240    my ($declaration, $is_object, $typefunc, $namefunc) = @_;
1241
1242    # Remove all private parts of the declaration
1243
1244    # For objects, assume private
1245    if ($is_object) {
1246        $declaration =~ s!(struct\s+\w*\s*\{)
1247                          .*?
1248                          (?:/\*\s*<\s*public\s*>\s*\*/|(?=\}))!$1!msgx;
1249    }
1250   
1251    # Assume end of declaration if line begins with '}'
1252    $declaration =~ s!\n?[ \t]*/\*\s*<\s*(private|protected)\s*>\s*\*/
1253                      .*?
1254                      (?:/\*\s*<\s*public\s*>\s*\*/|(?=^\}))!!msgx;
1255   
1256    # Remove all other comments;
1257    $declaration =~ s@/\*([^*]+|\*(?!/))*\*/@ @g;
1258
1259    my @result = ();
1260
1261    if ($declaration =~ /^\s*$/) {
1262        return @result;
1263    }
1264
1265    # Prime match after "struct {" declaration
1266    if (!scalar($declaration =~ m/struct\s+\w*\s*\{/msg)) {
1267        die "Structure declaration '$declaration' does not begin with struct [NAME] {\n";
1268    }
1269
1270    # Treat lines in sequence, allowing singly nested anonymous structs
1271    # and unions.
1272    while ($declaration =~ m/\s*([^{;]+(\{[^\}]*\}[^{;]+)?);/msg) {
1273        my $line = $1;
1274       
1275        last if $line =~ /^\s*\}\s*\w*\s*$/;
1276
1277        # FIXME: Just ignore nested structs and unions for now
1278        next if $line =~ /{/;
1279
1280        # FIXME: The regexes here are the same as in OutputFunction;
1281        #        this functionality should be separated out.
1282
1283        if ($line =~ m/^
1284            (const\s+|unsigned\s+|volatile\s+)*(struct\s+)? # mod1
1285            (\w+)\s*                            # type
1286            (\**)\s*                            # ptr1
1287            (const\s+)?                         # mod2
1288            (\**)?\s*                           # ptr2
1289            (\w+(?:\s*,\s*\w+)*)\s*             # name
1290            (?:((?:\[[^\]]*\]\s*)+) |           # array
1291               (:\s*\d+))?\s*                   # bits
1292                       $/x) {
1293            my $mod1 = defined($1) ? $1 : "";
1294            if (defined($2)) { $mod1 .= $2; }
1295            my $type = $3;
1296            my $ptr1 = $4;
1297            my $mod2 = defined($5) ? $5 : "";
1298            my $ptr2 = $6;
1299            my $name = $7;
1300            $ptr1 = " " . $ptr1;
1301            my $array = defined($8) ? $8 : "";
1302            my $bits =  defined($9) ? " $9" : "";
1303            my $ptype = defined $typefunc ? $typefunc->($type) : $type;
1304           
1305            # FIXME:
1306            # As a hack, we allow the "name" to be of the form
1307            # "a, b, c". This isn't the correct C syntax, but
1308            # at least we get "gint16 x, y" right. Such constructs
1309            # should really be completely removed from the source.
1310            # Or we should really try to understand the C syntax
1311            # here...
1312           
1313            my @names = split /\s*,\s*/, $name;
1314            for my $n (@names) {
1315                push @result, $n;
1316                if (defined $namefunc) {
1317                    $n = $namefunc->($n);
1318                }
1319                push @result, "$mod1$ptype$ptr1$mod2$ptr2$n$array$bits";
1320            }
1321           
1322        # Try to match structure members which are functions
1323        } elsif ($line =~ m/^
1324                 (const\s+|G_CONST_RETURN\s+|unsigned\s+)*(struct\s+)?  # mod1
1325                 (\w+)\s*                                               # type
1326                 (\**)\s*                                               # ptr1
1327                 (const\s+)?                                            # mod2
1328                 \(\s*\*\s*(\w+)\s*\)\s*                                # name
1329                 \(([^)]*)\)\s*                                         # func_params
1330                            $/x) {
1331
1332            my $mod1 = defined($1) ? $1 : "";
1333            if (defined($2)) { $mod1 .= $2; }
1334            my $type = $3;
1335            my $ptr1 = $4;
1336            my $mod2 = defined($5) ? $5 : "";
1337            my $name = $6;
1338            my $func_params = $7;
1339            my $ptype = defined $typefunc ? $typefunc->($type) : $type;
1340            my $pname = defined $namefunc ? $namefunc->($name) : $name;
1341           
1342            push @result, $name;
1343            push @result, "$mod1$ptype$ptr1$mod2 (*$pname) ($func_params)";
1344           
1345        } else {
1346            warn "Cannot parse structure field \"$line\"";
1347        }
1348    }
1349   
1350    return @result;
1351}
1352
1353
1354#############################################################################
1355# Function    : ParseEnumDeclaration
1356# Description : This function takes a enumeration declaration and
1357#               breaks it into individual enum member declarations.
1358# Arguments   : $declaration - the declaration to parse
1359#############################################################################
1360
1361sub ParseEnumDeclaration {
1362    my ($declaration, $is_object) = @_;
1363
1364    # Remove comments;
1365    $declaration =~ s@/\*([^*]+|\*(?!/))*\*/@ @g;
1366
1367    my @result = ();
1368
1369    if ($declaration =~ /^\s*$/) {
1370        return @result;
1371    }
1372
1373    # Remove parenthesized expressions (in macros like GTK_BLAH = BLAH(1,3))
1374    # to avoid getting confused by commas they might contain. This
1375    # doesn't handle nested parentheses correctly.
1376
1377    $declaration =~ s/\([^)]*\)//g;
1378
1379    # Remove comma from comma - possible whitespace - closing brace sequence
1380    # since it is legal in GNU C and C99 to have a trailing comma but doesn't
1381    # result in an actual enum member
1382
1383    $declaration =~ s/,(\s*})/$1/g;
1384
1385    # Prime match after "typedef enum {" declaration
1386    if (!scalar($declaration =~ m/typedef\s+enum\s*\{/msg)) {
1387        die "Enum declaration '$declaration' does not begin with typedef enum {\n";
1388    }
1389
1390    # Treat lines in sequence.
1391    while ($declaration =~ m/\s*([^,\}]+)([,\}])/msg) {
1392        my $line = $1;
1393        my $terminator = $2;
1394
1395        if ($line =~ m/^(\w+)\s*(=.*)?$/msg) {
1396            push @result, $1;
1397           
1398        # Special case for GIOCondition, where the values are specified by
1399        # macros which expand to include the equal sign like '=1'.
1400        } elsif ($line =~ m/^(\w+)\s*GLIB_SYSDEF_POLL/msg) {
1401            push @result, $1;
1402           
1403        # Special case include of <gdk/gdkcursors.h>, just ignore it
1404        } elsif ($line =~ m/^#include/) {
1405            last;
1406
1407        } else {
1408            warn "Cannot parse enumeration member \"$line\"";
1409        }
1410
1411        last if $terminator eq '}';
1412    }
1413   
1414    return @result;
1415}
Note: See TracBrowser for help on using the repository browser.