Don't die when encountering #if/#endif in enums. Fixes #324535.
[gtk-doc.git] / gtkdoc-mktmpl.in
blob9a8e7d65558bba350ddc3d2c437765b6fbd77a82
1 #!@PERL@ -w
2 # -*- cperl -*-
4 # gtk-doc - GTK DocBook documentation generator.
5 # Copyright (C) 1998  Damon Chaplin
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #############################################################################
23 # Script      : gtkdoc-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.)
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.
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.
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.
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 #############################################################################
54 use strict;
55 use Getopt::Long;
57 unshift @INC, '@PACKAGE_DATA_DIR@';
58 require "gtkdoc-common.pl";
60 # Options
62 # name of documentation module
63 my $MODULE;
64 my $TMPL_DIR;
65 my $FLAG_CHANGES;
66 my $PRINT_VERSION;
67 my $PRINT_HELP;
68 my $ONLY_SECTION_TMPL;
70 my %optctl = (module => \$MODULE,
71               'flag-changes' => \$FLAG_CHANGES,
72               'output-dir' => \$TMPL_DIR,
73               'only-section-tmpl' => \$ONLY_SECTION_TMPL,
74               'version' => \$PRINT_VERSION,
75               'help' => \$PRINT_HELP);
76 GetOptions(\%optctl, "module=s", "flag-changes!", "output-dir:s", "only-section-tmpl!", "version", "help");
78 if ($PRINT_VERSION) {
79     print "@VERSION@\n";
80     exit 0;
83 if (!$MODULE) {
84     $PRINT_HELP = 1;
87 if ($PRINT_HELP) {
88     print "gtkdoc-mktmpl version @VERSION@\n";
89     print "\n--module=MODULE_NAME Name of the doc module being parsed";
90     print "\n--flag-changes       If specified, changes in templates are flagged";
91     print "\n--output-dir=DIRNAME The directory where the results are stored";
92     print "\n--only-section-tmpl  Only include section information in templates";
93     print "\n--version            Print the version of this program";
94     print "\n--help               Print this help\n";
95     exit 0;
98 my $ROOT_DIR = ".";
100 # The directory containing the template files.
101 $TMPL_DIR = $TMPL_DIR ? $TMPL_DIR : "$ROOT_DIR/tmpl";
103 # This file contains the object hierarchy.
104 my $OBJECT_TREE_FILE = "$ROOT_DIR/$MODULE.hierarchy";
106 # The file containing signal handler prototype information.
107 my $SIGNALS_FILE = "$ROOT_DIR/$MODULE.signals";
109 # The file containing Arg information.
110 my $ARGS_FILE = "$ROOT_DIR/$MODULE.args";
112 # Set the flag to indicate changes, if requested.
113 my $CHANGES_FLAG = $FLAG_CHANGES ? "FIXME" : "";
115 # These global arrays store information on signals. Each signal has an entry
116 # in each of these arrays at the same index, like a multi-dimensional array.
117 my @SignalObjects;      # The GtkObject which emits the signal.
118 my @SignalNames;        # The signal name.
119 my @SignalReturns;      # The return type.
120 my @SignalFlags;        # Flags for the signal
121 my @SignalPrototypes;   # The rest of the prototype of the signal handler.
123 # These global arrays store information on Args. Each Arg has an entry
124 # in each of these arrays at the same index, like a multi-dimensional array.
125 my @ArgObjects;         # The GtkObject which has the Arg.
126 my @ArgNames;           # The Arg name.
127 my @ArgTypes;           # The Arg type - gint, GtkArrowType etc.
128 my @ArgFlags;           # How the Arg can be used - readable/writable etc.
130 # These global hashes store declaration info keyed on a symbol name.
131 my %Declarations;
132 my %DeclarationTypes;
133 my %DeclarationConditional;
134 my %DeclarationOutput;
136 # These global hashes store the existing documentation.
137 my %SymbolDocs;
138 my %SymbolTypes;
139 my %SymbolParams;
141 # These global arrays store GtkObject and subclasses and the hierarchy.
142 my @Objects;
143 my @ObjectLevels;
145 &ReadSignalsFile ($SIGNALS_FILE);
146 &ReadArgsFile ($ARGS_FILE);
147 &ReadObjectHierarchy;
149 &ReadDeclarationsFile ("$ROOT_DIR/$MODULE-decl.txt", 0);
150 if (-f "$ROOT_DIR/$MODULE-overrides.txt") {
151     &ReadDeclarationsFile ("$ROOT_DIR/$MODULE-overrides.txt", 1);
153 &ReadExistingTemplates;
155 my $changed = 0;
157 if (&UpdateTemplates ("$ROOT_DIR/$MODULE-sections.txt")) {
158   $changed = 1;
160 &OutputUnusedTemplates;
161 if (&CheckAllDeclarationsOutput) {
162   $changed = 1;
165 if ($changed || ! -e "$ROOT_DIR/tmpl.stamp") {
166     open (TIMESTAMP, ">$ROOT_DIR/tmpl.stamp")
167         || die "Can't create $ROOT_DIR/tmpl.stamp";
168     print (TIMESTAMP "timestamp");
169     close (TIMESTAMP);
172 #############################################################################
173 # Function    : ReadExistingTemplates
174 # Description : This reads in all the existing documentation, into the global
175 #               variables %SymbolDocs, %SymbolTypes, and %SymbolParams (a
176 #               hash of arrays).
177 # Arguments   : none
178 #############################################################################
180 sub ReadExistingTemplates {
181     %SymbolDocs = ();
182     %SymbolTypes = ();
183     %SymbolParams = ();
185     # Read the unused docs first, so they get overridden by any real docs.
186     # (though this shouldn't happen often).
187     my $unused_doc = "$TMPL_DIR/$MODULE-unused.sgml";
188     if (-e $unused_doc) {
189         &ReadTemplateFile ($unused_doc, 0);
190     }
192     while (<$TMPL_DIR/*.sgml>) {
193 #       print "Reading $_\n";
194         if ($_ eq $unused_doc) {
195 #           print "skipping $unused_doc\n";
196         } else {
197             &ReadTemplateFile ($_, 0);
198         }
199     }
203 #############################################################################
204 # Function    : UpdateTemplates
205 # Description : This collects the output for each section of the docs, and
206 #               outputs each file when the end of the section is found.
207 # Arguments   : $file - the file containing the sections of the docs.
208 #############################################################################
210 sub UpdateTemplates {
211     my ($file) = @_;
212 #    print "Reading: $file\n";
214     open (INPUT, $file)
215         || die "Can't open $file";
217     # Create the top output directory if it doesn't exist.
218     if (! -e $TMPL_DIR) {
219         mkdir ("$TMPL_DIR", 0777)
220             || die "Can't create directory: $TMPL_DIR";
221     }
223     my $title = "";
224     my $subsection = "";
225     my $output;
226     my $changed = 0;
227     while (<INPUT>) {
228         if (m/^#/) {
229             next;
231         } elsif (m/^<SECTION>/) {
232             $output = "";
234         } elsif (m/^<SUBSECTION\s*(.*)>/i) {
235             $subsection = $1;
236             next;
238         } elsif (m/^<TITLE>(.*)<\/TITLE>/) {
239             $title = $1;
240 #           print "Section: $title\n";
242         } elsif (m/^<FILE>(.*)<\/FILE>/) {
243             $file = $1;
245         } elsif (m/^<INCLUDE>(.*)<\/INCLUDE>/) {
246             next;
248         } elsif (m/^<\/SECTION>/) {
249             if ($title eq "") {
250                 $title = $file;
251             }
252 #           print "End of section: $title\n";
254             $file =~ s/\s/_/g;
255             $file .= ".sgml";
257             if (&OutputTemplateFile ($file, $title, \$output)) {
258               $changed = 1;
259             }
261             $title = "";
262             $subsection = "";
264         } elsif (m/^(\S+)/) {
265             my $symbol = $1;
266 #           print "  Symbol: $symbol\n";
268             my $declaration = $Declarations{$1};
269             if (defined ($declaration)) {
270                 # We don't want templates for standard macros/functions of
271                 # GtkObjects or private declarations.
272                 if ($subsection ne "Standard" && $subsection ne "Private") {
273                     $output .= &OutputDeclaration ($DeclarationTypes {$symbol},
274                                                    $symbol, $declaration);
276                     $output .= &OutputSignalTemplates ($symbol);
277                     $output .= &OutputArgTemplates ($symbol);
278                 }
280                 # Note that the declaration has been output.
281                 $DeclarationOutput{$symbol} = 1;
283                 if ($declaration eq '##conditional##') {
284 #                   print "Conditional $DeclarationTypes{$symbol}\n";
285                 }
287             } else {
288                 print "WARNING: No declaration found for: $1\n";
289             }
290         }
291     }
292     close (INPUT);
294     return $changed;
298 #############################################################################
299 # Function    : CheckAllDeclarationsOutput
300 # Description : This steps through all the declarations that were loaded, and
301 #               makes sure that each one has been output, by checking the
302 #               corresponding flag in the %DeclarationOutput hash. It is
303 #               intended to check that any new declarations in new versions
304 #               of GTK/Gnome get added to the $MODULE-sections.txt file.
305 # Arguments   : none
306 #############################################################################
308 sub CheckAllDeclarationsOutput {
309     my $num_unused = 0;
311     my $old_unused_file = "$ROOT_DIR/$MODULE-unused.txt";
312     my $new_unused_file = "$ROOT_DIR/$MODULE-unused.new";
314     open (UNUSED, ">$new_unused_file")
315         || die "Can't open $new_unused_file";
316     my ($symbol);
317     foreach $symbol (sort keys (%Declarations)) {
318         if (!defined ($DeclarationOutput{$symbol})) {
319             print (UNUSED "$symbol\n");
320             $num_unused++;
321         }
322     }
323     close (UNUSED);
324     if ($num_unused != 0) {
325         print <<EOF;
326 =============================================================================
327 WARNING: $num_unused unused declarations.
328   These can be found in $MODULE-unused.txt.
329   They should be added to $MODULE-sections.txt in the appropriate place.
330 =============================================================================
332     }
334     return &UpdateFileIfChanged ($old_unused_file, $new_unused_file, 0);
338 #############################################################################
339 # Function    : OutputDeclaration
340 # Description : This returns the template for one symbol & declaration.
341 #               Note that it uses the global %SymbolDocs and %SymbolParams to
342 #               lookup any existing documentation.
343 # Arguments   : $type - the type of the symbol ('FUNCTION'/'MACRO' etc.)
344 #               $symbol - the symbol name.
345 #               $declaration - the declaration of the symbol.
346 #############################################################################
348 sub OutputDeclaration {
349     my ($type, $symbol, $declaration) = @_;
350     my ($output) = "";
352 #    print "Outputting $type: $symbol\n";
354     # See if symbol already has a description.
355     my ($symbol_desc) = $SymbolDocs{$symbol};
356     my ($template_exists);
357     if (defined ($symbol_desc)) {
358         $template_exists = 1;
359         $symbol_desc =~ s/\s+$//;
360     } else {
361         $template_exists = 0;
362         $symbol_desc = "<para>\n$CHANGES_FLAG\n</para>";
363     }
365     $output .= <<EOF;
366 <!-- ##### $type $symbol ##### -->
367 $symbol_desc
371     # For functions, function typedefs and macros, we output the arguments.
372     # For functions and function typedefs we also output the return value.
373     if ($type eq "FUNCTION" || $type eq "USER_FUNCTION") {
374         # Take out the return type
375         $declaration =~ s/<RETURNS>\s*((const\s+|G_CONST_RETURN\s+|unsigned\s+|struct\s+|enum\s+)*)(\w+)\s*(\**\s*(const|G_CONST_RETURN)?\s*\**\s*(restrict)?\s*)<\/RETURNS>\n//;
376         my $ret_type_modifier = defined($1) ? $1 : "";
377         my $ret_type = $3;
378         my $ret_type_pointer = $4;
380         my ($param_num) = 0;
381         my ($name);
382         while ($declaration ne "") {
383             if ($declaration =~ s/^[\s,]+//) {
384                 # skip whitespace and commas
385                 next;
387             } elsif ($declaration =~ s/^void\s*[,\n]//) {
388                 if ($param_num != 0) {
389                     print "WARNING: void used as parameter in function $symbol\n";
390                 }
392             } elsif ($declaration =~ s/^...\s*[,\n]//) {
393                 $output .= &OutputParam ($symbol, "Varargs",
394                                          $template_exists, 1, "");
396             # Try to match a standard parameter (keep in sync with gtkdoc-mkdb)
397             #                                $1                                                                                                                                    $2                             $3                                                           $4       $5
398             } elsif ($declaration =~ s/^\s*((?:G_CONST_RETURN|G_GNUC_UNUSED|unsigned long|unsigned short|signed long|signed short|unsigned|signed|long|short|volatile|const)\s+)*((?:struct\b|enum\b)?\s*\w+)\s*((?:(?:const|restrict)?\s*\*?\s*(?:const\b|restrict\b)?\s*)*)(\w+)?\s*((?:\[\S*\])*)\s*[,\n]//) {
399                 my $pre         = defined($1) ? $1 : "";
400                 my $type        = $2;
401                 my $ptr         = defined($3) ? $3 : "";
402                 my $name        = defined($4) ? $4 : "";
404                 $pre  =~ s/\s+/ /g;
405                 $type =~ s/\s+/ /g;
406                 $ptr  =~ s/\s+/ /g;
407                 $ptr  =~ s/\s+$//;
408                 if ($ptr && $ptr !~ m/\*$/) { $ptr .= " "; }
410                 if (($name eq "") && $pre =~ m/^((un)?signed .*)\s?/ ) {
411                     $name = $type;
412                     $type = "$1";
413                     $pre = "";
414                 }
416                 #print "$symbol: '$pre' '$type' '$ptr' '$name' \n";
418                 if ($name eq "") {
419                     $name = "Param" . ($param_num + 1);
420                 }
421                 $output .= &OutputParam ($symbol, $name, $template_exists, 1,
422                                          "");
424             # Try to match parameters which are functions (keep in sync with gtkdoc-mkdb)
425             #                              $1                                       $2          $3      $4                      $5                    $7             $8
426             } elsif ($declaration =~ s/^(const\s+|G_CONST_RETURN\s+|unsigned\s+)*(struct\s+)?(\w+)\s*(\**)\s*(?:restrict\b)?\s*(const\s+)?\(\s*\*+\s*(\w+)\s*\)\s*\(([^)]*)\)\s*[,\n]//) {
427                 $name = $6;
428                 $output .= &OutputParam ($symbol, $name, $template_exists, 1,
429                                          "");
431             } else {
432                 print "###Can't parse args for function $symbol: $declaration\n";
433                 last;
434             }
435             $param_num++;
436         }
439         if ($ret_type ne "void" || $ret_type_modifier || $ret_type_pointer) {
440             $output .= &OutputParam ($symbol, "Returns", $template_exists, 1,
441                                      "");
442         }
443         $output .= &OutputParam ($symbol, "Deprecated", $template_exists, 0, "");
444         $output .= &OutputParam ($symbol, "Since", $template_exists, 0, "");
445         $output .= &OutputParam ($symbol, "Stability", $template_exists, 0, "");
446         $output .= &OutputOldParams ($symbol);
447         $output .= "\n";
448     }
450     if ($type eq "MACRO") {
451         if ($declaration =~ m/^\s*#\s*define\s+\w+\(([^\)]*)\)/) {
452             my ($params) = $1;
453             my ($param);
455             $params =~ s/\\\n//g;
456             foreach $param (split (/,/, $params)) {
457                 $param =~ s/^\s+//;
458                 $param =~ s/\s*$//;
459                 if ($param =~ m/\S/) {
460                     $output .= &OutputParam ($symbol, $param, $template_exists,
461                                              1, "");
462                 }
463             }
464         }
465         $output .= &OutputParam ($symbol, "Returns", $template_exists, 0, "");
466         $output .= &OutputParam ($symbol, "Deprecated", $template_exists, 0, "");
467         $output .= &OutputParam ($symbol, "Since", $template_exists, 0, "");
468         $output .= &OutputParam ($symbol, "Stability", $template_exists, 0, "");
469         $output .= &OutputOldParams ($symbol);
470         $output .= "\n";
471     }
473     if ($type eq "STRUCT") {
474         my $is_object_struct = CheckIsObject ($symbol);
475         my @fields = ParseStructDeclaration($declaration, $is_object_struct, 1);
477         for (my $i = 0; $i <= $#fields; $i += 2) {
478             my $field_name = $fields[$i];
479             $output .= &OutputParam ($symbol, $field_name, $template_exists, 1, "");
480         }
481         $output .= &OutputParam ($symbol, "Deprecated", $template_exists, 0, "");
482         $output .= &OutputParam ($symbol, "Since", $template_exists, 0, "");
483         $output .= &OutputParam ($symbol, "Stability", $template_exists, 0, "");
484     }
486     if ($type eq "ENUM") {
487         my @members = ParseEnumDeclaration($declaration);
489         for my $member (@members) {
490             $output .= &OutputParam ($symbol, $member, $template_exists, 1, "");
491         }
492         $output .= &OutputParam ($symbol, "Deprecated", $template_exists, 0, "");
493         $output .= &OutputParam ($symbol, "Since", $template_exists, 0, "");
494         $output .= &OutputParam ($symbol, "Stability", $template_exists, 0, "");
495     }
497     $output .= "\n";
499     # Remove the used docs from the hashes.
500     if ($template_exists) {
501         delete $SymbolDocs{$symbol};
502         delete $SymbolParams{$symbol};
503     }
505     return $output;
509 #############################################################################
510 # Function    : OutputParam
511 # Description : This outputs the part of a template for one parameter.
512 #               It first checks if the parameter is already described, and if
513 #               so it uses that description, and clears it so it isn't output
514 #               as an old param.
515 # Arguments   : $symbol - the symbol (function or macro) name.
516 #               $param_to_output - the parameter to add.
517 #               $template_exists - TRUE if the template already existed in
518 #                 template files. If it did, then we will flag any changes
519 #                 with 'FIXME'.
520 #               $force_output - TRUE if the parameter should be output even
521 #                 if it didn't already exist in the template. (The return
522 #                 values of macros are added manually if required, and so we
523 #                 never add it here - we only copy it if it already exists.)
524 #               $default_description - the default description of the
525 #                 parameter to be used if it doesn't already exist. (Signal
526 #                 handlers have a few common parameters.)
527 #############################################################################
529 sub OutputParam {
530     my ($symbol, $param_to_output, $template_exists,
531         $force_output, $default_description) = @_;
532     my ($j);
534     my ($params) = $SymbolParams{$symbol};
535     if (defined ($params)) {
536         for ($j = 0; $j <= $#$params; $j += 2) {
537             my $param_name = $$params[$j];
538             my $param_desc = $$params[$j + 1];
540             if ($param_name eq $param_to_output) {
541                 $param_desc =~ s/\s+$//;
542                 $$params[$j] = "";
543                 $$params[$j + 1] = "";
544                 return "\@$param_name: $param_desc\n";
545             }
546         }
547     }
549     # If the template was already in a file, flag the new parameter.
550     # If not, the template itself will be flagged, so we don't need to flag
551     # all the new parameters as well.
552     if ($force_output) {
553         if ($default_description ne "") {
554             $default_description =~ s/\s+$//;
555             return "\@$param_to_output: $default_description\n";
556         } else {
557             if ($template_exists) {
558                 return "\@$param_to_output: $CHANGES_FLAG\n";
559             } else {
560                 return "\@$param_to_output: \n";
561             }
562         }
563     }
564     return "";
568 #############################################################################
569 # Function    : OutputOldParams
570 # Description : This returns all the existing documentation for parameters of
571 #               the given function/macro/signal symbol which are unused, with
572 #               a comment before them.
573 # Arguments   : $symbol - the symbol (function/macro/signal) name.
574 #############################################################################
576 sub OutputOldParams {
577     my ($symbol) = @_;
578     my $output = "";
580     my ($params) = $SymbolParams{$symbol};
581     if (defined ($params)) {
582         my $j;
583         for ($j = 0; $j <= $#$params; $j += 2) {
584             my $param_name = $$params[$j];
585             my $param_desc = $$params[$j + 1];
587             if ($param_name ne "") {
588                 $param_desc =~ s/\s+$//;
590                 # There's no point keeping it if it has no docs.
591                 if ($param_desc ne "") {
592                   $output .= "\@$param_name: $param_desc\n";
593                 }
594             }
595         }
596     }
597     if ($output) {
598         $output = "<!-- # Unused Parameters # -->\n" . $output;
599     }
600     return $output;
604 #############################################################################
605 # Function    : OutputTemplateFile
606 # Description : This outputs one template file.
607 # Arguments   : $file - the basename of the file to output.
608 #               $title - the title from the $MODULE-sections.txt file. This
609 #                 will be overridden by any title given in the template file.
610 #               $output - reference to the templates to output.
611 #############################################################################
613 sub OutputTemplateFile {
614     my ($file, $title, $output) = @_;
616     my ($short_desc, $long_desc, $see_also, $stability);
618     if (defined ($SymbolDocs{"$TMPL_DIR/$file:Title"})) {
619         $title = $SymbolDocs{"$TMPL_DIR/$file:Title"};
620         delete $SymbolDocs{"$TMPL_DIR/$file:Title"};
621     }
622     if (defined ($SymbolDocs{"$TMPL_DIR/$file:Short_Description"})) {
623         $short_desc = $SymbolDocs{"$TMPL_DIR/$file:Short_Description"};
624         delete $SymbolDocs{"$TMPL_DIR/$file:Short_Description"};
625     } else {
626         $short_desc = "";
627     }
628     if (defined ($SymbolDocs{"$TMPL_DIR/$file:Long_Description"})) {
629         $long_desc = $SymbolDocs{"$TMPL_DIR/$file:Long_Description"};
630         delete $SymbolDocs{"$TMPL_DIR/$file:Long_Description"};
631     } else {
632         $long_desc = "<para>\n\n</para>\n";
633     }
634     if (defined ($SymbolDocs{"$TMPL_DIR/$file:See_Also"})) {
635         $see_also = $SymbolDocs{"$TMPL_DIR/$file:See_Also"};
636         delete $SymbolDocs{"$TMPL_DIR/$file:See_Also"};
637     } else {
638         $see_also = "<para>\n\n</para>\n";
639     }
640     if (defined ($SymbolDocs{"$TMPL_DIR/$file:Stability_Level"})) {
641         $stability = $SymbolDocs{"$TMPL_DIR/$file:Stability_Level"};
642         delete $SymbolDocs{"$TMPL_DIR/$file:Stability_Level"};
643     } else {
644         $stability = "";
645     }
648     my $old_tmpl_file = "$TMPL_DIR/$file";
649     my $new_tmpl_file = "$TMPL_DIR/$file.new";
651     open (OUTPUT, ">$new_tmpl_file")
652         || die "Can't create $new_tmpl_file";
654     print (OUTPUT <<EOF);
655 <!-- ##### SECTION Title ##### -->
656 $title
658 <!-- ##### SECTION Short_Description ##### -->
659 $short_desc
661 <!-- ##### SECTION Long_Description ##### -->
662 $long_desc
664 <!-- ##### SECTION See_Also ##### -->
665 $see_also
667 <!-- ##### SECTION Stability_Level ##### -->
668 $stability
672     print (OUTPUT $$output) unless $ONLY_SECTION_TMPL;
673     close (OUTPUT);
675     return &UpdateFileIfChanged ($old_tmpl_file, $new_tmpl_file, 1);
679 #############################################################################
680 # Function    : OutputSignalTemplates
681 # Description : Outputs templates for signal handlers.
682 # Arguments   : $title - the title from the $MODULE-sections.txt file. If the
683 #                 file is describing a GtkObject subclass, the title should
684 #                 be the name of the class, e.g. 'GtkButton'.
685 #############################################################################
687 sub OutputSignalTemplates {
688     my ($title) = @_;
690     my $output = "";
691     my ($i, $template_exists);
692     for ($i = 0; $i <= $#SignalObjects; $i++) {
693         if ($SignalObjects[$i] eq $title) {
694 #           print "Found signal: $SignalObjects[$i]\n";
695             my ($symbol) = "$SignalObjects[$i]::$SignalNames[$i]";
697             # See if symbol already has a description.
698             my ($symbol_desc) = $SymbolDocs{$symbol};
699             if (defined ($symbol_desc)) {
700                 $template_exists = 1;
701                 $symbol_desc =~ s/\s+$//;
702                 delete $SymbolDocs{$symbol};
703             } else {
704                 $template_exists = 0;
705                 $symbol_desc = "<para>\n$CHANGES_FLAG\n</para>";
706             }
708             $output .= <<EOF;
709 <!-- ##### SIGNAL $symbol ##### -->
710 $symbol_desc
713             my $sourceparams = $SymbolParams{$symbol};
714             my @params = split ("[,\n]", $SignalPrototypes[$i]);
715             my ($j, $name);
716             for ($j = 0; $j <= $#params; $j++) {
717                 my $param = $params[$j];
718                 $param =~ s/^\s+//;
719                 $param =~ s/\s*$//;
720                 if ($param =~ m/^\s*$/) { next; }
721                 if ($param =~ m/^void$/) { next; }
723                 if ($param =~ m/^\s*(\w+)\s*(\**)\s*([\w\[\]]+)?\s*$/) {
724                     if (defined ($sourceparams)) {
725                         $name = $$sourceparams[2 * $j];
726                     } else {
727                         $name = $3;
728                     }
730                     if (!defined ($name)) {
731                         $name = "Param" . ($j + 1);
732                     }
734                     if ($j == 0) {
735                         $output .= &OutputParam ($symbol, $name,
736                                                  $template_exists, 1,
737                                                  "the object which received the signal.");
738                     } else {
739                         $output .= &OutputParam ($symbol, $name,
740                                                  $template_exists, 1, "");
741                     }
742                 }
743             }
745             if ($SignalReturns[$i] ne "void") {
746                 $output .= &OutputParam ($symbol, "Returns", $template_exists,
747                                          1, "");
748             }
749             $output .= &OutputOldParams ($symbol);
750             $output .= "\n";
751         }
752     }
753     return $output;
757 #############################################################################
758 # Function    : OutputArgTemplates
759 # Description : Outputs templates for Args.
760 # Arguments   : $title - the title from the $MODULE-sections.txt file. If the
761 #                 file is describing a GtkObject subclass, the title should
762 #                 be the name of the class, e.g. 'GtkButton'.
763 #############################################################################
765 sub OutputArgTemplates {
766     my ($title) = @_;
768     my $output = "";
769     my $i;
770     for ($i = 0; $i <= $#ArgObjects; $i++) {
771         if ($ArgObjects[$i] eq $title) {
772 #           print "Found arg: $ArgObjects[$i]\n";
773             # I've only used one colon so we don't clash with signals.
774             my ($symbol) = "$ArgObjects[$i]:$ArgNames[$i]";
776             # See if symbol already has a description.
777             my ($symbol_desc) = $SymbolDocs{$symbol};
778             if (defined ($symbol_desc)) {
779                 delete $SymbolDocs{$symbol};
780                 $symbol_desc =~ s/\s+$//;
781             } else {
782                 $symbol_desc = "<para>\n$CHANGES_FLAG\n</para>";
783             }
785             $output .= <<EOF;
786 <!-- ##### ARG $symbol ##### -->
787 $symbol_desc
790         }
791     }
792     return $output;
796 #############################################################################
797 # Function    : OutputUnusedTemplates
798 # Description : This saves any unused documentation into $MODULE-unused.sgml.
799 # Arguments   : none
800 #############################################################################
802 sub OutputUnusedTemplates {
803     my ($old_unused_file) = "$TMPL_DIR/$MODULE-unused.sgml";
804     my ($new_unused_file) = "$TMPL_DIR/$MODULE-unused.new";
806     open (UNUSED, ">$new_unused_file")
807         || die "Can't open file: $new_unused_file";
809     my $output = "";
810     my ($symbol, $symbol_desc);
811     for $symbol (sort keys %SymbolDocs) {
812         $symbol_desc = $SymbolDocs{$symbol};
814 #       print "Unused: $symbol\n";
816         my $type = $SymbolTypes{$symbol};
817         if (!defined ($type)) {
818             $type = "UNKNOWN";
819             print "WARNING: Unused symbol $symbol has unknown type\n";
820         }
822     $output .= <<EOF;
823 <!-- ##### $type $symbol ##### -->
824 $symbol_desc
828         my ($params) = $SymbolParams{$symbol};
829         if (defined ($params)) {
830             my $j;
831             for ($j = 0; $j <= $#$params; $j += 2) {
832                 my $param_name = $$params[$j];
833                 my $param_desc = $$params[$j + 1];
834                 $param_desc =~ s/\s+$//;
835                 $output .= "\@$param_name: $param_desc\n";
836             }
837         }
838         $output .= "\n";
839     }
841     print UNUSED $output;
842     close (UNUSED);
844     &UpdateFileIfChanged ($old_unused_file, $new_unused_file, 1);
848 #############################################################################
849 # LIBRARY FUNCTIONS -   These functions are used in both gtkdoc-mkdb and
850 #                       gtkdoc-mktmpl and should eventually be moved to a
851 #                       separate library.
852 #############################################################################
854 #############################################################################
855 # Function    : ReadDeclarationsFile
856 # Description : This reads in a file containing the function/macro/enum etc.
857 #               declarations.
859 #               Note that in some cases there are several declarations with
860 #               the same name, e.g. for conditional macros. In this case we
861 #               set a flag in the %DeclarationConditional hash so the
862 #               declaration is not shown in the docs.
864 #               If a macro and a function have the same name, e.g. for
865 #               gtk_object_ref, the function declaration takes precedence.
867 #               Some opaque structs are just declared with 'typedef struct
868 #               _name name;' in which case the declaration may be empty.
869 #               The structure may have been found later in the header, so
870 #               that overrides the empty declaration.
872 # Arguments   : $file - the declarations file to read
873 #               $override - if declarations in this file should override
874 #                       any current declaration.
875 #############################################################################
877 sub ReadDeclarationsFile {
878     my ($file, $override) = @_;
880     if ($override == 0) {
881         %Declarations = ();
882         %DeclarationTypes = ();
883         %DeclarationConditional = ();
884         %DeclarationOutput = ();
885     }
887     open (INPUT, $file)
888         || die "Can't open $file";
889     my $declaration_type = "";
890     my $declaration_name;
891     my $declaration;
892     while (<INPUT>) {
893         if (!$declaration_type) {
894             if (m/^<([^>]+)>/) {
895                 $declaration_type = $1;
896                 $declaration_name = "";
897 #               print "Found declaration: $declaration_type\n";
898                 $declaration = "";
899             }
900         } else {
901             if (m%^<NAME>(.*)</NAME>%) {
902                 $declaration_name = $1;
903             } elsif (m%<DEPRECATED/>%) {
904                 # do nothing, just skip the line; we handle this
905                 # in mkdb
906             } elsif (m%^</$declaration_type>%) {
907 #               print "Found end of declaration: $declaration_name\n";
908                 # Check that the declaration has a name
909                 if ($declaration_name eq "") {
910                     print "ERROR: $declaration_type has no name $file:$.\n";
911                 }
913                 # Check if the symbol is already defined.
914                 if (defined ($Declarations{$declaration_name})
915                     && $override == 0) {
916                     # Function declarations take precedence.
917                     if ($DeclarationTypes{$declaration_name} eq 'FUNCTION') {
918                         # Ignore it.
919                     } elsif ($declaration_type eq 'FUNCTION') {
920                         $Declarations{$declaration_name} = $declaration;
921                         $DeclarationTypes{$declaration_name} = $declaration_type;
922                     } elsif ($DeclarationTypes{$declaration_name}
923                               eq $declaration_type) {
924                         # If the existing declaration is empty, or is just a
925                         # forward declaration of a struct, override it.
926                         if ($declaration_type eq 'STRUCT') {
927                             if ($Declarations{$declaration_name} =~ m/^\s*(struct\s+\w+\s*;)?\s*$/) {
928                                 $Declarations{$declaration_name} = $declaration;
929                             } elsif ($declaration =~ m/^\s*(struct\s+\w+\s*;)?\s*$/) {
930                                 # Ignore an empty or forward declaration.
931                             } else {
932                                 print "WARNING: Structure has multiple definitions: $declaration_name\n";
933                             }
935                         } else {
936                             # set flag in %DeclarationConditional hash for
937                             # multiply defined macros/typedefs.
938                             $DeclarationConditional{$declaration_name} = 1;
939                         }
940                     } else {
941                         print "WARNING: $declaration_name has multiple definitions\n";
942                     }
943                 } else {
944                     $Declarations{$declaration_name} = $declaration;
945                     $DeclarationTypes{$declaration_name} = $declaration_type;
946                 }
947                 $declaration_type = "";
948             } else {
949                 $declaration .= $_;
950             }
951         }
952     }
953     close (INPUT);
957 #############################################################################
958 # Function    : ReadSignalsFile
959 # Description : This reads in an existing file which contains information on
960 #               all GTK signals. It creates the arrays @SignalNames and
961 #               @SignalPrototypes containing info on the signals. The first
962 #               line of the SignalPrototype is the return type of the signal
963 #               handler. The remaining lines are the parameters passed to it.
964 #               The last parameter, "gpointer user_data" is always the same
965 #               so is not included.
966 # Arguments   : $file - the file containing the signal handler prototype
967 #                       information.
968 #############################################################################
970 sub ReadSignalsFile {
971     my ($file) = @_;
973     my $in_signal = 0;
974     my $signal_object;
975     my $signal_name;
976     my $signal_returns;
977     my $signal_flags;
978     my $signal_prototype;
980     # Reset the signal info.
981     @SignalObjects = ();
982     @SignalNames = ();
983     @SignalReturns = ();
984     @SignalFlags = ();
985     @SignalPrototypes = ();
987     if (! -f $file) {
988         return;
989     }
990     if (!open (INPUT, $file)) {
991         warn "Can't open $file - skipping signals\n";
992         return;
993     }
994     while (<INPUT>) {
995         if (!$in_signal) {
996             if (m/^<SIGNAL>/) {
997                 $in_signal = 1;
998                 $signal_object = "";
999                 $signal_name = "";
1000                 $signal_returns = "";
1001                 $signal_prototype = "";
1002             }
1003         } else {
1004             if (m/^<NAME>(.*)<\/NAME>/) {
1005                 $signal_name = $1;
1006                 if ($signal_name =~ m/^(.*)::(.*)$/) {
1007                     $signal_object = $1;
1008                     ($signal_name = $2) =~ s/_/-/g;
1009 #                   print "Found signal: $signal_name\n";
1010                 } else {
1011                     print "Invalid signal name: $signal_name\n";
1012                 }
1013             } elsif (m/^<RETURNS>(.*)<\/RETURNS>/) {
1014                 $signal_returns = $1;
1015             } elsif (m/^<FLAGS>(.*)<\/FLAGS>/) {
1016                 $signal_flags = $1;
1017             } elsif (m%^</SIGNAL>%) {
1018 #               print "Found end of signal: ${signal_object}::${signal_name}\nReturns: ${signal_returns}\n${signal_prototype}";
1019                 push (@SignalObjects, $signal_object);
1020                 push (@SignalNames, $signal_name);
1021                 push (@SignalReturns, $signal_returns);
1022                 push (@SignalFlags, $signal_flags);
1023                 push (@SignalPrototypes, $signal_prototype);
1024                 $in_signal = 0;
1025             } else {
1026                 $signal_prototype .= $_;
1027             }
1028         }
1029     }
1030     close (INPUT);
1034 #############################################################################
1035 # Function    : ReadTemplateFile
1036 # Description : This reads in the manually-edited documentation file
1037 #               corresponding to the file currently being created, so we can
1038 #               insert the documentation at the appropriate places.
1039 #               It outputs %SymbolTypes, %SymbolDocs and %SymbolParams, which
1040 #               is a hash of arrays.
1041 #               NOTE: This function is duplicated in gtkdoc-mkdb (but
1042 #               slightly different).
1043 # Arguments   : $docsfile - the template file to read in.
1044 #               $skip_unused_params - 1 if the unused parameters should be
1045 #                       skipped.
1046 #############################################################################
1048 sub ReadTemplateFile {
1049     my ($docsfile, $skip_unused_params) = @_;
1051 #    print "Reading $docsfile\n";
1052     if (! -f $docsfile) {
1053         print "File doesn't exist: $docsfile\n";
1054         return;
1055     }
1057     my $CurrentType = "";       # Type of symbol being read.
1058     my $CurrentSymbol = "";     # Name of symbol being read.
1059     my $SymbolDoc = "";         # Description of symbol being read.
1060     my @Params;                 # Parameter names and descriptions of current
1061                                 #   function/macro/function typedef.
1062     my $CurrentParam = -1;      # Index of parameter currently being read.
1063                                 #   Note that the param array contains pairs
1064                                 #   of param name & description.
1065     my $InUnusedParameters = 0; # True if we are reading in the unused params.
1067     open (DOCS, $docsfile)
1068         || die "Can't open file $docsfile: $!";
1069     while (<DOCS>) {
1070         if (m/^<!-- ##### ([A-Z_]+) (\S+) ##### -->/) {
1071             my $type = $1;
1072             my $symbol = $2;
1073             if ($symbol eq "Title"
1074                 || $symbol eq "Short_Description"
1075                 || $symbol eq "Long_Description"
1076                 || $symbol eq "See_Also"
1077                 || $symbol eq "Stability_Level") {
1078                 $symbol = $docsfile . ":" . $symbol;
1079 #               print "Found symbol: $symbol\n";
1080             }
1082             # Canonicalize signal and argument names to have -, not _
1083             if ($type eq "ARG" || $type eq "SIGNAL") {
1084               $symbol =~ s/_/-/g;
1085             }
1087             # Store previous symbol, but remove any trailing blank lines.
1088             if ($CurrentSymbol ne "") {
1089                 $SymbolDoc =~ s/\s+$//;
1090                 $SymbolTypes{$CurrentSymbol} = $CurrentType;
1091                 $SymbolDocs{$CurrentSymbol} = $SymbolDoc;
1092                 if ($CurrentParam >= 0) {
1093                     $SymbolParams{$CurrentSymbol} = [ @Params ];
1094                 } else {
1095                     # Delete any existing params in case we are overriding a
1096                     # previously read template.
1097                     delete $SymbolParams{$CurrentSymbol};
1098                 }
1099             }
1100             $CurrentType = $type;
1101             $CurrentSymbol = $symbol;
1102             $CurrentParam = -1;
1103             $InUnusedParameters = 0;
1104             $SymbolDoc = "";
1105             @Params = ();
1107         } elsif (m/^<!-- # Unused Parameters # -->/) {
1108             $InUnusedParameters = 1;
1109             next;
1111         } else {
1112             # Workaround for an old bug that left a mess in the templates.
1113             # This happened with macros with args spread over several lines.
1114             if (m/^\@\\$/) {
1115               # Skip the next line.
1116               $_ = <DOCS>;
1117               next;
1118             }
1120             # Workaround for an old bug that left '@:' at start of lines.
1121             if (m/^\@:$/) {
1122               next;
1123             }
1126             # Check if param found. Need to handle "..." and "format...".
1127             if (s/^\@([\w\.]+):\040?//) {
1128                 my $param_name = $1;
1129                 # Allow variations of 'Returns'
1130                 if ($param_name =~ m/^[Rr]eturns?$/) {
1131                     $param_name = "Returns";
1132                 }
1133 #               print "Found param: $param_name\n";
1134                 push (@Params, $param_name);
1135                 push (@Params, $_);
1136                 $CurrentParam += 2;
1137                 next;
1138             }
1140             # When outputting the DocBook we skip unused parameters.
1141             if (!$InUnusedParameters || !$skip_unused_params) {
1142                 if ($CurrentParam >= 0) {
1143                     $Params[$CurrentParam] .= $_;
1144                 } else {
1145                     $SymbolDoc .= $_;
1146                 }
1147             }
1148         }
1149     }
1151     # Remember to finish the current symbol doccs.
1152     if ($CurrentSymbol ne "") {
1153         $SymbolDoc =~ s/\s+$//;
1154         $SymbolTypes{$CurrentSymbol} = $CurrentType;
1155         $SymbolDocs{$CurrentSymbol} = $SymbolDoc;
1156         if ($CurrentParam >= 0) {
1157             $SymbolParams{$CurrentSymbol} = [ @Params ];
1158         } else {
1159             delete $SymbolParams{$CurrentSymbol};
1160         }
1161     }
1163     close (DOCS);
1167 #############################################################################
1168 # Function    : ReadObjectHierarchy
1169 # Description : This reads in the $MODULE-hierarchy.txt file containing all
1170 #               the GtkObject subclasses described in this module (and their
1171 #               ancestors).
1172 #               It places them in the @Objects array, and places their level
1173 #               in the widget hierarchy in the @ObjectLevels array, at the
1174 #               same index. GtkObject, the root object, has a level of 1.
1176 #               FIXME: the version in gtkdoc-mkdb also generates tree_index.sgml
1177 #               as it goes along, this should be split out into a separate
1178 #               function.
1180 # Arguments   : none
1181 #############################################################################
1183 sub ReadObjectHierarchy {
1184     @Objects = ();
1185     @ObjectLevels = ();
1187     if (! -f $OBJECT_TREE_FILE) {
1188         return;
1189     }
1190     if (!open (INPUT, $OBJECT_TREE_FILE)) {
1191         warn "Can't open $OBJECT_TREE_FILE - skipping object tree\n";
1192         return;
1193     }
1194     while (<INPUT>) {
1195         if (m/\S+/) {
1196             my $object = $&;
1197             my $level = (length($`)) / 2 + 1;
1198 #            print ("Level: $level  Object: $object\n");
1200             push (@Objects, $object);
1201             push (@ObjectLevels, $level);
1202         }
1203     }
1205     close (INPUT);
1209 #############################################################################
1210 # Function    : ReadArgsFile
1211 # Description : This reads in an existing file which contains information on
1212 #               all GTK args. It creates the arrays @ArgObjects, @ArgNames,
1213 #               @ArgTypes and @ArgFlags containing info on the args.
1214 # Arguments   : $file - the file containing the arg information.
1215 #############################################################################
1217 sub ReadArgsFile {
1218     my ($file) = @_;
1220     my $in_arg = 0;
1221     my $arg_object;
1222     my $arg_name;
1223     my $arg_type;
1224     my $arg_flags;
1226     # Reset the signal info.
1227     @ArgObjects = ();
1228     @ArgNames = ();
1229     @ArgTypes = ();
1230     @ArgFlags = ();
1232     if (! -f $file) {
1233         return;
1234     }
1235     if (!open (INPUT, $file)) {
1236         warn "Can't open $file - skipping args\n";
1237         return;
1238     }
1239     while (<INPUT>) {
1240         if (!$in_arg) {
1241             if (m/^<ARG>/) {
1242                 $in_arg = 1;
1243                 $arg_object = "";
1244                 $arg_name = "";
1245                 $arg_type = "";
1246                 $arg_flags = "";
1247             }
1248         } else {
1249             if (m/^<NAME>(.*)<\/NAME>/) {
1250                 $arg_name = $1;
1251                 if ($arg_name =~ m/^(.*)::(.*)$/) {
1252                     $arg_object = $1;
1253                     ($arg_name = $2) =~ s/_/-/g;
1254 #                   print "Found arg: $arg_name\n";
1255                 } else {
1256                     print "Invalid arg name: $arg_name\n";
1257                 }
1258             } elsif (m/^<TYPE>(.*)<\/TYPE>/) {
1259                 $arg_type = $1;
1260             } elsif (m/^<FLAGS>(.*)<\/FLAGS>/) {
1261                 $arg_flags = $1;
1262             } elsif (m%^</ARG>%) {
1263 #               print "Found end of arg: ${arg_object}::${arg_name}\n${arg_type} : ${arg_flags}\n";
1264                 push (@ArgObjects, $arg_object);
1265                 push (@ArgNames, $arg_name);
1266                 push (@ArgTypes, $arg_type);
1267                 push (@ArgFlags, $arg_flags);
1268                 $in_arg = 0;
1269             }
1270         }
1271     }
1272     close (INPUT);
1276 #############################################################################
1277 # Function    : CheckIsObject
1278 # Description : Returns 1 if the given name is a GtkObject or a subclass.
1279 #               It uses the global @Objects array.
1280 #               Note that the @Objects array only contains classes in the
1281 #               current module and their ancestors - not all GTK classes.
1282 # Arguments   : $name - the name to check.
1283 #############################################################################
1285 sub CheckIsObject {
1286     my ($name) = @_;
1288     my $object;
1289     foreach $object (@Objects) {
1290         if ($object eq $name) {
1291             return 1;
1292         }
1293     }
1294     return 0;