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