Updated Swedish translation
[gtk-doc.git] / gtkdoc-mktmpl.in
blobc64dfd30a00d2e55d1edfae5fbe68c8677d228b4
1 #!@PERL@ -w
2 # -*- cperl -*-
4 # gtk-doc - GTK DocBook documentation generator.
5 # Copyright (C) 1998  Damon Chaplin
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #############################################################################
23 # Script      : gtkdoc-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.sgml. 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 tmpl/$MODULE-unused.sgml.
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 push @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 <<EOF;
89 gtkdoc-mktmpl version @VERSION@ - generate documentation templates
91 --module=MODULE_NAME Name of the doc module being parsed
92 --flag-changes       If specified, changes in templates are flagged
93 --output-dir=DIRNAME The directory where the results are stored
94 --only-section-tmpl  Only include section information in templates
95 --version            Print the version of this program
96 --help               Print this help
97 EOF
98     exit 0;
101 print <<EOF;
102 ###############################################################################
103 gtkdoc-mktmpl is deprecated and will be removed from one of the next gtk-doc 
104 release.
105 Please refer to the documentation "Modernizing the documentation"/"GTK-Doc 1.9".
106 ###############################################################################
109 my $ROOT_DIR = ".";
111 # The directory containing the template files.
112 $TMPL_DIR = $TMPL_DIR ? $TMPL_DIR : "$ROOT_DIR/tmpl";
114 # This file contains the object hierarchy.
115 my $OBJECT_TREE_FILE = "$ROOT_DIR/$MODULE.hierarchy";
117 # The file containing signal handler prototype information.
118 my $SIGNALS_FILE = "$ROOT_DIR/$MODULE.signals";
120 # The file containing Arg information.
121 my $ARGS_FILE = "$ROOT_DIR/$MODULE.args";
123 # Set the flag to indicate changes, if requested.
124 my $CHANGES_FLAG = $FLAG_CHANGES ? "FIXME" : "";
126 # These global arrays store information on signals. Each signal has an entry
127 # in each of these arrays at the same index, like a multi-dimensional array.
128 my @SignalObjects;        # The GtkObject which emits the signal.
129 my @SignalNames;        # The signal name.
130 my @SignalReturns;        # The return type.
131 my @SignalFlags;        # Flags for the signal
132 my @SignalPrototypes;        # The rest of the prototype of the signal handler.
134 # These global arrays store information on Args. Each Arg has an entry
135 # in each of these arrays at the same index, like a multi-dimensional array.
136 my @ArgObjects;                # The GtkObject which has the Arg.
137 my @ArgNames;                # The Arg name.
138 my @ArgTypes;                # The Arg type - gint, GtkArrowType etc.
139 my @ArgFlags;                # How the Arg can be used - readable/writable etc.
141 # These global hashes store declaration info keyed on a symbol name.
142 my %Declarations;
143 my %DeclarationTypes;
144 my %DeclarationConditional;
145 my %DeclarationOutput;
147 # These global hashes store the existing documentation.
148 my %SymbolDocs;
149 my %SymbolTypes;
150 my %SymbolParams;
151 my %SymbolSourceFile;
152 my %SymbolSourceLine;
154 # These global arrays store GObject and subclasses and the hierarchy.
155 my @Objects;
156 my @ObjectLevels;
158 &ReadSignalsFile ($SIGNALS_FILE);
159 &ReadArgsFile ($ARGS_FILE);
160 &ReadObjectHierarchy;
162 &ReadDeclarationsFile ("$ROOT_DIR/$MODULE-decl.txt", 0);
163 if (-f "$ROOT_DIR/$MODULE-overrides.txt") {
164     &ReadDeclarationsFile ("$ROOT_DIR/$MODULE-overrides.txt", 1);
166 &ReadExistingTemplates;
168 my $changed = 0;
170 if (&UpdateTemplates ("$ROOT_DIR/$MODULE-sections.txt")) {
171   $changed = 1;
173 &OutputUnusedTemplates;
174 if (&CheckAllDeclarationsOutput) {
175   $changed = 1;
178 if ($changed || ! -e "$ROOT_DIR/tmpl.stamp") {
179     open (TIMESTAMP, ">$ROOT_DIR/tmpl.stamp")
180         || die "Can't create $ROOT_DIR/tmpl.stamp";
181     print (TIMESTAMP "timestamp");
182     close (TIMESTAMP);
185 #############################################################################
186 # Function    : ReadExistingTemplates
187 # Description : This reads in all the existing documentation, into the global
188 #                variables %SymbolDocs, %SymbolTypes, and %SymbolParams (a
189 #                hash of arrays).
190 # Arguments   : none
191 #############################################################################
193 sub ReadExistingTemplates {
194     %SymbolDocs = ();
195     %SymbolTypes = ();
196     %SymbolParams = ();
198     # Read the unused docs first, so they get overridden by any real docs.
199     # (though this shouldn't happen often).
200     my $unused_doc = "$TMPL_DIR/$MODULE-unused.sgml";
201     if (-e $unused_doc) {
202         &ReadTemplateFile ($unused_doc, 0);
203     }
205     while (<$TMPL_DIR/*.sgml>) {
206 #        print "Reading $_\n";
207         if ($_ eq $unused_doc) {
208 #            print "skipping $unused_doc\n";
209         } else {
210             &ReadTemplateFile ($_, 0);
211         }
212     }
216 #############################################################################
217 # Function    : UpdateTemplates
218 # Description : This collects the output for each section of the docs, and
219 #                outputs each file when the end of the section is found.
220 # Arguments   : $file - the file containing the sections of the docs.
221 #############################################################################
223 sub UpdateTemplates {
224     my ($file) = @_;
225 #    print "Reading: $file\n";
227     open (INPUT, $file)
228         || die "Can't open $file";
230     # Create the top output directory if it doesn't exist.
231     if (! -e $TMPL_DIR) {
232         mkdir ("$TMPL_DIR", 0777)
233             || die "Can't create directory: $TMPL_DIR";
234     }
236     my $filename = "";
237     my $title = "";
238     my $subsection = "";
239     my $output;
240     my $changed = 0;
241     while (<INPUT>) {
242         if (m/^#/) {
243             next;
245         } elsif (m/^<SECTION>/) {
246             $output = "";
248         } elsif (m/^<SUBSECTION\s*(.*)>/i) {
249             $subsection = $1;
250             next;
252         } elsif (m/^<TITLE>(.*)<\/TITLE>/) {
253             $title = $1;
254 #            print "Section: $title\n";
256         } elsif (m/^<FILE>(.*)<\/FILE>/) {
257             $filename = $1;
259         } elsif (m/^<INCLUDE>(.*)<\/INCLUDE>/) {
260             next;
262         } elsif (m/^<\/SECTION>/) {
263             if ($title eq "") {
264                 $title = $filename;
265             }
266 #            print "End of section: $title\n";
268             $filename =~ s/\s/_/g;
269             $filename .= ".sgml";
271             if (&OutputTemplateFile ($filename, $title, \$output)) {
272               $changed = 1;
273             }
275             $title = "";
276             $subsection = "";
278         } elsif (m/^(\S+)/) {
279             my $symbol = $1;
280 #            print "  Symbol: $symbol\n";
282             my $declaration = $Declarations{$1};
283             if (defined ($declaration)) {
284                 # We don't want templates for standard macros/functions of
285                 # GObjects or private declarations.
286                 if ($subsection ne "Standard" && $subsection ne "Private") {
287                     $output .= &OutputDeclaration ($DeclarationTypes {$symbol},
288                                                    $symbol, $declaration);
290                     $output .= &OutputSignalTemplates ($symbol);
291                     $output .= &OutputArgTemplates ($symbol);
292                 }
294                 # Note that the declaration has been output.
295                 $DeclarationOutput{$symbol} = 1;
297                 if ($declaration eq '##conditional##') {
298 #                    print "Conditional $DeclarationTypes{$symbol}\n";
299                 }
301             } else {
302                 &LogWarning ($file, $., "No declaration found for: $1");
303             }
304         }
305     }
306     close (INPUT);
308     return $changed;
312 #############################################################################
313 # Function    : CheckAllDeclarationsOutput
314 # Description : This steps through all the declarations that were loaded, and
315 #                makes sure that each one has been output, by checking the
316 #                corresponding flag in the %DeclarationOutput hash. It is
317 #                intended to check that any new declarations in new versions
318 #                of the module get added to the $MODULE-sections.txt file.
319 # Arguments   : none
320 #############################################################################
322 sub CheckAllDeclarationsOutput {
323     my $num_unused = 0;
325     my $old_unused_file = "$ROOT_DIR/$MODULE-unused.txt";
326     my $new_unused_file = "$ROOT_DIR/$MODULE-unused.new";
328     open (UNUSED, ">$new_unused_file")
329         || die "Can't open $new_unused_file";
330     my ($symbol);
331     foreach $symbol (sort keys (%Declarations)) {
332         if (!defined ($DeclarationOutput{$symbol})) {
333             print (UNUSED "$symbol\n");
334             $num_unused++;
335         }
336     }
337     close (UNUSED);
338     if ($num_unused != 0) {
339         &LogWarning ($old_unused_file, 1, "$num_unused unused declarations.".
340             "They should be added to $MODULE-sections.txt in the appropriate place.");
341     }
343     return &UpdateFileIfChanged ($old_unused_file, $new_unused_file, 0);
347 #############################################################################
348 # Function    : OutputDeclaration
349 # Description : This returns the template for one symbol & declaration.
350 #                Note that it uses the global %SymbolDocs and %SymbolParams to
351 #                lookup any existing documentation.
352 # Arguments   : $type - the type of the symbol ('FUNCTION'/'MACRO' etc.)
353 #                $symbol - the symbol name.
354 #                $declaration - the declaration of the symbol.
355 #############################################################################
357 sub OutputDeclaration {
358     my ($type, $symbol, $declaration) = @_;
359     my ($output) = "";
361     #print "Outputting $type: $symbol\n";
363     # See if symbol already has a description.
364     my ($symbol_desc) = $SymbolDocs{$symbol};
365     my ($template_exists);
366     if (defined ($symbol_desc)) {
367         $template_exists = 1;
368         $symbol_desc =~ s/\s+$//;
369     } else {
370         $template_exists = 0;
371         $symbol_desc = "<para>\n$CHANGES_FLAG\n</para>";
372     }
374     $output .= <<EOF;
375 <!-- ##### $type $symbol ##### -->
376 $symbol_desc
380     # For functions, function typedefs and macros, we output the arguments.
381     # For functions and function typedefs we also output the return value.
382     if ($type eq "FUNCTION" || $type eq "USER_FUNCTION") {
383         # Take out the return type
384         $declaration =~ s/<RETURNS>\s*(.*?)<\/RETURNS>\n//;
385         my $ret_type_decl = $1;
386         my $ret_type_modifier;
387         my $ret_type;
388         my $ret_type_pointer;
390         if ($ret_type_decl =~ m/((const\s+|G_CONST_RETURN\s+|unsigned\s+|signed\s+|long\s+|short\s+|struct\s+|enum\s+)*)(\w+)\s*(\**\s*(const|G_CONST_RETURN)?\s*\**\s*(restrict)?\s*)/) {
391             $ret_type_modifier = defined($1) ? $1 : "";
392             $ret_type = $3;
393             $ret_type_pointer = $4;
394         } else {
395             $ret_type = "void";
396         }
398         my @fields = ParseFunctionDeclaration($declaration);
400         for (my $i = 0; $i <= $#fields; $i += 2) {
401             my $field_name = $fields[$i];
402             $output .= &OutputParam ($symbol, $field_name, $template_exists, 1, "");
403         }
405         if ($ret_type ne "void" || $ret_type_modifier || $ret_type_pointer) {
406             $output .= &OutputParam ($symbol, "Returns", $template_exists, 1, "");
407         }
409         $output .= &OutputParam ($symbol, "Deprecated", $template_exists, 0, "");
410         $output .= &OutputParam ($symbol, "Since", $template_exists, 0, "");
411         $output .= &OutputParam ($symbol, "Stability", $template_exists, 0, "");
412         $output .= &OutputOldParams ($symbol);
413         $output .= "\n";
414     }
416     if ($type eq "MACRO") {
417         my @fields = ParseMacroDeclaration($declaration);
419         for (my $i = 0; $i <= $#fields; $i +=2) {
420             my $field_name = $fields[$i];
422             $output .= &OutputParam ($symbol, $field_name, $template_exists,
423                                      1, "");
424         }
425         $output .= &OutputParam ($symbol, "Returns", $template_exists, 0, "");
426         $output .= &OutputParam ($symbol, "Deprecated", $template_exists, 0, "");
427         $output .= &OutputParam ($symbol, "Since", $template_exists, 0, "");
428         $output .= &OutputParam ($symbol, "Stability", $template_exists, 0, "");
429         $output .= &OutputOldParams ($symbol);
430         $output .= "\n";
431     }
433     if ($type eq "STRUCT") {
434         my $is_object_struct = CheckIsObject ($symbol);
435         my @fields = ParseStructDeclaration($declaration, $is_object_struct, 1);
437         for (my $i = 0; $i <= $#fields; $i += 2) {
438             my $field_name = $fields[$i];
439             $output .= &OutputParam ($symbol, $field_name, $template_exists, 1, "");
440         }
441         $output .= &OutputParam ($symbol, "Deprecated", $template_exists, 0, "");
442         $output .= &OutputParam ($symbol, "Since", $template_exists, 0, "");
443         $output .= &OutputParam ($symbol, "Stability", $template_exists, 0, "");
444     }
446     if ($type eq "ENUM") {
447         my @members = ParseEnumDeclaration($declaration);
449         for my $member (@members) {
450             $output .= &OutputParam ($symbol, $member, $template_exists, 1, "");
451         }
452         $output .= &OutputParam ($symbol, "Deprecated", $template_exists, 0, "");
453         $output .= &OutputParam ($symbol, "Since", $template_exists, 0, "");
454         $output .= &OutputParam ($symbol, "Stability", $template_exists, 0, "");
455     }
457     $output .= "\n";
459     # Remove the used docs from the hashes.
460     if ($template_exists) {
461         delete $SymbolDocs{$symbol};
462         delete $SymbolParams{$symbol};
463     }
465     return $output;
469 #############################################################################
470 # Function    : OutputParam
471 # Description : This outputs the part of a template for one parameter.
472 #                It first checks if the parameter is already described, and if
473 #                so it uses that description, and clears it so it isn't output
474 #                as an old param.
475 # Arguments   : $symbol - the symbol (function or macro) name.
476 #                $param_to_output - the parameter to add.
477 #                $template_exists - TRUE if the template already existed in
478 #                  template files. If it did, then we will flag any changes
479 #                  with 'FIXME'.
480 #                $force_output - TRUE if the parameter should be output even
481 #                  if it didn't already exist in the template. (The return
482 #                  values of macros are added manually if required, and so we
483 #                  never add it here - we only copy it if it already exists.)
484 #                $default_description - the default description of the
485 #                  parameter to be used if it doesn't already exist. (Signal
486 #                  handlers have a few common parameters.)
487 #############################################################################
489 sub OutputParam {
490     my ($symbol, $param_to_output, $template_exists,
491         $force_output, $default_description) = @_;
492     my ($j);
494     my ($params) = $SymbolParams{$symbol};
495     if (defined ($params)) {
496         for ($j = 0; $j <= $#$params; $j += 2) {
497             my $param_name = $$params[$j];
498             my $param_desc = $$params[$j + 1];
500             if ($param_name eq $param_to_output) {
501                 $param_desc =~ s/\s+$//;
502                 $$params[$j] = "";
503                 $$params[$j + 1] = "";
504                 return "\@$param_name: $param_desc\n";
505             }
506         }
507     }
509     # If the template was already in a file, flag the new parameter.
510     # If not, the template itself will be flagged, so we don't need to flag
511     # all the new parameters as well.
512     if ($force_output) {
513         if ($default_description ne "") {
514             $default_description =~ s/\s+$//;
515             return "\@$param_to_output: $default_description\n";
516         } else {
517             if ($template_exists) {
518                 return "\@$param_to_output: $CHANGES_FLAG\n";
519             } else {
520                 return "\@$param_to_output: \n";
521             }
522         }
523     }
524     return "";
528 #############################################################################
529 # Function    : OutputOldParams
530 # Description : This returns all the existing documentation for parameters of
531 #                the given function/macro/signal symbol which are unused, with
532 #                a comment before them.
533 # Arguments   : $symbol - the symbol (function/macro/signal) name.
534 #############################################################################
536 sub OutputOldParams {
537     my ($symbol) = @_;
538     my $output = "";
540     my ($params) = $SymbolParams{$symbol};
541     if (defined ($params)) {
542         my $j;
543         for ($j = 0; $j <= $#$params; $j += 2) {
544             my $param_name = $$params[$j];
545             my $param_desc = $$params[$j + 1];
547             if ($param_name ne "") {
548                 $param_desc =~ s/\s+$//;
550                 # There's no point keeping it if it has no docs.
551                 if ($param_desc ne "") {
552                   $output .= "\@$param_name: $param_desc\n";
553                 }
554             }
555         }
556     }
557     if ($output) {
558         $output = "<!-- # Unused Parameters # -->\n" . $output;
559     }
560     return $output;
564 #############################################################################
565 # Function    : OutputTemplateFile
566 # Description : This outputs one template file.
567 # Arguments   : $file - the basename of the file to output.
568 #                $title - the title from the $MODULE-sections.txt file. This
569 #                  will be overridden by any title given in the template file.
570 #                $output - reference to the templates to output.
571 #############################################################################
573 sub OutputTemplateFile {
574     my ($file, $title, $output) = @_;
576     my ($short_desc, $long_desc, $see_also, $stability, $image);
578     if (defined ($SymbolDocs{"$TMPL_DIR/$file:Title"})) {
579         $title = $SymbolDocs{"$TMPL_DIR/$file:Title"};
580         delete $SymbolDocs{"$TMPL_DIR/$file:Title"};
581     }
582     if (defined ($SymbolDocs{"$TMPL_DIR/$file:Short_Description"})) {
583         $short_desc = $SymbolDocs{"$TMPL_DIR/$file:Short_Description"};
584         delete $SymbolDocs{"$TMPL_DIR/$file:Short_Description"};
585     } else {
586         $short_desc = "";
587     }
588     if (defined ($SymbolDocs{"$TMPL_DIR/$file:Long_Description"})) {
589         $long_desc = $SymbolDocs{"$TMPL_DIR/$file:Long_Description"};
590         delete $SymbolDocs{"$TMPL_DIR/$file:Long_Description"};
591     } else {
592         $long_desc = "<para>\n\n</para>\n";
593     }
594     if (defined ($SymbolDocs{"$TMPL_DIR/$file:See_Also"})) {
595         $see_also = $SymbolDocs{"$TMPL_DIR/$file:See_Also"};
596         delete $SymbolDocs{"$TMPL_DIR/$file:See_Also"};
597     } else {
598         $see_also = "<para>\n\n</para>\n";
599     }
600     if (defined ($SymbolDocs{"$TMPL_DIR/$file:Stability_Level"})) {
601         $stability = $SymbolDocs{"$TMPL_DIR/$file:Stability_Level"};
602         delete $SymbolDocs{"$TMPL_DIR/$file:Stability_Level"};
603     } else {
604         $stability = "";
605     }
606     if (defined ($SymbolDocs{"$TMPL_DIR/$file:Image"})) {
607         $image = $SymbolDocs{"$TMPL_DIR/$file:Image"};
608         delete $SymbolDocs{"$TMPL_DIR/$file:Image"};
609     } else {
610         $image = "";
611     }
614     my $old_tmpl_file = "$TMPL_DIR/$file";
615     my $new_tmpl_file = "$TMPL_DIR/$file.new";
617     open (OUTPUT, ">$new_tmpl_file")
618         || die "Can't create $new_tmpl_file";
620     print (OUTPUT <<EOF);
621 <!-- ##### SECTION Title ##### -->
622 $title
624 <!-- ##### SECTION Short_Description ##### -->
625 $short_desc
627 <!-- ##### SECTION Long_Description ##### -->
628 $long_desc
630 <!-- ##### SECTION See_Also ##### -->
631 $see_also
633 <!-- ##### SECTION Stability_Level ##### -->
634 $stability
636 <!-- ##### SECTION Image ##### -->
637 $image
641     print (OUTPUT $$output) unless $ONLY_SECTION_TMPL;
642     close (OUTPUT);
644     return &UpdateFileIfChanged ($old_tmpl_file, $new_tmpl_file, 1);
648 #############################################################################
649 # Function    : OutputSignalTemplates
650 # Description : Outputs templates for signal handlers.
651 # Arguments   : $title - the title from the $MODULE-sections.txt file. If the
652 #                  file is describing a GtkObject subclass, the title should
653 #                  be the name of the class, e.g. 'GtkButton'.
654 #############################################################################
656 sub OutputSignalTemplates {
657     my ($title) = @_;
659     my $output = "";
660     my ($i, $template_exists);
661     for ($i = 0; $i <= $#SignalObjects; $i++) {
662         if ($SignalObjects[$i] eq $title) {
663 #            print "Found signal: $SignalObjects[$i]\n";
664             my ($symbol) = "$SignalObjects[$i]::$SignalNames[$i]";
666             # See if symbol already has a description.
667             my ($symbol_desc) = $SymbolDocs{$symbol};
668             if (defined ($symbol_desc)) {
669                 $template_exists = 1;
670                 $symbol_desc =~ s/\s+$//;
671                 delete $SymbolDocs{$symbol};
672             } else {
673                 $template_exists = 0;
674                 $symbol_desc = "<para>\n$CHANGES_FLAG\n</para>";
675             }
677             $output .= <<EOF;
678 <!-- ##### SIGNAL $symbol ##### -->
679 $symbol_desc
682             my $sourceparams = $SymbolParams{$symbol};
683             my @params = split ("[,\n]", $SignalPrototypes[$i]);
684             my ($j, $name);
685             for ($j = 0; $j <= $#params; $j++) {
686                 my $param = $params[$j];
687                 $param =~ s/^\s+//;
688                 $param =~ s/\s*$//;
689                 if ($param =~ m/^\s*$/) { next; }
690                 if ($param =~ m/^void$/) { next; }
692                 if ($param =~ m/^\s*(\w+)\s*(\**)\s*([\w\[\]]+)?\s*$/) {
693                     if (defined ($sourceparams)) {
694                         $name = $$sourceparams[2 * $j];
695                     } else {
696                         $name = $3;
697                     }
699                     if (!defined ($name)) {
700                         $name = "Param" . ($j + 1);
701                     }
703                     if ($j == 0) {
704                         $output .= &OutputParam ($symbol, $name,
705                                                  $template_exists, 1,
706                                                  "the object which received the signal.");
707                     } else {
708                         $output .= &OutputParam ($symbol, $name,
709                                                  $template_exists, 1, "");
710                     }
711                 }
712             }
714             if ($SignalReturns[$i] ne "void") {
715                 $output .= &OutputParam ($symbol, "Returns", $template_exists,
716                                          1, "");
717             }
718             $output .= &OutputOldParams ($symbol);
719             $output .= "\n";
720         }
721     }
722     return $output;
726 #############################################################################
727 # Function    : OutputArgTemplates
728 # Description : Outputs templates for Args.
729 # Arguments   : $title - the title from the $MODULE-sections.txt file. If the
730 #                  file is describing a GtkObject subclass, the title should
731 #                  be the name of the class, e.g. 'GtkButton'.
732 #############################################################################
734 sub OutputArgTemplates {
735     my ($title) = @_;
737     my $output = "";
738     my $i;
739     for ($i = 0; $i <= $#ArgObjects; $i++) {
740         if ($ArgObjects[$i] eq $title) {
741 #            print "Found arg: $ArgObjects[$i]\n";
742             # I've only used one colon so we don't clash with signals.
743             my ($symbol) = "$ArgObjects[$i]:$ArgNames[$i]";
745             # See if symbol already has a description.
746             my ($symbol_desc) = $SymbolDocs{$symbol};
747             if (defined ($symbol_desc)) {
748                 delete $SymbolDocs{$symbol};
749                 $symbol_desc =~ s/\s+$//;
750             } else {
751                 $symbol_desc = "<para>\n$CHANGES_FLAG\n</para>";
752             }
754             $output .= <<EOF;
755 <!-- ##### ARG $symbol ##### -->
756 $symbol_desc
759         }
760     }
761     return $output;
765 #############################################################################
766 # Function    : OutputUnusedTemplates
767 # Description : This saves any unused documentation into $MODULE-unused.sgml.
768 # Arguments   : none
769 #############################################################################
771 sub OutputUnusedTemplates {
772     my ($old_unused_file) = "$TMPL_DIR/$MODULE-unused.sgml";
773     my ($new_unused_file) = "$TMPL_DIR/$MODULE-unused.new";
775     open (UNUSED, ">$new_unused_file")
776         || die "Can't open file: $new_unused_file";
778     my $output = "";
779     my ($symbol, $symbol_desc);
780     for $symbol (sort keys %SymbolDocs) {
781         $symbol_desc = $SymbolDocs{$symbol};
783 #        print "Unused: $symbol\n";
785         my $type = $SymbolTypes{$symbol};
786         if (!defined ($type)) {
787             $type = "UNKNOWN";
788             &LogWarning ($SymbolSourceFile{$symbol},$SymbolSourceLine{$symbol}, "Unused symbol $symbol has unknown type.");
789         }
791     $output .= <<EOF;
792 <!-- ##### $type $symbol ##### -->
793 $symbol_desc
797         my ($params) = $SymbolParams{$symbol};
798         if (defined ($params)) {
799             my $j;
800             for ($j = 0; $j <= $#$params; $j += 2) {
801                 my $param_name = $$params[$j];
802                 my $param_desc = $$params[$j + 1];
803                 $param_desc =~ s/\s+$//;
804                 $output .= "\@$param_name: $param_desc\n";
805             }
806         }
807         $output .= "\n";
808     }
810     print UNUSED $output;
811     close (UNUSED);
813     &UpdateFileIfChanged ($old_unused_file, $new_unused_file, 1);
817 #############################################################################
818 # LIBRARY FUNCTIONS -        These functions are used in both gtkdoc-mkdb and
819 #                        gtkdoc-mktmpl and should eventually be moved to a
820 #                        separate library.
821 #############################################################################
823 #############################################################################
824 # Function    : ReadDeclarationsFile
825 # Description : This reads in a file containing the function/macro/enum etc.
826 #                declarations.
828 #                Note that in some cases there are several declarations with
829 #                the same name, e.g. for conditional macros. In this case we
830 #                set a flag in the %DeclarationConditional hash so the
831 #                declaration is not shown in the docs.
833 #                If a macro and a function have the same name, e.g. for
834 #                gtk_object_ref, the function declaration takes precedence.
836 #                Some opaque structs are just declared with 'typedef struct
837 #                _name name;' in which case the declaration may be empty.
838 #                The structure may have been found later in the header, so
839 #                that overrides the empty declaration.
841 # Arguments   : $file - the declarations file to read
842 #                $override - if declarations in this file should override
843 #                        any current declaration.
844 #############################################################################
846 sub ReadDeclarationsFile {
847     my ($file, $override) = @_;
849     if ($override == 0) {
850         %Declarations = ();
851         %DeclarationTypes = ();
852         %DeclarationConditional = ();
853         %DeclarationOutput = ();
854     }
856     open (INPUT, $file)
857         || die "Can't open $file";
858     my $declaration_type = "";
859     my $declaration_name;
860     my $declaration;
861     while (<INPUT>) {
862         if (!$declaration_type) {
863             if (m/^<([^>]+)>/) {
864                 $declaration_type = $1;
865                 $declaration_name = "";
866 #                print "Found declaration: $declaration_type\n";
867                 $declaration = "";
868             }
869         } else {
870             if (m%^<NAME>(.*)</NAME>%) {
871                 $declaration_name = $1;
872             } elsif (m%<DEPRECATED/>%) {
873                 # do nothing, just skip the line; we handle this
874                 # in mkdb
875             } elsif (m%^</$declaration_type>%) {
876 #                print "Found end of declaration: $declaration_name\n";
877                 # Check that the declaration has a name
878                 if ($declaration_name eq "") {
879                     print "ERROR: $declaration_type has no name $file:$.\n";
880                 }
882                 # Check if the symbol is already defined.
883                 if (defined ($Declarations{$declaration_name})
884                     && $override == 0) {
885                     # Function declarations take precedence.
886                     if ($DeclarationTypes{$declaration_name} eq 'FUNCTION') {
887                         # Ignore it.
888                     } elsif ($declaration_type eq 'FUNCTION') {
889                         $Declarations{$declaration_name} = $declaration;
890                         $DeclarationTypes{$declaration_name} = $declaration_type;
891                     } elsif ($DeclarationTypes{$declaration_name}
892                               eq $declaration_type) {
893                         # If the existing declaration is empty, or is just a
894                         # forward declaration of a struct, override it.
895                         if ($declaration_type eq 'STRUCT') {
896                             if ($Declarations{$declaration_name} =~ m/^\s*(struct\s+\w+\s*;)?\s*$/) {
897                                 $Declarations{$declaration_name} = $declaration;
898                             } elsif ($declaration =~ m/^\s*(struct\s+\w+\s*;)?\s*$/) {
899                                 # Ignore an empty or forward declaration.
900                             } else {
901                                 &LogWarning ($file, $., "Structure $declaration_name has multiple definitions.");
902                             }
904                         } else {
905                             # set flag in %DeclarationConditional hash for
906                             # multiply defined macros/typedefs.
907                             $DeclarationConditional{$declaration_name} = 1;
908                         }
909                     } else {
910                         &LogWarning ($file, $., "$declaration_name has multiple definitions.");
911                     }
912                 } else {
913                     $Declarations{$declaration_name} = $declaration;
914                     $DeclarationTypes{$declaration_name} = $declaration_type;
915                 }
916                 $declaration_type = "";
917             } else {
918                 $declaration .= $_;
919             }
920         }
921     }
922     close (INPUT);
926 #############################################################################
927 # Function    : ReadSignalsFile
928 # Description : This reads in an existing file which contains information on
929 #                all GObject signals. It creates the arrays @SignalNames and
930 #                @SignalPrototypes containing info on the signals. The first
931 #                line of the SignalPrototype is the return type of the signal
932 #                handler. The remaining lines are the parameters passed to it.
933 #                The last parameter, "gpointer user_data" is always the same
934 #                so is not included.
935 # Arguments   : $file - the file containing the signal handler prototype
936 #                        information.
937 #############################################################################
939 sub ReadSignalsFile {
940     my ($file) = @_;
942     my $in_signal = 0;
943     my $signal_object;
944     my $signal_name;
945     my $signal_returns;
946     my $signal_flags;
947     my $signal_prototype;
949     # Reset the signal info.
950     @SignalObjects = ();
951     @SignalNames = ();
952     @SignalReturns = ();
953     @SignalFlags = ();
954     @SignalPrototypes = ();
956     if (! -f $file) {
957         return;
958     }
959     if (!open (INPUT, $file)) {
960         warn "Can't open $file - skipping signals\n";
961         return;
962     }
963     while (<INPUT>) {
964         if (!$in_signal) {
965             if (m/^<SIGNAL>/) {
966                 $in_signal = 1;
967                 $signal_object = "";
968                 $signal_name = "";
969                 $signal_returns = "";
970                 $signal_prototype = "";
971             }
972         } else {
973             if (m/^<NAME>(.*)<\/NAME>/) {
974                 $signal_name = $1;
975                 if ($signal_name =~ m/^(.*)::(.*)$/) {
976                     $signal_object = $1;
977                     ($signal_name = $2) =~ s/_/-/g;
978 #                    print "Found signal: $signal_name\n";
979                 } else {
980                     print "Invalid signal name: $signal_name\n";
981                 }
982             } elsif (m/^<RETURNS>(.*)<\/RETURNS>/) {
983                 $signal_returns = $1;
984             } elsif (m/^<FLAGS>(.*)<\/FLAGS>/) {
985                 $signal_flags = $1;
986             } elsif (m%^</SIGNAL>%) {
987 #                print "Found end of signal: ${signal_object}::${signal_name}\nReturns: ${signal_returns}\n${signal_prototype}";
988                 push (@SignalObjects, $signal_object);
989                 push (@SignalNames, $signal_name);
990                 push (@SignalReturns, $signal_returns);
991                 push (@SignalFlags, $signal_flags);
992                 push (@SignalPrototypes, $signal_prototype);
993                 $in_signal = 0;
994             } else {
995                 $signal_prototype .= $_;
996             }
997         }
998     }
999     close (INPUT);
1003 #############################################################################
1004 # Function    : ReadTemplateFile
1005 # Description : This reads in the manually-edited documentation file
1006 #                corresponding to the file currently being created, so we can
1007 #                insert the documentation at the appropriate places.
1008 #                It outputs %SymbolTypes, %SymbolDocs and %SymbolParams, which
1009 #                is a hash of arrays.
1010 #                NOTE: This function is duplicated in gtkdoc-mkdb (but
1011 #                slightly different).
1012 # Arguments   : $docsfile - the template file to read in.
1013 #                $skip_unused_params - 1 if the unused parameters should be
1014 #                        skipped.
1015 #############################################################################
1017 sub ReadTemplateFile {
1018     my ($docsfile, $skip_unused_params) = @_;
1020 #    print "Reading $docsfile\n";
1021     if (! -f $docsfile) {
1022         print "File doesn't exist: $docsfile\n";
1023         return 0;
1024     }
1026     my $CurrentType = "";         # Type of symbol being read.
1027     my $CurrentSymbol = "";        # Name of symbol being read.
1028     my $SymbolDoc = "";                # Description of symbol being read.
1029     my @Params;                        # Parameter names and descriptions of current
1030                                 #   function/macro/function typedef.
1031     my $CurrentParam = -1;        # Index of parameter currently being read.
1032                                 #   Note that the param array contains pairs
1033                                 #   of param name & description.
1034     my $InUnusedParameters = 0;        # True if we are reading in the unused params.
1036     open (DOCS, $docsfile)
1037         || die "Can't open file $docsfile: $!";
1038     while (<DOCS>) {
1039         if (m/^<!-- ##### ([A-Z_]+) (\S+) ##### -->/) {
1040             my $type = $1;
1041             my $symbol = $2;
1042             if ($symbol eq "Title"
1043                 || $symbol eq "Short_Description"
1044                 || $symbol eq "Long_Description"
1045                 || $symbol eq "See_Also"
1046                 || $symbol eq "Stability_Level"
1047                 || $symbol eq "Image") {
1048                 $symbol = $docsfile . ":" . $symbol;
1049             }
1051             #print "Found symbol: $symbol\n";
1052             # Remember file and line for the symbol
1053             $SymbolSourceFile{$symbol} = $docsfile;
1054             $SymbolSourceLine{$symbol} = $.;
1056             # Canonicalize signal and argument names to have -, not _
1057             if ($type eq "ARG" || $type eq "SIGNAL") {
1058               $symbol =~ s/_/-/g;
1059             }
1061             # Store previous symbol, but remove any trailing blank lines.
1062             if ($CurrentSymbol ne "") {
1063                 $SymbolDoc =~ s/\s+$//;
1064                 $SymbolTypes{$CurrentSymbol} = $CurrentType;
1065                 $SymbolDocs{$CurrentSymbol} = $SymbolDoc;
1067                 if ($CurrentParam >= 0) {
1068                     $SymbolParams{$CurrentSymbol} = [ @Params ];
1069                 } else {
1070                     # Delete any existing params in case we are overriding a
1071                     # previously read template.
1072                     delete $SymbolParams{$CurrentSymbol};
1073                 }
1074             }
1075             $CurrentType = $type;
1076             $CurrentSymbol = $symbol;
1077             $CurrentParam = -1;
1078             $InUnusedParameters = 0;
1079             $SymbolDoc = "";
1080             @Params = ();
1082         } elsif (m/^<!-- # Unused Parameters # -->/) {
1083             $InUnusedParameters = 1;
1084             next;
1086         } else {
1087             # Workaround for an old bug that left a mess in the templates.
1088             # This happened with macros with args spread over several lines.
1089             if (m/^\@\\$/) {
1090               # Skip the next line.
1091               $_ = <DOCS>;
1092               next;
1093             }
1095             # Workaround for an old bug that left '@:' at start of lines.
1096             if (m/^\@:$/) {
1097               next;
1098             }
1101             # Check if param found. Need to handle "..." and "format...".
1102             if (s/^\@([\w\.]+):\040?//) {
1103                 my $param_name = $1;
1104                 # Allow variations of 'Returns'
1105                 if ($param_name =~ m/^[Rr]eturns?$/) {
1106                     $param_name = "Returns";
1107                 }
1108 #                print "Found param: $param_name\n";
1109                 push (@Params, $param_name);
1110                 push (@Params, $_);
1111                 $CurrentParam += 2;
1112                 next;
1113             }
1115             # When outputting the DocBook we skip unused parameters.
1116             if (!$InUnusedParameters || !$skip_unused_params) {
1117                 if ($CurrentParam >= 0) {
1118                     $Params[$CurrentParam] .= $_;
1119                 } else {
1120                     $SymbolDoc .= $_;
1121                 }
1122             }
1123         }
1124     }
1126     # Remember to finish the current symbol doccs.
1127     if ($CurrentSymbol ne "") {
1129         $SymbolDoc =~ s/\s+$//;
1130         $SymbolTypes{$CurrentSymbol} = $CurrentType;
1131         $SymbolDocs{$CurrentSymbol} = $SymbolDoc;
1133         if ($CurrentParam >= 0) {
1134             $SymbolParams{$CurrentSymbol} = [ @Params ];
1135         } else {
1136             delete $SymbolParams{$CurrentSymbol};
1137         }
1138     }
1140     close (DOCS);
1141     return 1;
1145 #############################################################################
1146 # Function    : ReadObjectHierarchy
1147 # Description : This reads in the $MODULE-hierarchy.txt file containing all
1148 #                the GtkObject subclasses described in this module (and their
1149 #                ancestors).
1150 #                It places them in the @Objects array, and places their level
1151 #                in the widget hierarchy in the @ObjectLevels array, at the
1152 #                same index. GtkObject, the root object, has a level of 1.
1154 #               FIXME: the version in gtkdoc-mkdb also generates tree_index.sgml
1155 #               as it goes along, this should be split out into a separate
1156 #               function.
1158 # Arguments   : none
1159 #############################################################################
1161 sub ReadObjectHierarchy {
1162     @Objects = ();
1163     @ObjectLevels = ();
1165     if (! -f $OBJECT_TREE_FILE) {
1166         return;
1167     }
1168     if (!open (INPUT, $OBJECT_TREE_FILE)) {
1169         warn "Can't open $OBJECT_TREE_FILE - skipping object tree\n";
1170         return;
1171     }
1172     while (<INPUT>) {
1173         if (m/\S+/) {
1174             my $object = $&;
1175             my $level = (length($`)) / 2 + 1;
1176 #            print ("Level: $level  Object: $object\n");
1178             push (@Objects, $object);
1179             push (@ObjectLevels, $level);
1180         }
1181     }
1183     close (INPUT);
1187 #############################################################################
1188 # Function    : ReadArgsFile
1189 # Description : This reads in an existing file which contains information on
1190 #                all GObject args. It creates the arrays @ArgObjects, @ArgNames,
1191 #                @ArgTypes and @ArgFlags containing info on the args.
1192 # Arguments   : $file - the file containing the arg information.
1193 #############################################################################
1195 sub ReadArgsFile {
1196     my ($file) = @_;
1198     my $in_arg = 0;
1199     my $arg_object;
1200     my $arg_name;
1201     my $arg_type;
1202     my $arg_flags;
1204     # Reset the signal info.
1205     @ArgObjects = ();
1206     @ArgNames = ();
1207     @ArgTypes = ();
1208     @ArgFlags = ();
1210     if (! -f $file) {
1211         return;
1212     }
1213     if (!open (INPUT, $file)) {
1214         warn "Can't open $file - skipping args\n";
1215         return;
1216     }
1217     while (<INPUT>) {
1218         if (!$in_arg) {
1219             if (m/^<ARG>/) {
1220                 $in_arg = 1;
1221                 $arg_object = "";
1222                 $arg_name = "";
1223                 $arg_type = "";
1224                 $arg_flags = "";
1225             }
1226         } else {
1227             if (m/^<NAME>(.*)<\/NAME>/) {
1228                 $arg_name = $1;
1229                 if ($arg_name =~ m/^(.*)::(.*)$/) {
1230                     $arg_object = $1;
1231                     ($arg_name = $2) =~ s/_/-/g;
1232 #                    print "Found arg: $arg_name\n";
1233                 } else {
1234                     print "Invalid arg name: $arg_name\n";
1235                 }
1236             } elsif (m/^<TYPE>(.*)<\/TYPE>/) {
1237                 $arg_type = $1;
1238             } elsif (m/^<FLAGS>(.*)<\/FLAGS>/) {
1239                 $arg_flags = $1;
1240             } elsif (m%^</ARG>%) {
1241 #                print "Found end of arg: ${arg_object}::${arg_name}\n${arg_type} : ${arg_flags}\n";
1242                 push (@ArgObjects, $arg_object);
1243                 push (@ArgNames, $arg_name);
1244                 push (@ArgTypes, $arg_type);
1245                 push (@ArgFlags, $arg_flags);
1246                 $in_arg = 0;
1247             }
1248         }
1249     }
1250     close (INPUT);
1254 #############################################################################
1255 # Function    : CheckIsObject
1256 # Description : Returns 1 if the given name is a GObject or a subclass.
1257 #                It uses the global @Objects array.
1258 #                Note that the @Objects array only contains classes in the
1259 #                current module and their ancestors - not all GObject classes.
1260 # Arguments   : $name - the name to check.
1261 #############################################################################
1263 sub CheckIsObject {
1264     my ($name) = @_;
1266     my $object;
1267     foreach $object (@Objects) {
1268         if ($object eq $name) {
1269             return 1;
1270         }
1271     }
1272     return 0;