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

Revision 20745, 96.1 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20744, which included commits to RCS files with non-trunk default branches.
  • Property svn:executable set to *
Line 
1#!@PERL@ -w
2# -*- cperl -*-
3#
4# gtk-doc - GTK DocBook documentation generator.
5# Copyright (C) 1998  Damon Chaplin
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20#
21
22#############################################################################
23# Script      : gtkdoc-mkdb
24# Description : This creates the DocBook files from the edited templates.
25#
26#               NOTE: When creating SGML IDS, we append -CAPS to all
27#               all-caps identifiers to prevent name clashes. (It basically
28#               never is the case that mixed-case identifiers would collide.)
29#               See the CreateValidSGMLID function.
30#############################################################################
31
32use strict;
33use Getopt::Long;
34
35unshift @INC, "@PACKAGE_DATA_DIR@";
36require "gtkdoc-common.pl";
37
38# Options
39
40# name of documentation module
41my $MODULE;
42my $TMPL_DIR;
43my $SGML_OUTPUT_DIR;
44my @SOURCE_DIRS;
45my $IGNORE_FILES = "";
46my $PRINT_VERSION;
47my $PRINT_HELP;
48my $OUTPUT_ALL_SYMBOLS;
49my $MAIN_SGML_FILE;
50my $SGML_MODE;
51my $OUTPUT_FORMAT;
52
53my %optctl = (module => \$MODULE,
54              'source-dir' => \@SOURCE_DIRS,
55              'ignore-files' => \$IGNORE_FILES,
56              'output-dir' => \$SGML_OUTPUT_DIR,
57              'tmpl-dir' => \$TMPL_DIR,
58              'version' => \$PRINT_VERSION,
59              'help' => \$PRINT_HELP,
60              'main-sgml-file' => \$MAIN_SGML_FILE,
61              'outputallsymbols' => \$OUTPUT_ALL_SYMBOLS,
62              'sgml-mode' => \$SGML_MODE,
63              'output-format' => \$OUTPUT_FORMAT);
64GetOptions(\%optctl, "module=s", "source-dir:s", "ignore-files:s", "output-dir:s", "tmpl-dir:s", "version", "outputallsymbols", "main-sgml-file:s", "help", "sgml-mode", "output-format:s");
65
66if ($PRINT_VERSION) {
67    print "@VERSION@\n";
68    exit 0;
69}
70
71if (!$MODULE) {
72    $PRINT_HELP = 1;
73}
74
75if ($PRINT_HELP) {
76    print "gtkdoc-mkdb version @VERSION@\n";
77    print "\n--module=MODULE_NAME   Name of the doc module being parsed";
78    print "\n--source-dir=DIRNAME   Directories which contain inline reference material";
79    print "\n--ignore-files=FILES   Files or directories which should not be scanned";
80    print "\n                       May be used more than once for multiple directories";
81    print "\n--output-dir=DIRNAME   Directory to put the generated Docbook files in";
82    print "\n--tmpl-dir=DIRNAME     Directory in which template files may be found";
83    print "\n--main-sgml-file=FILE  File containing the toplevel SGML file.";
84    print "\n--output-format=FORMAT The format to use for the generated docbook, XML or SGML.";
85    print "\n--sgml-mode            Allow Docbook markup in inline documentation.";
86    print "\n--version              Print the version of this program";
87    print "\n--help                 Print this help\n";
88    exit 0;
89}
90
91if (!$MAIN_SGML_FILE) {
92    $MAIN_SGML_FILE="${MODULE}-docs.sgml";
93}
94
95my ($empty_element_end, $doctype_header);
96
97if (lc($OUTPUT_FORMAT) eq "xml") {
98    $OUTPUT_FORMAT = "xml";
99    $empty_element_end = "/>";
100
101    if ($MAIN_SGML_FILE && -e $MAIN_SGML_FILE) {
102        open(INPUT, "<$MAIN_SGML_FILE") || die "Can't open $MAIN_SGML_FILE";
103        $doctype_header = "";
104        while (<INPUT>) {
105            if (/^\s*<(book|chapter|article)/) {
106                if ($_ !~ m/http:\/\/www.w3.org\/200[13]\/XInclude/) {
107                    $doctype_header = "";
108                }
109                last;
110            }
111            $doctype_header .= $_;
112        }
113        close(INPUT);
114    } else {
115        $doctype_header =
116"<?xml version=\"1.0\"?>\n" .
117"<!DOCTYPE book PUBLIC \"-//OASIS//DTD DocBook XML V4.1.2//EN\"\n" .
118"               \"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd\">\n";
119    }
120    $doctype_header =~ s/<!DOCTYPE \w+/<!DOCTYPE refentry/;
121  } else {
122    $OUTPUT_FORMAT = "sgml";
123    $doctype_header = "";
124    $empty_element_end = ">";
125}
126
127my $ROOT_DIR = ".";
128
129# All the files are written in subdirectories beneath here.
130$TMPL_DIR = $TMPL_DIR ? $TMPL_DIR : "$ROOT_DIR/tmpl";
131
132# This is where we put all the DocBook output.
133$SGML_OUTPUT_DIR = $SGML_OUTPUT_DIR ? $SGML_OUTPUT_DIR : "$ROOT_DIR/$OUTPUT_FORMAT";
134
135# This file contains the object hierarchy.
136my $OBJECT_TREE_FILE = "$ROOT_DIR/$MODULE.hierarchy";
137
138# This file contains the interfaces.
139my $INTERFACES_FILE = "$ROOT_DIR/$MODULE.interfaces";
140
141# This file contains the prerequisites.
142my $PREREQUISITES_FILE = "$ROOT_DIR/$MODULE.prerequisites";
143
144# This file contains signal arguments and names.
145my $SIGNALS_FILE = "$ROOT_DIR/$MODULE.signals";
146
147# The file containing Arg information.
148my $ARGS_FILE = "$ROOT_DIR/$MODULE.args";
149
150# These global arrays store information on signals. Each signal has an entry
151# in each of these arrays at the same index, like a multi-dimensional array.
152my @SignalObjects;      # The GtkObject which emits the signal.
153my @SignalNames;        # The signal name.
154my @SignalReturns;      # The return type.
155my @SignalPrototypes;   # The rest of the prototype of the signal handler.
156
157# These global arrays store information on Args. Each Arg has an entry
158# in each of these arrays at the same index, like a multi-dimensional array.
159my @ArgObjects;         # The GtkObject which has the Arg.
160my @ArgNames;           # The Arg name.
161my @ArgTypes;           # The Arg type - gint, GtkArrowType etc.
162my @ArgFlags;           # How the Arg can be used - readable/writable etc.
163my @ArgNicks;           # The nickname of the Arg.
164my @ArgBlurbs;          # Docstring of the Arg.
165# These global hashes store declaration info keyed on a symbol name.
166my %Declarations;
167my %DeclarationTypes;
168my %DeclarationConditional;
169my %DeclarationOutput;
170my %Deprecated;
171my %Since;
172
173# These global hashes store the existing documentation.
174my %SymbolDocs;
175my %SymbolTypes;
176my %SymbolParams;
177
178# These global hashes store documentation scanned from the source files.
179my %SourceSymbolDocs;
180my %SourceSymbolParams;
181
182# all documentation goes in here, so we can do coverage analysis
183my %AllSymbols;
184my %AllDocumentedSymbols;
185
186# These global arrays store GtkObject and subclasses and the hierarchy.
187my @Objects;
188my @ObjectLevels;
189
190my %Interfaces;
191my %Prerequisites;
192
193# Create the root DocBook output directory if it doens't exist.
194if (! -e $SGML_OUTPUT_DIR) {
195    mkdir ("$SGML_OUTPUT_DIR", 0777)
196        || die "Can't create directory: $SGML_OUTPUT_DIR";
197}
198
199# Function and other declaration output settings.
200my $RETURN_TYPE_FIELD_WIDTH = 12;
201my $SYMBOL_FIELD_WIDTH = 32;
202my $SIGNAL_FIELD_WIDTH = 12;
203
204&ReadSignalsFile ($SIGNALS_FILE);
205&ReadArgsFile ($ARGS_FILE);
206&ReadObjectHierarchy;
207&ReadInterfaces;
208&ReadPrerequisites;
209
210# FIXME: this is the header file output at the top of the Synopsis.
211# We should allow this to be changed in the MODULE-sections.txt file.
212# gnome.h includes gtk/gtk.h which includes gdk/gdk.h which includes glib.h
213# so what should we output? - alternatives?
214my $HEADER_FILE = "";
215if ($MODULE eq 'glib') {
216    $HEADER_FILE = "glib.h";
217} elsif ($MODULE eq 'gdk') {
218    $HEADER_FILE = "gtk/gdk.h";
219} elsif ($MODULE eq 'gtk') {
220    $HEADER_FILE = "gtk/gtk.h";
221} elsif ($MODULE eq 'gnome' || $MODULE eq 'gnomeui') {
222    $HEADER_FILE = "gnome.h";
223}
224
225&ReadDeclarationsFile ("$ROOT_DIR/$MODULE-decl.txt", 0);
226if (-f "$ROOT_DIR/$MODULE-overrides.txt") {
227    &ReadDeclarationsFile ("$ROOT_DIR/$MODULE-overrides.txt", 1);
228}
229
230for my $dir (@SOURCE_DIRS) {
231    &ReadSourceDocumentation ($dir);
232}
233
234my $changed = &OutputSGML ("$ROOT_DIR/$MODULE-sections.txt");
235
236# If any of the DocBook SGML files have changed, update the timestamp file (so
237# it can be used for Makefile dependencies).
238if ($changed || ! -e "$ROOT_DIR/sgml.stamp") {
239    open (TIMESTAMP, ">$ROOT_DIR/sgml.stamp")
240        || die "Can't create $ROOT_DIR/sgml.stamp";
241    print (TIMESTAMP "timestamp");
242    close (TIMESTAMP);
243}
244
245#############################################################################
246# Function    : OutputObjectList
247# Description : This outputs the alphabetical list of objects, in a columned
248#               table. FIXME: Currently this also outputs ancestor objects
249#               which may not actually be in this module.
250# Arguments   : none
251#############################################################################
252
253sub OutputObjectList {
254    my $cols = 3;
255    my $old_object_index = "$SGML_OUTPUT_DIR/object_index.sgml";
256    my $new_object_index = "$SGML_OUTPUT_DIR/object_index.new";
257
258    open (OUTPUT, ">$new_object_index")
259        || die "Can't create $new_object_index";
260    print (OUTPUT <<EOF);
261<informaltable pgwide="1" frame="none">
262<tgroup cols="$cols">
263<colspec colwidth="1*"${empty_element_end}
264<colspec colwidth="1*"${empty_element_end}
265<colspec colwidth="1*"${empty_element_end}
266<tbody>
267EOF
268
269    my $count = 0;
270    my $object;
271    foreach $object (sort(@Objects)) {
272        my $xref = &MakeXRef ($object);
273        if ($count % $cols == 0) { print (OUTPUT "<row>\n"); }
274        print (OUTPUT "<entry>$xref</entry>\n");
275        if ($count % $cols == ($cols - 1)) { print (OUTPUT "</row>\n"); }
276        $count++;
277    }
278    if ($count == 0) {
279        # emit an empty row, since empty tables are invalid
280        print (OUTPUT "<row><entry> </entry></row>\n");
281    }
282
283    print (OUTPUT <<EOF);
284</tbody></tgroup></informaltable>
285EOF
286    close (OUTPUT);
287
288    &UpdateFileIfChanged ($old_object_index, $new_object_index, 0);
289}
290
291
292#############################################################################
293# Function    : OutputSGML
294# Description : This collects the output for each section of the docs, and
295#               outputs each file when the end of the section is found.
296# Arguments   : $file - the $MODULE-sections.txt file which contains all of
297#               the functions/macros/structs etc. being documented, organised
298#               into sections and subsections.
299#############################################################################
300
301sub OutputSGML {
302    my ($file) = @_;
303   
304#    print "Reading: $file\n";
305    open (INPUT, $file)
306        || die "Can't open $file";
307    my $book_top = "";
308    my $book_bottom = "";
309    my $includes = "";
310    my $section_includes = "";
311    my $in_section = 0;
312    my $title = "";
313    my $subsection = "";
314    my $synopsis;
315    my $details;
316    my $num_symbols;
317    my $changed = 0;
318    my $signals_synop = "";
319    my $signals_desc = "";
320    my $args_synop = "";
321    my $child_args_synop = "";
322    my $style_args_synop = "";
323    my $args_desc = "";
324    my $child_args_desc = "";
325    my $style_args_desc = "";
326    my $hierarchy = "";
327    my $interfaces = "";
328    my $implementations = "";
329    my $prerequisites = "";
330    my $derived = "";
331    my @file_objects = ();
332
333    while (<INPUT>) {
334        if (m/^#/) {
335            next;
336
337        } elsif (m/^<SECTION>/) {
338            $synopsis = "";
339            $details = "";
340            $num_symbols = 0;
341            $in_section = 1;
342            @file_objects = ();
343
344        } elsif (m/^<SUBSECTION\s*(.*)>/i) {
345            $synopsis .= "\n";
346            $subsection = $1;
347
348        } elsif (m/^<SUBSECTION>/) {
349
350        } elsif (m/^<TITLE>(.*)<\/TITLE>/) {
351            $title = $1;
352#           print "Section: $title\n";
353
354            # We don't want warnings if object & class structs aren't used.
355            $DeclarationOutput{$title} = 1;
356            $DeclarationOutput{"${title}Class"} = 1;
357
358        } elsif (m/^<FILE>(.*)<\/FILE>/) {
359            my $sym;
360
361            $file = $1;
362            %SymbolDocs = ();
363            %SymbolTypes = ();
364            %SymbolParams = ();
365            &ReadTemplateFile ("$TMPL_DIR/$file", 1);
366            &MergeSourceDocumentation;
367
368        } elsif (m/^<INCLUDE>(.*)<\/INCLUDE>/) {
369            if ($in_section) {
370                $section_includes = $1;
371            } else {
372                $includes = $1;
373            }
374
375        } elsif (m/^<\/SECTION>/) {
376            if ($title eq "") {
377                $title = $file;
378            }
379#           print "End of section: $title\n";
380
381            $file =~ s/\s/_/g;
382
383            # GtkObjects use their class name as the ID.
384            my $section_id;
385            if (&CheckIsObject ($title)) {
386                $section_id = &CreateValidSGMLID ($title);
387            } else {
388                $section_id = &CreateValidSGMLID ("$MODULE-$title");
389            }
390           
391            if ($num_symbols > 0) {
392                if (lc($OUTPUT_FORMAT) eq "xml") {
393                    $book_bottom .= "    <xi:include href=\"xml/$file.xml\"/>\n";
394                } else {
395                    $book_top.="<!ENTITY $section_id SYSTEM \"sgml/$file.sgml\">\n";
396                    $book_bottom .= "    &$section_id;\n";
397                }
398
399                if ($section_includes eq "") {
400                    $section_includes = $includes;
401                }
402
403                if ($signals_synop ne '') {
404                    $signals_synop = <<EOF;
405<refsect1>
406<title>Signal Prototypes</title>
407<synopsis>
408
409${signals_synop}</synopsis>
410</refsect1>
411EOF
412                    $signals_desc  = <<EOF;
413<refsect1>
414<title>Signals</title>
415$signals_desc
416</refsect1>
417EOF
418                }
419
420                if ($args_synop ne '') {
421                    $args_synop = <<EOF;
422<refsect1>
423<title>Properties</title>
424<synopsis>
425
426${args_synop}</synopsis>
427</refsect1>
428EOF
429                    $args_desc  = <<EOF;
430<refsect1>
431<title>Properties</title>
432<variablelist>
433$args_desc
434</variablelist>
435</refsect1>
436EOF
437                }
438
439                if ($child_args_synop ne '') {
440                    $args_synop .= <<EOF;
441<refsect1>
442<title>Child Properties</title>
443<synopsis>
444
445${child_args_synop}</synopsis>
446</refsect1>
447EOF
448                    $args_desc .= <<EOF;
449<refsect1>
450<title>Child Properties</title>
451<variablelist>
452$child_args_desc
453</variablelist>
454</refsect1>
455EOF
456                }
457
458                if ($style_args_synop ne '') {
459                    $args_synop .= <<EOF;
460<refsect1>
461<title>Style Properties</title>
462<synopsis>
463
464${style_args_synop}</synopsis>
465</refsect1>
466EOF
467                    $args_desc .= <<EOF;
468<refsect1>
469<title>Style Properties</title>
470<variablelist>
471$style_args_desc
472</variablelist>
473</refsect1>
474EOF
475                }
476
477                if ($hierarchy ne "") {
478                    $hierarchy = <<EOF;
479<refsect1>
480<title>Object Hierarchy</title>
481$hierarchy
482</refsect1>
483EOF
484                }
485
486                if ($interfaces ne "") {
487                    $interfaces = <<EOF;
488<refsect1>
489<title>Implemented Interfaces</title>
490$interfaces
491</refsect1>
492EOF
493                }
494
495                if ($implementations ne "") {
496                    $implementations = <<EOF;
497<refsect1>
498<title>Known Implementations</title>
499$implementations
500</refsect1>
501EOF
502                }
503
504                if ($prerequisites ne "") {
505                    $prerequisites = <<EOF;
506<refsect1>
507<title>Prerequisites</title>
508$prerequisites
509</refsect1>
510EOF
511                }
512
513                if ($derived ne "") {
514                    $derived = <<EOF;
515<refsect1>
516<title>Known Derived Interfaces</title>
517$derived
518</refsect1>
519EOF
520                }
521
522                my $file_changed = &OutputSGMLFile ($file, $title, $section_id,
523                                                    $section_includes,
524                                                    \$synopsis, \$details,
525                                                    \$signals_synop, \$signals_desc,
526                                                    \$args_synop, \$args_desc,
527                                                    \$hierarchy, \$interfaces,
528                                                    \$implementations,
529                                                    \$prerequisites, \$derived,
530                                                    \@file_objects);
531                if ($file_changed) {
532                    $changed = 1;
533                }
534            }
535            $title = "";
536            $subsection = "";
537            $in_section = 0;
538            $section_includes = "";
539            $signals_synop = "";
540            $signals_desc = "";
541            $args_synop = "";
542            $child_args_synop = "";
543            $style_args_synop = "";
544            $args_desc = "";
545            $child_args_desc = "";
546            $style_args_desc = "";
547            $hierarchy = "";
548            $interfaces = "";
549            $implementations = "";
550            $prerequisites = "";
551            $derived = "";
552
553        } elsif (m/^(\S+)/) {
554            my $symbol = $1;
555#           print "  Symbol: $symbol\n";
556
557            my $declaration = $Declarations{$symbol};
558            if (defined ($declaration)) {
559                # We don't want standard macros/functions of GtkObjects,
560                # or private declarations.
561                if ($subsection ne "Standard" && $subsection ne "Private") {
562                    if (&CheckIsObject ($symbol)) {
563                        push @file_objects, $symbol;
564                    }
565                    my ($synop, $desc) = &OutputDeclaration ($symbol,
566                                                             $declaration);
567                    my ($sig_synop, $sig_desc) = &GetSignals ($symbol);
568                    my ($arg_synop, $child_arg_synop, $style_arg_synop,
569                        $arg_desc, $child_arg_desc, $style_arg_desc) = &GetArgs ($symbol);
570                    my $hier = &GetHierarchy ($symbol);
571                    my $ifaces = &GetInterfaces ($symbol);
572                    my $impls = &GetImplementations ($symbol);
573                    my $prereqs = &GetPrerequisites ($symbol);
574                    my $der = &GetDerived ($symbol);
575                    $synopsis .= $synop;
576                    $details .= $desc;
577                    $signals_synop .= $sig_synop;
578                    $signals_desc .= $sig_desc;
579                    $args_synop .= $arg_synop;
580                    $child_args_synop .= $child_arg_synop;
581                    $style_args_synop .= $style_arg_synop;
582                    $args_desc .= $arg_desc;
583                    $child_args_desc .= $child_arg_desc;
584                    $style_args_desc .= $style_arg_desc;
585                    $hierarchy .= $hier;
586                    $interfaces .= $ifaces;
587                    $implementations .= $impls;
588                    $prerequisites .= $prereqs;
589                    $derived .= $der;
590                }
591
592                # Note that the declaration has been output.
593                $DeclarationOutput{$symbol} = 1;
594            } else {
595                print "WARNING: No declaration for: $1\n";
596            }
597            $num_symbols++;
598        }
599    }
600    close (INPUT);
601
602    &OutputMissingDocumentation;
603
604    if ($OUTPUT_ALL_SYMBOLS) {
605        &OutputAllSymbols;
606    }
607
608    &OutputBook ($book_top, $book_bottom);
609
610    return $changed;
611}
612
613
614#############################################################################
615# Function    : OutputDeclaration
616# Description : Returns the synopsis and detailed description DocBook
617#               describing one function/macro etc.
618# Arguments   : $symbol - the name of the function/macro begin described.
619#               $declaration - the declaration of the function/macro.
620#############################################################################
621
622sub OutputDeclaration {
623    my ($symbol, $declaration) = @_;
624
625    my $type = $DeclarationTypes {$symbol};
626    if ($type eq 'MACRO') {
627        return &OutputMacro ($symbol, $declaration);
628    } elsif ($type eq 'TYPEDEF') {
629        return &OutputTypedef ($symbol, $declaration);
630    } elsif ($type eq 'STRUCT') {
631        return &OutputStruct ($symbol, $declaration);
632    } elsif ($type eq 'ENUM') {
633        return &OutputEnum ($symbol, $declaration);
634    } elsif ($type eq 'UNION') {
635        return &OutputUnion ($symbol, $declaration);
636    } elsif ($type eq 'VARIABLE') {
637        return &OutputVariable ($symbol, $declaration);
638
639    } elsif ($type eq 'FUNCTION') {
640        return &OutputFunction ($symbol, $declaration, $type);
641    } elsif ($type eq 'USER_FUNCTION') {
642        return &OutputFunction ($symbol, $declaration, $type);
643    } else {
644        die "Unknown symbol type";
645    }
646}
647
648
649#############################################################################
650# Function    : OutputMacro
651# Description : Returns the synopsis and detailed description of a macro.
652# Arguments   : $symbol - the macro.
653#               $declaration - the declaration of the macro.
654#############################################################################
655
656sub OutputMacro {
657    my ($symbol, $declaration) = @_;
658    my $id = &CreateValidSGMLID ($symbol);
659    my $synop = "#define     <link linkend=\"$id\">$symbol</link>";
660    my $desc;
661    my $args = "";
662    if ($declaration =~ m/^\s*#\s*define\s+\w+(\([^\)]*\))/) {
663        $args = $1;
664
665        if (length ($symbol) < $SYMBOL_FIELD_WIDTH) {
666            $synop .= (' ' x ($SYMBOL_FIELD_WIDTH - length ($symbol)));
667        }
668
669        $synop .= &CreateValidSGML ($args);
670    }
671    $synop .= "\n";
672
673    if ($args ne "") {
674        $desc = "<refsect2>\n<title><anchor id=\"$id\"${empty_element_end}${symbol}()</title>\n";
675    } else {
676        $desc = "<refsect2>\n<title><anchor id=\"$id\"${empty_element_end}$symbol</title>\n";
677    }
678    $desc .= MakeIndexterms($symbol);
679
680    # Don't output the macro definition if is is a conditional macro or it
681    # looks like a function, i.e. starts with "g_" or "_?gnome_", or it is
682    # longer than 2 lines, otherwise we get lots of complicated macros like
683    # g_assert.
684    if (!defined ($DeclarationConditional{$symbol}) && ($symbol !~ m/^g_/)
685        && ($symbol !~ m/^_?gnome_/) && (($declaration =~ tr/\n//) < 2)) {
686        $declaration = &CreateValidSGML ($declaration);
687        $desc .= "<programlisting>$declaration</programlisting>\n";
688    } else {
689        $desc .= "<programlisting>#define     $symbol";
690        $desc .= &CreateValidSGML ($args);
691        $desc .= "</programlisting>\n";
692    }
693
694    $desc .= &MakeDeprecationNote($symbol);
695
696    if (defined ($SymbolDocs{$symbol})) {
697        $desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
698    }
699    $desc .= &OutputParamDescriptions ("MACRO", $symbol);
700    if (exists $Since{$symbol}) {
701        $desc .= "<para>Since $Since{$symbol}</para>";
702    }
703    $desc .= "</refsect2>\n";
704    return ($synop, $desc);
705}
706
707
708#############################################################################
709# Function    : OutputTypedef
710# Description : Returns the synopsis and detailed description of a typedef.
711# Arguments   : $symbol - the typedef.
712#               $declaration - the declaration of the typedef,
713#                 e.g. 'typedef unsigned int guint;'
714#############################################################################
715
716sub OutputTypedef {
717    my ($symbol, $declaration) = @_;
718    my $id = &CreateValidSGMLID ($symbol);
719    my $synop = "typedef     <link linkend=\"$id\">$symbol</link>;\n";
720    my $desc = "<refsect2>\n<title><anchor id=\"$id\"${empty_element_end}$symbol</title>\n";
721
722    $desc .= MakeIndexterms($symbol);
723
724    if (!defined ($DeclarationConditional{$symbol})) {
725        $declaration = &CreateValidSGML ($declaration);
726        $desc .= "<programlisting>$declaration</programlisting>\n";
727    }
728
729    $desc .= &MakeDeprecationNote($symbol);
730
731    if (defined ($SymbolDocs{$symbol})) {
732        $desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
733    }
734    if (exists $Since{$symbol}) {
735        $desc .= "<para>Since $Since{$symbol}</para>";
736    }
737    $desc .= "</refsect2>\n";
738    return ($synop, $desc);
739}
740
741
742#############################################################################
743# Function    : OutputStruct
744# Description : Returns the synopsis and detailed description of a struct.
745#               We check if it is a widget struct, and if so we only output
746#               parts of it that are noted as public fields.
747#               We also use a different SGML ID for widget structs, since the
748#               original ID is used for the entire RefEntry.
749# Arguments   : $symbol - the struct.
750#               $declaration - the declaration of the struct.
751#############################################################################
752
753sub OutputStruct {
754    my ($symbol, $declaration) = @_;
755
756    my $is_widget_struct = 0;
757    my $default_to_public = 1;
758    if (&CheckIsObject ($symbol)) {
759#       print "Found widget struct: $symbol\n";
760        $is_widget_struct = 1;
761        $default_to_public = 0;
762    }
763
764    my $id;
765    if ($is_widget_struct) {
766        $id = &CreateValidSGMLID ($symbol . "_struct");
767    } else {
768        $id = &CreateValidSGMLID ($symbol);
769    }
770    my $synop = "struct      <link linkend=\"$id\">$symbol</link>;\n";
771    my $desc = "<refsect2>\n<title><anchor id=\"$id\"${empty_element_end}struct $symbol</title>\n";
772
773    $desc .= MakeIndexterms($symbol);
774
775    # Form a pretty-printed, private-data-removed form of the declaration
776
777    my $decl_out;
778    if ($declaration =~ m/^\s*$/) {
779#       print "Found opaque struct\n";
780        $decl_out = "struct $symbol;";
781    } else {
782        my $public = $default_to_public;
783        my $new_declaration = "";
784        my $decl_line;
785        my $decl = $declaration;
786        $decl =~ s/^[^{]*{//;
787        foreach $decl_line (split (/\n/, $decl)) {
788#           print "Struct line: $decl_line\n";
789            if ($decl_line =~ m%/\*\s*<\s*public\s*>\s*\*/%) {
790                $public = 1;
791            } elsif ($decl_line =~ m%/\*\s*<\s*(private|protected)\s*>\s*\*/%) {
792                $public = 0;
793            } elsif ($public) {
794                $new_declaration .= $decl_line . "\n";
795            }
796        }
797        if ($new_declaration) {
798            $decl_out = "struct $symbol {\n" . $new_declaration;
799            # If we finished with public set, we already have the struct end.
800            if ($public == 0) {
801                $decl_out .= "};\n";
802            }
803        } else {
804            $decl_out = "struct $symbol;";
805        }
806    }
807
808    $decl_out = &CreateValidSGML ($decl_out);
809    $desc .= "<programlisting>$decl_out</programlisting>\n";
810
811    $desc .= &MakeDeprecationNote($symbol);
812
813    if (defined ($SymbolDocs{$symbol})) {
814        $desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
815    }
816
817    # Create a table of fields and descriptions
818
819    # FIXME: Inserting &nbsp's into the produced type declarations here would
820    #        improve the output in most situations ... except for function
821    #        members of structs!
822    my @fields = ParseStructDeclaration($declaration, !$default_to_public, \&MakeXRef,
823                                        sub {
824                                            "<structfield>$_[0]</structfield>";
825                                        });
826    my $params = $SymbolParams{$symbol};
827
828    # If no parameters are filled in, we don't generate the description
829    # table, for backwards compatibility
830
831    my $found = 0;
832    if (defined $params) {
833        for (my $i = 1; $i <= $#$params; $i += 2) {
834            if ($params->[$i] =~ /\S/) {
835                $found = 1;
836                last;
837            }
838        }
839    }
840   
841    if ($found) {
842        my %field_descrs = @$params;
843       
844            $desc .= <<EOF;
845<variablelist role="struct">
846EOF
847        while (@fields) {
848            my $field_name = shift @fields;
849            my $text = shift @fields;
850            my $field_descr = $field_descrs{$field_name};
851
852            $desc .= "<varlistentry>\n<term>$text</term>\n";
853            if (defined $field_descr) {
854                $desc .= "<listitem><simpara>".&ExpandAbbreviations($field_descr)."</simpara></listitem>\n";
855            } else {
856                $desc .= "<listitem></listitem>\n";
857            }
858            $desc .= "</varlistentry>\n";
859        }
860   
861        $desc .= "</variablelist>";
862    }
863    if (exists $Since{$symbol}) {
864        $desc .= "<para>Since $Since{$symbol}</para>";
865    }
866    $desc .= "</refsect2>\n";
867    return ($synop, $desc);
868}
869
870
871#############################################################################
872# Function    : OutputEnum
873# Description : Returns the synopsis and detailed description of a enum.
874# Arguments   : $symbol - the enum.
875#               $declaration - the declaration of the enum.
876#############################################################################
877
878sub OutputEnum {
879    my ($symbol, $declaration) = @_;
880    my $id = &CreateValidSGMLID ($symbol);
881    my $synop = "enum        <link linkend=\"$id\">$symbol</link>;\n";
882    my $desc = "<refsect2>\n<title><anchor id=\"$id\"${empty_element_end}enum $symbol</title>\n";
883
884    $desc .= MakeIndexterms($symbol);
885
886    $declaration = &CreateValidSGML ($declaration);
887    $desc .= "<programlisting>$declaration</programlisting>\n";
888
889    $desc .= &MakeDeprecationNote($symbol);
890
891    if (defined ($SymbolDocs{$symbol})) {
892        $desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
893    }
894
895    # Create a table of fields and descriptions
896
897    my @members = ParseEnumDeclaration($declaration);
898    my $params = $SymbolParams{$symbol};
899
900    # If no parameters are filled in, we don't generate the description
901    # table, for backwards compatibility
902
903    my $found = 0;
904    if (defined $params) {
905        for (my $i = 1; $i <= $#$params; $i += 2) {
906            if ($params->[$i] =~ /\S/) {
907                $found = 1;
908                last;
909            }
910        }
911    }
912   
913    if ($found) {
914        my %member_descrs = @$params;
915       
916            $desc .= <<EOF;
917<variablelist role="enum">
918EOF
919        for my $member_name (@members) {
920            my $member_descr = $member_descrs{$member_name};
921           
922            $desc .= "<varlistentry>\n<term><literal>$member_name</literal></term>\n";
923            if (defined $member_descr) {
924                $desc .= "<listitem><simpara>".&ExpandAbbreviations($member_descr)."</simpara></listitem>\n";
925            } else {
926                $desc .= "<listitem></listitem>\n";
927            }
928            $desc .= "</varlistentry>\n";
929        }
930   
931        $desc .= "</variablelist>";
932    }
933
934    if (exists $Since{$symbol}) {
935        $desc .= "<para>Since $Since{$symbol}</para>";
936    }
937    $desc .= "</refsect2>\n";
938    return ($synop, $desc);
939}
940
941
942#############################################################################
943# Function    : OutputUnion
944# Description : Returns the synopsis and detailed description of a union.
945# Arguments   : $symbol - the union.
946#               $declaration - the declaration of the union.
947#############################################################################
948
949sub OutputUnion {
950    my ($symbol, $declaration) = @_;
951    my $id = &CreateValidSGMLID ($symbol);
952    my $synop = "union       <link linkend=\"$id\">$symbol</link>;\n";
953    my $desc = "<refsect2>\n<title><anchor id=\"$id\"${empty_element_end}union $symbol</title>\n";
954
955    $desc .= MakeIndexterms($symbol);
956
957    $declaration = &CreateValidSGML ($declaration);
958    $desc .= "<programlisting>$declaration</programlisting>\n";
959
960    $desc .= &MakeDeprecationNote($symbol);
961
962    if (defined ($SymbolDocs{$symbol})) {
963        $desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
964    }
965    if (exists $Since{$symbol}) {
966        $desc .= "<para>Since $Since{$symbol}</para>";
967    }
968    $desc .= "</refsect2>\n";
969    return ($synop, $desc);
970}
971
972
973#############################################################################
974# Function    : OutputVariable
975# Description : Returns the synopsis and detailed description of a variable.
976# Arguments   : $symbol - the extern'ed variable.
977#               $declaration - the declaration of the variable.
978#############################################################################
979
980sub OutputVariable {
981    my ($symbol, $declaration) = @_;
982    my $id = &CreateValidSGMLID ($symbol);
983
984    my $synop;
985    if ($declaration =~ m/^\s*extern\s+((const\s+|unsigned\s+)*\w+)(\s+\*+|\*+|\s)(\s*)([A-Za-z]\w*)\s*;/) {
986        my $mod = defined ($1) ? $1 : "";
987        my $ptr = defined ($3) ? $3 : "";
988        my $space = defined ($4) ? $4 : "";
989        $synop = "extern      $mod$ptr$space<link linkend=\"$id\">$symbol</link>;\n";
990
991    } else {
992        $synop = "extern      <link linkend=\"$id\">$symbol</link>;\n";
993    }
994
995    my $desc = "<refsect2>\n<title><anchor id=\"$id\"${empty_element_end}$symbol</title>\n";
996
997    $desc .= MakeIndexterms($symbol);
998
999    $declaration = &CreateValidSGML ($declaration);
1000    $desc .= "<programlisting>$declaration</programlisting>\n";
1001
1002    $desc .= &MakeDeprecationNote($symbol);
1003
1004    if (defined ($SymbolDocs{$symbol})) {
1005        $desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
1006    }
1007    if (exists $Since{$symbol}) {
1008        $desc .= "<para>Since $Since{$symbol}</para>";
1009    }
1010    $desc .= "</refsect2>\n";
1011    return ($synop, $desc);
1012}
1013
1014
1015#############################################################################
1016# Function    : OutputFunction
1017# Description : Returns the synopsis and detailed description of a function.
1018# Arguments   : $symbol - the function.
1019#               $declaration - the declaration of the function.
1020#############################################################################
1021
1022sub OutputFunction {
1023    my ($symbol, $declaration, $symbol_type) = @_;
1024    my $id = &CreateValidSGMLID ($symbol);
1025
1026    # Take out the return type
1027    $declaration =~ s/<RETURNS>\s*(const\s+|G_CONST_RETURN\s+|unsigned\s+)*(\w+)\s*(\**)\s*<\/RETURNS>\n//;
1028    my $type_modifier = defined($1) ? $1 : "";
1029    my $type = $2;
1030    my $pointer = $3;
1031    my $xref = &MakeXRef ($type);
1032    my $start = "";
1033    if ($symbol_type eq 'USER_FUNCTION') {
1034#       $start = "typedef ";
1035    }
1036
1037    my $ret_type_len = length ($start) + length ($type_modifier)
1038        + length ($pointer) + length ($type);
1039    my $ret_type_output;
1040    my $symbol_len;
1041    if ($ret_type_len < $RETURN_TYPE_FIELD_WIDTH) {
1042        $ret_type_output = "$start$type_modifier$xref$pointer"
1043            . (' ' x ($RETURN_TYPE_FIELD_WIDTH - $ret_type_len));
1044        $symbol_len = 0;
1045    } else {
1046#       $ret_type_output = "$start$type_modifier$xref$pointer\n"
1047#           . (' ' x $RETURN_TYPE_FIELD_WIDTH);
1048
1049        $ret_type_output = "$start$type_modifier$xref$pointer ";
1050        $symbol_len = $ret_type_len + 1 - $RETURN_TYPE_FIELD_WIDTH;
1051    }
1052
1053    $symbol_len += length ($symbol);
1054    my $char1 = my $char2 = my $char3 = "";
1055    if ($symbol_type eq 'USER_FUNCTION') {
1056        $symbol_len += 3;
1057        $char1 = "(";
1058        $char2 = "*";
1059        $char3 = ")";
1060    }
1061
1062    my ($symbol_output, $symbol_desc_output);
1063    if ($symbol_len < $SYMBOL_FIELD_WIDTH) {
1064        $symbol_output = "$char1<link linkend=\"$id\">$char2$symbol</link>$char3"
1065            . (' ' x ($SYMBOL_FIELD_WIDTH - $symbol_len));
1066        $symbol_desc_output = "$char1$char2$symbol$char3"
1067            . (' ' x ($SYMBOL_FIELD_WIDTH - $symbol_len));
1068    } else {
1069        $symbol_output = "$char1<link linkend=\"$id\">$char2$symbol</link>$char3\n"
1070            . (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH));
1071        $symbol_desc_output = "$char1$char2$symbol$char3\n"
1072            . (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH));
1073    }
1074
1075    my $synop = $ret_type_output . $symbol_output . '(';
1076    my $desc = "<refsect2>\n<title><anchor id=\"$id\"${empty_element_end}${symbol} ()</title>\n";
1077
1078    $desc .= MakeIndexterms($symbol);
1079
1080    $desc  .= "<programlisting>${ret_type_output}$symbol_desc_output(";
1081
1082    my $param_num = 0;
1083    while ($declaration ne "") {
1084        if ($declaration =~ s/^[\s,]+//) {
1085            # skip whitespace and commas
1086            next;
1087
1088        } elsif ($declaration =~ s/^void\s*[,\n]//) {
1089            $synop .= "void";
1090            $desc  .= "void";
1091
1092        } elsif ($declaration =~ s/^...\s*[,\n]//) {
1093            if ($param_num == 0) {
1094                $synop .= "...";
1095                $desc  .= "...";
1096            } else {
1097                $synop .= ",\n"
1098                    . (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH))
1099                    . " ...";
1100                $desc  .= ",\n"
1101                    . (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH))
1102                    . " ...";
1103            }
1104
1105            # allow alphanumerics, '_', '[' & ']' in param names
1106        } 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]//) {
1107            my $mod1 = defined($1) ? $1 : "";
1108            if (defined($2)) { $mod1 .= $2; }
1109            my $type = $3;
1110            my $ptr1 = $4;
1111            my $mod2 = defined($5) ? $5 : "";
1112            my $ptr2 = $6;
1113            my $name = defined($7) ? $7 : "";
1114            if ($name) { $ptr1 = " " . $ptr1; }
1115            my $array = defined($8) ? $8 : "";
1116            my $xref = &MakeXRef ($type);
1117
1118#           print "Type: $mod1$type $ptr1 $mod2 $name $array\n";
1119            if ($param_num == 0) {
1120                $synop .= "$mod1$xref$ptr1$mod2$ptr2$name$array";
1121                $desc  .= "$mod1$xref$ptr1$mod2$ptr2$name$array";
1122            } else {
1123                $synop .= ",\n"
1124                    . (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH))
1125                    . " $mod1$xref$ptr1$mod2$ptr2$name$array";
1126                $desc  .= ",\n"
1127                    . (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH))
1128                    . " $mod1$xref$ptr1$mod2$ptr2$name$array";
1129            }
1130
1131            # Try to match parameters which are functions.
1132        } elsif ($declaration =~ s/^(const\s+|unsigned\s+)*(struct\s+)?(\w+)\s*(\**)\s*(const\s+)?\(\s*\*\s*(\w+)\s*\)\s*\(([^)]*)\)\s*[,\n]//) {
1133            my $mod1 = defined($1) ? $1 : "";
1134            if (defined($2)) { $mod1 .= $2; }
1135            my $type = $3;
1136            my $ptr1 = $4;
1137            my $mod2 = defined($5) ? $5 : "";
1138            my $name = $6;
1139            my $func_params = $7;
1140            my $xref = &MakeXRef ($type);
1141
1142#           print "Type: $mod1$type$ptr1$mod2(*$name)($func_params)\n";
1143            if ($param_num == 0) {
1144                $synop .= "$mod1$xref$ptr1$mod2 (*$name) ($func_params)";
1145                $desc  .= "$mod1$xref$ptr1$mod2 (*$name) ($func_params)";
1146            } else {
1147                $synop .= ",\n"
1148                    . (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH))
1149                    . " $mod1$xref$ptr1$mod2 (*$name) ($func_params)";
1150                $desc  .= ",\n"
1151                    . (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH))
1152                    . " $mod1$xref$ptr1$mod2 (*$name) ($func_params)";
1153            }
1154
1155        } else {
1156            print "###Can't parse args for function $symbol: $declaration\n";
1157            last;
1158        }
1159        $param_num++;
1160    }
1161    $synop .= ");\n";
1162    $desc  .= ");</programlisting>\n";
1163
1164    $desc .= &MakeDeprecationNote($symbol);
1165
1166    if (defined ($SymbolDocs{$symbol})) {
1167        $desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
1168    }
1169
1170    $desc .= &OutputParamDescriptions ("FUNCTION", $symbol);
1171    if (exists $Since{$symbol}) {
1172        $desc .= "<para>Since $Since{$symbol}</para>";
1173    }
1174    $desc .= "</refsect2>\n";
1175    return ($synop, $desc);
1176}
1177
1178
1179#############################################################################
1180# Function    : OutputParamDescriptions
1181# Description : Returns the DocBook output describing the parameters of a
1182#               function, macro or signal handler.
1183# Arguments   : $symbol_type - 'FUNCTION', 'MACRO' or 'SIGNAL'. Signal
1184#                 handlers have an implicit user_data parameter last.
1185#               $symbol - the name of the function/macro being described.
1186#############################################################################
1187
1188sub OutputParamDescriptions {
1189    my ($symbol_type, $symbol) = @_;
1190    my $output = "";
1191    if (defined ($SymbolParams{$symbol})) {
1192        my $returns = "";
1193        my $params = $SymbolParams{$symbol};
1194        my $params_desc = "";
1195        my $j;
1196        for ($j = 0; $j <= $#$params; $j += 2) {
1197            my $param_name = $$params[$j];
1198            my $param = $$params[$j + 1];
1199            if ($param_name eq "Returns") {
1200                $returns = &ExpandAbbreviations($param);
1201            } else {
1202                if ($param_name eq "Varargs") {
1203                    $param_name = "...";
1204                }
1205                $param = &ExpandAbbreviations($param);
1206                $params_desc .= "<varlistentry><term><parameter>$param_name</parameter>&nbsp;:</term>\n<listitem><simpara>$param</simpara></listitem></varlistentry>\n";
1207            }
1208        }
1209
1210        # Signals have an implicit user_data parameter which we describe.
1211        if ($symbol_type eq "SIGNAL") {
1212            $params_desc .= "<varlistentry><term><parameter>user_data</parameter>&nbsp;:</term>\n<listitem><simpara>user data set when the signal handler was connected.</simpara></listitem></varlistentry>\n";
1213        }
1214
1215        # Start a table if we need one.
1216        if ($params_desc || $returns) {
1217            $output .= <<EOF;
1218<variablelist role="params">
1219EOF
1220
1221            if ($params_desc ne "") {
1222#               $output .= "<varlistentry><term>Parameters:</term><listitem></listitem></varlistentry>\n";
1223                $output .= $params_desc;
1224            }
1225
1226            # Output the returns info last.
1227            if ($returns) {
1228                $output .= "<varlistentry><term><emphasis>Returns</emphasis> :</term><listitem><simpara>$returns</simpara></listitem></varlistentry>\n";
1229            }
1230
1231            # Finish the table.
1232            $output .= "</variablelist>";
1233        }
1234    }
1235    return $output;
1236}
1237
1238
1239#############################################################################
1240# Function    : OutputSGMLFile
1241# Description : Outputs the final DocBook file for one section.
1242# Arguments   : $file - the name of the file.
1243#               $title - the title from the $MODULE-sections.txt file, which
1244#                 will be overriden by the title in the template file.
1245#               $section_id - the SGML id to use for the toplevel tag.
1246#               $includes - comma-separates list of include files added at top
1247#                 of synopsis, with '<' '>' around them.
1248#               $synopsis - reference to the DocBook for the Synopsis part.
1249#               $details - reference to the DocBook for the Details part.
1250#               $signal_synop - reference to the DocBook for the Signal Synopsis part
1251#               $signal_desc - reference to the DocBook for the Signal Description part
1252#               $args_synop - reference to the DocBook for the Arg Synopsis part
1253#               $args_desc - reference to the DocBook for the Arg Description part
1254#               $hierarchy - reference to the DocBook for the Object Hierarchy part
1255#               $interfaces - reference to the DocBook for the Interfaces part
1256#               $implementations - reference to the DocBook for the Known Implementations part
1257#               $prerequisites - reference to the DocBook for the Prerequisites part
1258#               $derived - reference to the DocBook for the Derived Interfaces part
1259#               $file_objects - reference to an array of objects in this file
1260#############################################################################
1261
1262sub OutputSGMLFile {
1263    my ($file, $title, $section_id, $includes, $synopsis, $details, $signals_synop, $signals_desc, $args_synop, $args_desc, $hierarchy, $interfaces, $implementations, $prerequisites, $derived, $file_objects) = @_;
1264
1265    # The edited title overrides the one from the sections file.
1266    my $new_title = $SymbolDocs{"$TMPL_DIR/$file:Title"};
1267    if (defined ($new_title) && $new_title !~ m/^\s*$/) {
1268        $title = $new_title;
1269#       print "Found title: $title\n";
1270    }
1271    my $short_desc = $SymbolDocs{"$TMPL_DIR/$file:Short_Description"};
1272    if (!defined ($short_desc) || $short_desc =~ m/^\s*$/) {
1273#       $short_desc = "one line description goes here.";
1274        $short_desc = "";
1275    } else {
1276        $short_desc = &ExpandAbbreviations($short_desc);
1277#       print "Found short_desc: $short_desc";
1278    }
1279    my $long_desc = $SymbolDocs{"$TMPL_DIR/$file:Long_Description"};
1280    if (!defined ($long_desc) || $long_desc =~ m/^\s*$/) {
1281        $long_desc = "<para>\nA longer description goes here.\n</para>\n";
1282    } else {
1283        $long_desc = &ExpandAbbreviations($long_desc);
1284#       print "Found long_desc: $long_desc";
1285    }
1286    my $see_also = $SymbolDocs{"$TMPL_DIR/$file:See_Also"};
1287    if (!defined ($see_also) || $see_also =~ m%^\s*(<para>)?\s*(</para>)?\s*$%) {
1288        $see_also = "";
1289    } else {
1290        $see_also = &ExpandAbbreviations($see_also);
1291#       print "Found see_also: $see_also";
1292    }
1293    if ($see_also) {
1294        $see_also = "<refsect1>\n<title>See Also</title>\n$see_also\n</refsect1>\n";
1295    }
1296
1297    my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
1298        gmtime (time);
1299    my $month = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$mon];
1300    $year += 1900;
1301
1302    my $include_output = "";
1303    my $include;
1304    foreach $include (split (/,/, $includes)) {
1305        $include_output .= "#include &lt;${include}&gt;\n";
1306    }
1307
1308    my $old_sgml_file = "$SGML_OUTPUT_DIR/$file.$OUTPUT_FORMAT";
1309    my $new_sgml_file = "$SGML_OUTPUT_DIR/$file.$OUTPUT_FORMAT.new";
1310
1311    open (OUTPUT, ">$new_sgml_file")
1312        || die "Can't create $new_sgml_file";
1313
1314    my $object_anchors = "";
1315    foreach my $object (@$file_objects) {
1316        next if ($object eq $section_id);
1317        my $id = CreateValidSGMLID($object);
1318#       print "Debug: Adding anchor for $object\n";
1319        $object_anchors .= "<anchor id=\"$id\"$empty_element_end";
1320    }
1321
1322    # Note: The refname and refpurpose are on the same line to stop
1323    # docbook-to-man 1.08 putting them on separate lines.
1324    #
1325    # We used to output this, but is messes up our UpdateFileIfChanged code
1326    # since it changes every day (and it is only used in the man pages):
1327    # "<refentry id="$section_id" revision="$mday $month $year">"
1328
1329    if (lc($OUTPUT_FORMAT) eq "xml") {
1330        print OUTPUT $doctype_header;
1331    }
1332
1333    print OUTPUT <<EOF;
1334<refentry id="$section_id">
1335<refmeta>
1336<refentrytitle>$title</refentrytitle>
1337<manvolnum>3</manvolnum>
1338<refmiscinfo>\U$MODULE\E Library</refmiscinfo>
1339</refmeta>
1340
1341<refnamediv>
1342<refname>$title</refname><refpurpose>$short_desc</refpurpose>
1343</refnamediv>
1344
1345<refsynopsisdiv><title>Synopsis</title>
1346$object_anchors
1347<synopsis>
1348
1349$include_output
1350
1351$${synopsis}</synopsis>
1352</refsynopsisdiv>
1353
1354$$hierarchy
1355$$prerequisites
1356$$derived
1357$$interfaces
1358$$implementations
1359$$args_synop
1360$$signals_synop
1361
1362<refsect1>
1363<title>Description</title>
1364$long_desc
1365</refsect1>
1366
1367<refsect1>
1368<title>Details</title>
1369$$details
1370</refsect1>
1371$$args_desc
1372$$signals_desc
1373
1374$see_also
1375</refentry>
1376EOF
1377    close (OUTPUT);
1378
1379    return &UpdateFileIfChanged ($old_sgml_file, $new_sgml_file, 0);
1380}
1381
1382
1383#############################################################################
1384# Function    : OutputBook
1385# Description : Outputs the SGML entities that need to be included into the
1386#               main SGML file for the module.
1387# Arguments   : $book_top - the declarations of the entities, which are added
1388#                 at the top of the main SGML file.
1389#               $book_bottom - the references to the entities, which are
1390#                 added in the main SGML file at the desired position.
1391#############################################################################
1392
1393sub OutputBook {
1394    my ($book_top, $book_bottom) = @_;
1395
1396    my $old_file = "$SGML_OUTPUT_DIR/$MODULE-doc.top";
1397    my $new_file = "$SGML_OUTPUT_DIR/$MODULE-doc.top.new";
1398
1399    open (OUTPUT, ">$new_file")
1400        || die "Can't create $new_file";
1401    print OUTPUT $book_top;
1402    close (OUTPUT);
1403
1404    &UpdateFileIfChanged ($old_file, $new_file, 0);
1405
1406
1407    $old_file = "$SGML_OUTPUT_DIR/$MODULE-doc.bottom";
1408    $new_file = "$SGML_OUTPUT_DIR/$MODULE-doc.bottom.new";
1409
1410    open (OUTPUT, ">$new_file")
1411        || die "Can't create $new_file";
1412    print OUTPUT $book_bottom;
1413    close (OUTPUT);
1414
1415    &UpdateFileIfChanged ($old_file, $new_file, 0);
1416
1417
1418    # If the main SGML file hasn't been created yet, we create it here.
1419    # The user can tweak it later.
1420    if ($MAIN_SGML_FILE && ! -e $MAIN_SGML_FILE) {
1421      open (OUTPUT, ">$MAIN_SGML_FILE")
1422        || die "Can't create $MAIN_SGML_FILE";
1423
1424      if (lc($OUTPUT_FORMAT) eq "xml") {
1425          print OUTPUT <<EOF;
1426<?xml version="1.0"?>
1427<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
1428               "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
1429<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
1430EOF
1431      } else {
1432        print OUTPUT <<EOF;
1433<!doctype book PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
1434EOF
1435        print OUTPUT $book_top;
1436        print OUTPUT <<EOF;
1437]>
1438<book id="index">
1439EOF
1440      }
1441
1442print OUTPUT <<EOF;
1443  <bookinfo>
1444    <title>[Insert name here] Reference Manual</title>
1445  </bookinfo>
1446
1447  <chapter>
1448    <title>[Insert title here]</title>
1449EOF
1450      print OUTPUT $book_bottom;
1451
1452      print OUTPUT <<EOF;
1453  </chapter>
1454</book>
1455EOF
1456
1457      close (OUTPUT);
1458    }
1459}
1460
1461
1462#############################################################################
1463# Function    : CreateValidSGMLID
1464# Description : Creates a valid SGML 'id' from the given string.
1465#               NOTE: SGML ids are case-insensitive, so we have a few special
1466#                     cases to avoid clashes of ids.
1467# Arguments   : $id - the string to be converted into a valid SGML id.
1468#############################################################################
1469
1470sub CreateValidSGMLID {
1471    my ($id) = $_[0];
1472
1473    # Append -CAPS to all all-caps identifiers
1474
1475    # Special case, '_' would end up as '' so we use 'gettext-macro' instead.
1476    if ($id eq "_") { return "gettext-macro"; }
1477
1478    if ($id !~ /[a-z]/) { $id .= "-CAPS" };
1479
1480    $id =~ s/[_ ]/-/g;
1481    $id =~ s/[,\.]//g;
1482    $id =~ s/^-*//;
1483    $id =~ s/::/-/g;
1484
1485    return $id;
1486}
1487
1488
1489#############################################################################
1490# Function    : CreateValidSGML
1491# Description : This turns any chars which are used in SGML into entities,
1492#               e.g. '<' into '&lt;'
1493# Arguments   : $text - the text to turn into proper SGML.
1494#############################################################################
1495
1496sub CreateValidSGML {
1497    my ($text) = @_;
1498    $text =~ s/&/&amp;/g;       # Do this first, or the others get messed up.
1499    $text =~ s/</&lt;/g;
1500    $text =~ s/>/&gt;/g;
1501    return $text;
1502}
1503
1504#############################################################################
1505# Function    : ConvertSGMLChars
1506# Description : This turns chars which are used in SGML into entities,
1507#               e.g. '<' into '&lt;'. Depending on $SGML_MODE, this is done
1508#               unconditionally or only if the character doesn't seem to be
1509#               part of an SGML construct (tag or entity reference)
1510# Arguments   : $text - the text to turn into proper SGML.
1511#############################################################################
1512
1513sub ConvertSGMLChars {
1514    my ($text) = @_;
1515    if ($SGML_MODE) {
1516        $text =~ s/&(?![a-zA-Z#])/&amp;/g;      # Do this first, or the others get messed up.
1517        $text =~ s/<(?![a-zA-Z\/!])/&lt;/g;
1518        $text =~ s/(?<![a-zA-Z0-9"'\/-])>/&gt;/g;
1519    }
1520    else {
1521        $text =~ s/&/&amp;/g;   # Do this first, or the others get messed up.
1522        $text =~ s/</&lt;/g;
1523        $text =~ s/>/&gt;/g;
1524    }
1525    return $text;
1526}
1527
1528
1529#############################################################################
1530# Function    : ExpandAbbreviations
1531# Description : This turns the abbreviations function(), macro(), @param,
1532#               %constant, and #symbol into appropriate DocBook markup.
1533# Arguments   : $text - the text to expand.
1534#############################################################################
1535
1536sub ExpandAbbreviations {
1537    my ($text) = @_;
1538
1539    # Convert 'function()' or 'macro()'
1540    $text =~ s/(\w+)\s*\(\)/&MakeXRef($1, &tagify($1 . "()", "function"));/eg;
1541
1542    # Convert '@param'
1543    $text =~ s/\@(\w+((\.|->)\w+)*)/<parameter>$1<\/parameter>/g;
1544
1545    # Convert '%constant'. Also allow negative numbers, e.g. %-1.
1546    $text =~ s/\%(-?\w+)/<literal>$1<\/literal>/g;
1547
1548    # Convert '#symbol'
1549    $text =~ s/#([\w-]+)/&MakeXRef($1, &tagify($1, "type"));/eg;
1550
1551    return $text;
1552}
1553
1554sub tagify {
1555   my ($text, $elem) = @_;
1556   return "<" . $elem . ">" . $text . "</" . $elem . ">";
1557}
1558
1559#############################################################################
1560# Function    : MakeXRef
1561# Description : This returns a cross-reference link to the given symbol.
1562#               Though it doesn't try to do this for a few standard C types
1563#               that it knows won't be in the documentation.
1564# Arguments   : $symbol - the symbol to try to create a XRef to.
1565#               $text - text text to put inside the XRef, defaults to $symbol
1566#############################################################################
1567
1568sub MakeXRef {
1569    my ($symbol, $text) = ($_[0], $_[1]);
1570    if (!defined($text)) {
1571        $text = $symbol;
1572
1573        # Get rid of special '-struct' suffix.
1574        $text =~ s/-struct$//;
1575    }
1576
1577    #print "Getting type link for $symbol -> $text\n";
1578
1579    my $symbol_id = &CreateValidSGMLID ($symbol);
1580    return "<link linkend=\"$symbol_id\">$text</link>";
1581}
1582
1583
1584#############################################################################
1585# Function    : MakeIndexterms
1586# Description : This returns a indexterm elements for the given symbol
1587# Arguments   : $symbol - the symbol to create indexterms for
1588#############################################################################
1589
1590sub MakeIndexterms {
1591  my ($symbol) = $_[0];
1592  my $desc = "";
1593
1594  $desc .= "<indexterm><primary>$symbol</primary></indexterm>";
1595
1596  return $desc;
1597}
1598
1599#############################################################################
1600# Function    : MakeDeprecationNote
1601# Description : This returns a deprecation warning for the given symbol.
1602# Arguments   : $symbol - the symbol to try to create a warning for.
1603#############################################################################
1604
1605sub MakeDeprecationNote {
1606    my ($symbol) = $_[0];
1607    my $desc = "";
1608    my $note = "";
1609    if (exists $Deprecated{$symbol}) {
1610        $desc .= "<warning>";
1611        $desc .= "<para><literal>$symbol</literal> is deprecated and should not be used in newly-written code.";
1612        if ($Deprecated{$symbol} ne "") {
1613            $note = &ExpandAbbreviations($Deprecated{$symbol});
1614            $note =~ s/^\s+//;
1615            $note =~ s/\s+$//;
1616            $note =~ s%\n{2,}%\n</para>\n<para>\n%g;
1617            $desc .= " " . $note;
1618        }
1619        $desc .= "</para></warning>\n";
1620    }
1621    return $desc;
1622}
1623
1624
1625#############################################################################
1626# Function    : GetHierarchy
1627# Description : Returns the DocBook output describing the ancestors and
1628#               immediate children of a GObject subclass. It uses the
1629#               global @Objects and @ObjectLevels arrays to walk the tree.
1630# Arguments   : $object - the GtkObject subclass.
1631#############################################################################
1632
1633sub GetHierarchy {
1634    my ($object) = @_;
1635
1636    # Find object in the objects array.
1637    my $found = 0;
1638    my @children = ();
1639    my $i;
1640    my $level;
1641    my $j;
1642    for ($i = 0; $i < @Objects; $i++) {
1643        if ($found) {
1644            if ($ObjectLevels[$i] <= $level) {
1645            last;
1646        }
1647            elsif ($ObjectLevels[$i] == $level + 1) {
1648                push (@children, $Objects[$i]);
1649            }
1650        }
1651        elsif ($Objects[$i] eq $object) {
1652            $found = 1;
1653            $j = $i;
1654            $level = $ObjectLevels[$i];
1655        }
1656    }
1657    if (!$found) {
1658        return "";
1659    }
1660
1661    # Walk up the hierarchy, pushing ancestors onto the ancestors array.
1662    my @ancestors = ();
1663    push (@ancestors, $object);
1664#    print "Level: $level\n";
1665    while ($level > 1) {
1666        $j--;
1667        if ($ObjectLevels[$j] < $level) {
1668            push (@ancestors, $Objects[$j]);
1669            $level = $ObjectLevels[$j];
1670#           print "Level: $level\n";
1671        }
1672    }
1673
1674    # Output the ancestors list, indented and with links.
1675    my $hierarchy = "<synopsis>\n\n";
1676    $level = 0;
1677    for ($i = $#ancestors; $i >= 0; $i--) {
1678        my $link_text;
1679        # Don't add a link to the current widget, i.e. when i == 0.
1680        if ($i > 0) {
1681            my $ancestor_id = &CreateValidSGMLID ($ancestors[$i]);
1682            $link_text = "<link linkend=\"$ancestor_id\">$ancestors[$i]</link>";
1683        } else {
1684            $link_text = "$ancestors[$i]";
1685        }
1686        if ($level == 0) {
1687            $hierarchy .= "  $link_text\n";
1688        } else {
1689#           $hierarchy .= ' ' x ($level * 6 - 3) . "|\n";
1690            $hierarchy .= ' ' x ($level * 6 - 3) . "+----$link_text\n";
1691        }
1692        $level++;
1693    }
1694    for ($i = 0; $i <= $#children; $i++) {
1695      my $id = &CreateValidSGMLID ($children[$i]);
1696      my $link_text = "<link linkend=\"$id\">$children[$i]</link>";
1697      $hierarchy .= ' ' x ($level * 6 - 3) . "+----$link_text\n";
1698    }
1699    $hierarchy .= "</synopsis>\n";
1700
1701    return $hierarchy;
1702}
1703
1704
1705#############################################################################
1706# Function    : GetInterfaces
1707# Description : Returns the DocBook output describing the interfaces
1708#               implemented by a class. It uses the global %Interfaces hash.
1709# Arguments   : $object - the GtkObject subclass.
1710#############################################################################
1711
1712sub GetInterfaces {
1713    my ($object) = @_;
1714    my $text = "";
1715    my $i;
1716
1717    # Find object in the objects array.
1718    if (exists($Interfaces{$object})) {
1719        my @ifaces = split(' ', $Interfaces{$object});
1720        $text = <<EOF;
1721<para>
1722$object implements
1723EOF
1724        for ($i = 0; $i <= $#ifaces; $i++) {
1725            my $id = &CreateValidSGMLID ($ifaces[$i]);
1726            $text .= " <link linkend=\"$id\">$ifaces[$i]</link>";
1727            if ($i < $#ifaces - 1) {
1728                $text .= ', ';
1729            }
1730            elsif ($i < $#ifaces) {
1731                $text .= ' and ';
1732            }
1733            else {
1734                $text .= '.';
1735            }
1736        }
1737        $text .= <<EOF;
1738</para>
1739EOF
1740    }
1741
1742    return $text;
1743}
1744
1745#############################################################################
1746# Function    : GetImplementations
1747# Description : Returns the DocBook output describing the implementations
1748#               of an interface. It uses the global %Interfaces hash.
1749# Arguments   : $object - the GtkObject subclass.
1750#############################################################################
1751
1752sub GetImplementations {
1753    my ($object) = @_;
1754    my @impls = ();
1755    my $text = "";
1756    my $i;
1757    foreach my $key (keys %Interfaces) {
1758        if ($Interfaces{$key} =~ /\b$object\b/) {
1759            push (@impls, $key);
1760        }
1761    }
1762    if ($#impls >= 0) {
1763        $text = <<EOF;
1764<para>
1765$object is implemented by
1766EOF
1767        for ($i = 0; $i <= $#impls; $i++) {
1768            my $id = &CreateValidSGMLID ($impls[$i]);
1769            $text .= " <link linkend=\"$id\">$impls[$i]</link>";
1770            if ($i < $#impls - 1) {
1771                $text .= ', ';
1772            }
1773            elsif ($i < $#impls) {
1774                $text .= ' and ';
1775            }
1776            else {
1777                $text .= '.';
1778            }
1779        }
1780        $text .= <<EOF;
1781</para>
1782EOF
1783    }
1784    return $text;
1785}
1786
1787
1788#############################################################################
1789# Function    : GetPrerequisites
1790# Description : Returns the DocBook output describing the prerequisites
1791#               of an interface. It uses the global %Prerequisites hash.
1792# Arguments   : $iface - the interface.
1793#############################################################################
1794
1795sub GetPrerequisites {
1796    my ($iface) = @_;
1797    my $text = "";
1798    my $i;
1799
1800    if (exists($Prerequisites{$iface})) {
1801        $text = <<EOF;
1802<para>
1803$iface requires
1804EOF
1805        my @prereqs = split(' ', $Prerequisites{$iface});
1806        for ($i = 0; $i <= $#prereqs; $i++) {
1807            my $id = &CreateValidSGMLID ($prereqs[$i]);
1808            $text .= " <link linkend=\"$id\">$prereqs[$i]</link>";
1809            if ($i < $#prereqs - 1) {
1810                $text .= ', ';
1811            }
1812            elsif ($i < $#prereqs) {
1813                $text .= ' and ';
1814            }
1815            else {
1816                $text .= '.';
1817            }
1818        }
1819        $text .= <<EOF;
1820</para>
1821EOF
1822    }
1823    return $text;
1824}
1825
1826#############################################################################
1827# Function    : GetDerived
1828# Description : Returns the DocBook output describing the derived interfaces
1829#               of an interface. It uses the global %Prerequisites hash.
1830# Arguments   : $iface - the interface.
1831#############################################################################
1832
1833sub GetDerived {
1834    my ($iface) = @_;
1835    my $text = "";
1836    my $i;
1837
1838    my @derived = ();
1839    foreach my $key (keys %Prerequisites) {
1840        if ($Prerequisites{$key} =~ /\b$iface\b/) {
1841            push (@derived, $key);
1842        }
1843    }
1844    if ($#derived >= 0) {
1845        $text = <<EOF;
1846<para>
1847$iface is required by
1848EOF
1849        for ($i = 0; $i <= $#derived; $i++) {
1850            my $id = &CreateValidSGMLID ($derived[$i]);
1851            $text .= " <link linkend=\"$id\">$derived[$i]</link>";
1852            if ($i < $#derived - 1) {
1853                $text .= ', ';
1854            }
1855            elsif ($i < $#derived) {
1856                $text .= ' and ';
1857            }
1858            else {
1859                $text .= '.';
1860            }
1861        }
1862        $text .= <<EOF;
1863</para>
1864EOF
1865    }
1866    return $text;
1867}
1868
1869
1870#############################################################################
1871# Function    : GetSignals
1872# Description : Returns the synopsis and detailed description DocBook output
1873#               for the signal handlers of a given GtkObject subclass.
1874# Arguments   : $object - the GtkObject subclass, e.g. 'GtkButton'.
1875#############################################################################
1876
1877sub GetSignals {
1878    my ($object) = @_;
1879    my $synop = "";
1880    my $desc = "";
1881
1882    my $i;
1883    for ($i = 0; $i <= $#SignalObjects; $i++) {
1884        if ($SignalObjects[$i] eq $object) {
1885#           print "Found signal: $SignalNames[$i]\n";
1886            my $name = $SignalNames[$i];
1887            my $symbol = "${object}::${name}";
1888            my $id = &CreateValidSGMLID ("$object-$name");
1889
1890            my $name_len = length ($name) + 2;
1891            if ($name_len < $SIGNAL_FIELD_WIDTH) {
1892                $synop .= "&quot;<link linkend=\"$id\">$name</link>&quot;"
1893                    . (' ' x ($SIGNAL_FIELD_WIDTH - $name_len));
1894            } else {
1895                $synop .= "&quot;<link linkend=\"$id\">$name</link>&quot;\n"
1896                    . (' ' x $SIGNAL_FIELD_WIDTH);
1897            }
1898
1899            $desc .= "<refsect2><title><anchor id=\"$id\"${empty_element_end}The &quot;$name&quot; signal</title>\n";
1900            $desc .= "<programlisting>";
1901
1902            $SignalReturns[$i] =~ m/\s*(const\s*)?(\w+)\s*(\**)/;
1903            my $type_modifier = defined($1) ? $1 : "";
1904            my $type = $2;
1905            my $pointer = $3;
1906            my $xref = &MakeXRef ($type);
1907
1908            my $ret_type_len = length ($type_modifier) + length ($pointer)
1909                + length ($type);
1910            my $ret_type_output = "$type_modifier$xref$pointer"
1911                . (' ' x ($RETURN_TYPE_FIELD_WIDTH - $ret_type_len));
1912
1913            $synop .= "${ret_type_output}user_function      (";
1914            $desc  .= "${ret_type_output}user_function                  (";
1915
1916            my $sourceparams = $SourceSymbolParams{$symbol};
1917            my @params = split ("\n", $SignalPrototypes[$i]);
1918            my $j;
1919            for ($j = 0; $j <= $#params; $j++) {
1920                # allow alphanumerics, '_', '[' & ']' in param names
1921                if ($params[$j] =~ m/^\s*(\w+)\s*(\**)\s*([\w\[\]]+)\s*$/) {
1922                    $type = $1;
1923                    $pointer = $2;
1924                    if (defined($sourceparams)) {
1925                        $name = $$sourceparams[2 * $j];
1926                    }
1927                    else {
1928                        $name = $3;
1929                    }
1930                    $xref = &MakeXRef ($type);
1931                    $synop .= "$xref $pointer$name,\n";
1932                    $synop .= (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH));
1933                    $desc .= "$xref $pointer$name,\n";
1934                    $desc .= (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH));
1935                } else {
1936                    print "###Can't parse arg: $params[$j]\nArgs:$SignalPrototypes[$i]\n";
1937                }
1938            }
1939            $xref = &MakeXRef ("gpointer");
1940            $synop .= "$xref user_data);\n";
1941            $desc  .= "$xref user_data);</programlisting>\n";
1942
1943            $AllSymbols{$symbol} = 1;
1944            if (defined ($SymbolDocs{$symbol})) {
1945                $desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
1946                if (!IsEmptyDoc($SymbolDocs{$symbol})) {
1947                    $AllDocumentedSymbols{$symbol} = 1;
1948                }
1949            }
1950
1951            $desc .= &OutputParamDescriptions ("SIGNAL", $symbol);
1952            if (exists $Since{$symbol}) {
1953              $desc .= "<para>Since $Since{$symbol}</para>";
1954            }
1955            $desc .= "</refsect2>";
1956        }
1957    }
1958    return ($synop, $desc);
1959}
1960
1961
1962#############################################################################
1963# Function    : GetArgs
1964# Description : Returns the synopsis and detailed description DocBook output
1965#               for the Args of a given GtkObject subclass.
1966# Arguments   : $object - the GtkObject subclass, e.g. 'GtkButton'.
1967#############################################################################
1968
1969sub GetArgs {
1970    my ($object) = @_;
1971    my $synop = "";
1972    my $desc = "";
1973    my $child_synop = "";
1974    my $child_desc = "";
1975    my $style_synop = "";
1976    my $style_desc = "";
1977
1978    my $i;
1979    for ($i = 0; $i <= $#ArgObjects; $i++) {
1980        if ($ArgObjects[$i] eq $object) {
1981#           print "Found arg: $ArgNames[$i]\n";
1982            my $name = $ArgNames[$i];
1983            # Remember only one colon so we don't clash with signals.
1984            my $symbol = "${object}:${name}";
1985            # I've used two dashes here for the same reason.
1986            my $id = &CreateValidSGMLID ("$object--$name");
1987
1988            my $type = $ArgTypes[$i];
1989            my $type_output;
1990
1991            if ($type eq "GtkSignal") {
1992                $type = "GtkSignalFunc, gpointer";
1993                $type_output = &MakeXRef ("GtkSignalFunc") . ", "
1994                    . &MakeXRef ("gpointer");
1995            } elsif ($type eq "GtkString") {
1996                $type = "gchar*";
1997                $type_output = &MakeXRef ("gchar") . "*";
1998            } else {
1999                $type_output = &MakeXRef ($type);
2000            }
2001
2002            my $flags = $ArgFlags[$i];
2003            my $flags_string = "";
2004
2005            if ($flags =~ m/r/) {
2006                $flags_string = "Read";
2007            }
2008            if ($flags =~ m/w/) {
2009                if ($flags_string) { $flags_string .= " / "; }
2010                $flags_string .= "Write";
2011            }
2012            if ($flags =~ m/x/) {
2013                if ($flags_string) { $flags_string .= " / "; }
2014                $flags_string .= "Construct";
2015            }
2016            if ($flags =~ m/X/) {
2017                if ($flags_string) { $flags_string .= " / "; }
2018                $flags_string .= "Construct Only";
2019            }
2020
2021            $AllSymbols{$symbol} = 1;
2022            my $blurb;
2023            if (defined($SymbolDocs{$symbol}) &&
2024                !IsEmptyDoc($SymbolDocs{$symbol})) {
2025                $blurb = &ExpandAbbreviations($SymbolDocs{$symbol});
2026                $AllDocumentedSymbols{$symbol} = 1;
2027            }
2028            else {
2029                if (!($ArgBlurbs[$i] eq "")) {
2030                    $AllDocumentedSymbols{$symbol} = 1;
2031                }
2032                $blurb = "<para>" . &CreateValidSGML ($ArgBlurbs[$i]) . "</para>";
2033            }
2034            if (exists $Since{$symbol}) {
2035              $blurb .= "<para>Since $Since{$symbol}</para>";
2036            }
2037            my $pad1 = " " x (20 - length ($name));
2038            my $pad2 = " " x (20 - length ($type));
2039
2040            my $arg_synop = "  &quot;<link linkend=\"$id\">$name</link>&quot;$pad1 $type_output$pad2 : $flags_string\n";
2041            my $arg_desc = "<varlistentry><term><anchor id=\"$id\"${empty_element_end}&quot;<literal>$name</literal>&quot; ($type_output : $flags_string)</term>\n<listitem>\n$blurb\n</listitem></varlistentry>\n";
2042
2043            if ($flags =~ m/c/) {
2044                $child_synop .= $arg_synop;
2045                $child_desc .= $arg_desc;
2046            }
2047            elsif ($flags =~ m/s/) {
2048                $style_synop .= $arg_synop;
2049                $style_desc .= $arg_desc;
2050            }
2051            else {
2052                $synop .= $arg_synop;
2053                $desc .= $arg_desc;
2054            }
2055        }
2056    }
2057    return ($synop, $child_synop, $style_synop, $desc, $child_desc, $style_desc);
2058}
2059
2060
2061#############################################################################
2062# Function    : ReadSourceDocumentation
2063# Description : This reads in the documentation embedded in comment blocks
2064#               in the source code (for Gnome).
2065#               
2066#               Parameter descriptions override any in the template files.
2067#               Function descriptions are placed before any description from
2068#               the template files.
2069#
2070#               It recursively descends the source directory looking for .c
2071#               files and scans them looking for specially-formatted comment
2072#               blocks.
2073#
2074# Arguments   : $source_dir - the directory to scan.
2075#############################################################################
2076
2077sub ReadSourceDocumentation {
2078    my ($source_dir) = @_;
2079#    print "Scanning source directory: $source_dir\n";
2080
2081    # This array holds any subdirectories found.
2082    my (@subdirs) = ();
2083   
2084    opendir (SRCDIR, $source_dir)
2085        || die "Can't open source directory $source_dir: $!";
2086    my $file;
2087    foreach $file (readdir (SRCDIR)) {
2088        if ($file =~ /^\./) {
2089            next;
2090        } elsif (-d "$source_dir/$file") {
2091            push (@subdirs, $file);
2092        } elsif ($file =~ m/\.[ch]$/) {
2093            &ScanSourceFile ("$source_dir/$file");
2094        }
2095    }
2096    closedir (SRCDIR);
2097
2098    # Now recursively scan the subdirectories.
2099    my $dir;
2100    foreach $dir (@subdirs) {
2101        next if ($IGNORE_FILES =~ m/(\s|^)\Q${dir}\E(\s|$)/);
2102        &ReadSourceDocumentation ("$source_dir/$dir");
2103    }
2104}
2105
2106
2107#############################################################################
2108# Function    : ScanSourceFile
2109# Description : Scans one source file looking for specially-formatted comment
2110#               blocks. It calls &MergeSourceDocumentation to merge any
2111#               documentation found with the documentation already read in
2112#               from the template files.
2113#               
2114# Arguments   : $file - the file to scan.
2115#############################################################################
2116
2117sub ScanSourceFile {
2118    my ($file) = @_;
2119    my $basename;
2120
2121    if ($file =~ m/^.*[\/\\](.*\.[hc])$/) {
2122        $basename = $1;
2123    } else {
2124        print "WARNING: Can't find basename of file $file\n";
2125        $basename = $file;
2126    }
2127
2128    # Check if the basename is in the list of files to ignore.
2129    if ($IGNORE_FILES =~ m/(\s|^)\Q${basename}(\s|$)/) {
2130        return;
2131    }
2132
2133    open (SRCFILE, $file)
2134        || die "Can't open $file: $!";
2135    my $in_comment_block = 0;
2136    my $symbol;
2137    my ($in_description, $in_return, $in_since, $in_deprecated);
2138    my ($description, $return_desc, $return_start, $since_desc, $deprecated_desc);
2139    my $current_param;
2140    my $ignore_returns;
2141    my @params;
2142    while (<SRCFILE>) {
2143        # Look for the start of a comment block.
2144        if (!$in_comment_block) {
2145            if (m%^\s*/\*.*\*/%) {
2146                #one-line comment - not gtkdoc
2147            } elsif (m%^\s*/\*\*\s%) {
2148#             print "Found comment block start\n";
2149
2150                $in_comment_block = 1;
2151
2152                # Reset all the symbol data.
2153                $symbol = "";
2154                $in_description = 0;
2155                $in_return = 0;
2156                $in_since = 0;
2157                $in_deprecated = 0;
2158                $description = "";
2159                $return_desc = "";
2160                $since_desc = "";
2161                $deprecated_desc = "";
2162                $current_param = -1;
2163                $ignore_returns = 0;
2164                @params = ();
2165            }
2166            next;
2167        }
2168
2169        # We're in a comment block. Check if we've found the end of it.
2170        if (m%^\s*\*+/%) {
2171            if (!$symbol) {
2172                print <<EOF;
2173WARNING: symbol name not found in comment block.
2174 $file line $.
2175EOF
2176            } else {
2177                # Add the return value description onto the end of the params.
2178                if ($return_desc) {
2179                    push (@params, "Returns");
2180                    push (@params, $return_desc);
2181                }
2182                # Convert special SGML characters
2183                $description = &ConvertSGMLChars ($description);
2184                my $k;
2185                for ($k = 1; $k <= $#params; $k += 2) {
2186                    $params[$k] = &ConvertSGMLChars ($params[$k]);
2187                }
2188
2189                $SourceSymbolDocs{$symbol} = $description;
2190                $SourceSymbolParams{$symbol} = [ @params ];
2191
2192                if ($since_desc) {
2193                    $Since{$symbol} = &ConvertSGMLChars ($since_desc);
2194                }
2195
2196                if ($deprecated_desc) {
2197                    if (exists $Deprecated{$symbol}) {
2198                    }
2199                    else {
2200                        print <<EOF;
2201WARNING: Unguarded $symbol deprecated in inline comments
2202EOF
2203                    }
2204                    $Deprecated{$symbol} = &ConvertSGMLChars ($deprecated_desc);
2205                }
2206            }
2207
2208            $in_comment_block = 0;
2209            next;
2210        }
2211
2212        # Get rid of ' * ' at start of every line in the comment block.
2213        s%^\s*\*\s?%%;
2214        # But make sure we don't get rid of the newline at the end.
2215        if (!$_) {
2216            $_ = "\n";
2217        }
2218
2219        # If we haven't found the symbol name yet, look for it.
2220        if (!$symbol) {
2221            if (m%^\s*([\w:-]*\w)\s*:?%) {
2222                $symbol = $1;
2223            }
2224            next;
2225        }
2226
2227        # If we're in the return value description, add it to the end.
2228        if ($in_return) {
2229            # If we find another valid returns line, we assume that the first
2230            # one was really part of the description.
2231            if (m%^\s*(returns:|return\s+value:|returns\s*)%i) {
2232                $description .= $return_start . $return_desc;
2233                $return_start = $1;
2234                $return_desc = $';
2235            } elsif (m%^\s*since:%i) {
2236                $since_desc = $';
2237                $in_since = 1;
2238                $in_return = 0;
2239            } elsif (m%^\s*deprecated:%i) {
2240                $deprecated_desc = $';
2241                $in_deprecated = 1;
2242                $in_return = 0;
2243            } else {
2244                $return_desc .= $_;
2245            }
2246            next;
2247        }
2248
2249        if ($in_since) {
2250            if (m%^\s*(returns:|return\s+value:|returns\s*)%i) {
2251                $description .= $return_start . $return_desc;
2252                $return_start = $1;
2253                $return_desc = $';
2254                $in_return = 1;
2255                $in_since = 0;
2256            } elsif (m%^\s*deprecated:%i) {
2257                $deprecated_desc = $';
2258                $in_deprecated = 1;
2259                $in_since = 0;
2260            } else {
2261                $since_desc .= $_;
2262            }
2263            next;
2264        }
2265
2266        if ($in_deprecated) {
2267            if (m%^\s*(returns:|return\s+value:|returns\s*)%i) {
2268                $description .= $return_start . $return_desc;
2269                $return_start = $1;
2270                $return_desc = $';
2271                $in_return = 1;
2272                $in_deprecated = 0;
2273            } elsif (m%^\s*since:%i) {
2274                $since_desc = $';
2275                $in_since = 1;
2276                $in_deprecated = 0;
2277            } else {
2278                $deprecated_desc .= $_;
2279            }
2280            next;
2281        }
2282
2283        # If we're in the description part, check for the 'Return' line.
2284        # If that isn't found, add the text to the end.
2285        if ($in_description) {
2286            # Get rid of 'Description:'
2287            s%^\s*Description:%%;
2288
2289            if (!$ignore_returns && m%^\s*(returns:|return\s+value:|returns\s*)%i) {
2290                $return_start = $1;
2291                $return_desc = $';
2292                $in_return = 1;
2293                next;
2294            }
2295            elsif (m%^\s*since:%i) {
2296                $since_desc = $';
2297                $in_since = 1;
2298                next;
2299            }
2300            elsif (m%^\s*deprecated:%i) {
2301                $deprecated_desc = $';
2302                $in_deprecated = 1;
2303                next;
2304            }
2305
2306            $description .= $_;
2307            next;
2308        }
2309
2310        # We must be in the parameters. Check for the empty line at the end.
2311        if (m%^\s*$%) {
2312            $in_description = 1;
2313            next;
2314        }
2315
2316        # Look for a parameter name.
2317        if (m%^\s*@(\S+)\s*:%) {
2318            my $param_name = $1;
2319#           print "Found parameter: $param_name\n";
2320            # Allow '...' as the Varargs parameter.
2321            if ($param_name eq "...") {
2322                $param_name = "Varargs";
2323            }
2324            if ("\L$param_name" eq "returns") {
2325              $ignore_returns = 1;
2326            }
2327            push (@params, $param_name);
2328            push (@params, $');
2329            $current_param += 2;
2330            next;
2331        }
2332
2333        # We must be in the middle of a parameter description, so add it on
2334        # to the last element in @params.
2335        if ($current_param == -1) {
2336            print <<EOF
2337ERROR parsing comment block file : parameter expected -
2338 $file:$.
2339EOF
2340        } else {
2341            $params[$#params] .= $_;
2342        }
2343    }
2344    close (SRCFILE);
2345}
2346
2347#############################################################################
2348# Function    : OutputMissingDocumentation
2349# Description : Outputs report of documentation coverage to a file
2350#
2351# Arguments   : none
2352#############################################################################
2353
2354sub OutputMissingDocumentation {
2355     my $n_documented = 0;
2356     my $total = 0;
2357     my $symbol;
2358     my $percent;
2359     my $msg;
2360     my $buffer = "";
2361     my $buffer2 = "";
2362
2363     open (UNDOCUMENTED, ">$ROOT_DIR/$MODULE-undocumented.txt")
2364          || die "Can't create $ROOT_DIR/$MODULE-undocumented.txt";
2365
2366     foreach $symbol (sort (keys (%AllSymbols))) {
2367          if ($symbol !~ /:(Title|Long_Description|Short_Description|See_Also)/) {
2368              $total++;
2369              if (exists ($AllDocumentedSymbols{$symbol})) {
2370                  $n_documented++;
2371              } elsif (exists $Deprecated{$symbol}) {
2372                  $buffer2 .= $symbol . "\n";
2373              }
2374              else {
2375                  $buffer .= $symbol . "\n";
2376              }
2377          }
2378     }
2379
2380     $buffer .= "\n" . $buffer2;
2381     
2382     if ($total == 0) {
2383          $percent = 100;
2384     } else {
2385          $percent = ($n_documented / $total) * 100.0;
2386     }
2387
2388     printf UNDOCUMENTED "%.0f%% symbol docs coverage.\n", $percent;
2389     print UNDOCUMENTED "$n_documented symbols documented.\n";
2390     print UNDOCUMENTED ($total - $n_documented) . " not documented.\n\n\n";
2391
2392     print UNDOCUMENTED $buffer;
2393
2394     close (UNDOCUMENTED);
2395
2396     printf (("%.0f%% symbol docs coverage ($n_documented symbols documented, " . ($total - $n_documented) . " not documented)\nSee $MODULE-undocumented.txt for a list of missing docs.\nThe doc coverage percentage doesn't include intro sections.\n"), $percent);
2397}
2398
2399
2400#############################################################################
2401# Function    : OutputAllSymbols
2402# Description : Outputs list of all symbols to a file
2403#
2404# Arguments   : none
2405#############################################################################
2406
2407sub OutputAllSymbols {
2408     my $n_documented = 0;
2409     my $total = 0;
2410     my $symbol;
2411     my $percent;
2412     my $msg;
2413
2414     open (SYMBOLS, ">$ROOT_DIR/$MODULE-symbols.txt")
2415          || die "Can't create $ROOT_DIR/$MODULE-symbols.txt";
2416
2417     foreach $symbol (sort (keys (%AllSymbols))) {
2418          print SYMBOLS $symbol . "\n"
2419     }
2420
2421     close (SYMBOLS);
2422}
2423
2424
2425#############################################################################
2426# Function    : MergeSourceDocumentation
2427# Description : This merges documentation read from a source file into the
2428#               documentation read in from a template file.
2429#               
2430#               Parameter descriptions override any in the template files.
2431#               Function descriptions are placed before any description from
2432#               the template files.
2433#
2434# Arguments   : none
2435#############################################################################
2436
2437sub MergeSourceDocumentation {
2438    my $symbol;
2439    foreach $symbol (keys (%SymbolDocs)) {
2440        $AllSymbols{$symbol} = 1;
2441
2442        my $have_tmpl_docs = 0;
2443       
2444        ## See if the symbol is documented out-of-line
2445        my $tmpl_doc = $SymbolDocs{$symbol};
2446        $tmpl_doc = defined ($tmpl_doc) ? $tmpl_doc : "";
2447        $tmpl_doc =~ s/<\/?[a-z]+>//g;
2448        $tmpl_doc =~ s/\s//g;
2449        if ($tmpl_doc ne "") {
2450            $have_tmpl_docs = 1;
2451        }
2452       
2453        if (exists ($SourceSymbolDocs{$symbol})) {
2454            my $src_doc = $SourceSymbolDocs{$symbol};
2455            my $tmpl_doc = $SymbolDocs{$symbol};
2456            $tmpl_doc = defined ($tmpl_doc) ? $tmpl_doc : "";
2457            $src_doc =~ s/^\s+//;
2458            $src_doc =~ s/\s+$//;
2459
2460            if ($have_tmpl_docs) {
2461                    print <<EOF;
2462WARNING: Documentation in template file for $symbol being overriden by inline comments
2463EOF
2464            }
2465
2466            if ($src_doc ne "") {
2467                 $AllDocumentedSymbols{$symbol} = 1;
2468            }
2469
2470            # If there is a blank line, finish the paragraph and start another.
2471            if ($src_doc =~ s%\n{2,}%\n</para>\n<para>\n%g) {
2472#               print "Converted blank lines:\n$src_doc\n";
2473            }
2474            $SymbolDocs{$symbol} = "<para>\n$src_doc</para>\n$tmpl_doc";
2475
2476            if ($symbol =~ m/.*::.*/) {
2477                # For signals we prefer the param names from the source docs,
2478                # since the ones from the templates are likely to contain the
2479                # artificial argn names which are generated by gtkdoc-scangobj.
2480                $SymbolParams{$symbol} = $SourceSymbolParams{$symbol}
2481            }
2482            else {
2483                # The templates contain the definitive parameter names and order,
2484                # so we will not change that. We only override the actual text.
2485                my $tmpl_params = $SymbolParams{$symbol};
2486                if (!defined ($tmpl_params)) {
2487                    next;
2488                }
2489               
2490                my $params = $SourceSymbolParams{$symbol};
2491                my $j;
2492                for ($j = 0; $j <= $#$tmpl_params; $j += 2) {
2493                    my $tmpl_param_name = $$tmpl_params[$j];
2494                    my $tmpl_param_desc = $$tmpl_params[$j + 1];
2495                   
2496                    # Try to find the param in the source comment documentation.
2497                    my $found = 0;
2498                    my $k;
2499                    for ($k = 0; $k <= $#$params; $k += 2) {
2500                        my $param_name = $$params[$k];
2501                        my $param_desc = $$params[$k + 1];
2502                       
2503                        # We accept changed in case, since the Gnome source docs
2504                        # contain a lot of these.
2505                        if ("\L$param_name" eq "\L$tmpl_param_name") {
2506                            $found = 1;
2507                           
2508                            # Override the description.
2509                            $$tmpl_params[$j + 1] = $param_desc ;
2510                           
2511                            # Set the name to "" to mark it as used.
2512                            $$params[$k] = "";
2513                            last;
2514                        }
2515                    }
2516                   
2517                    # Output a warning if the parameter is not found.
2518                    if (!$found) {
2519                        print <<EOF;
2520WARNING: Parameter description missing in source code comment block -
2521         Func: $symbol Param: $tmpl_param_name.
2522EOF
2523                    }
2524                }
2525
2526                # Now we output a warning if parameters have been described which
2527                # do not exist.
2528                for ($j = 0; $j <= $#$params; $j += 2) {
2529                    my $param_name = $$params[$j];
2530                    if ($param_name) {
2531                        print <<EOF;
2532WARNING: Parameter described in source code comment block but does not exist -
2533         Func: $symbol Param: $param_name.
2534EOF
2535                    }
2536                }
2537            }
2538        } else {
2539            if ($have_tmpl_docs) {
2540                $AllDocumentedSymbols{$symbol} = 1;
2541            }
2542        }
2543   }
2544}
2545
2546sub IsEmptyDoc {
2547    my ($doc) = @_;
2548
2549    if ($doc =~ /^\s*<para>\s*(FIXME)?\s*<\/para>\s*$/) {
2550        return 1;
2551    }
2552    else {
2553        return 0;
2554    }
2555}
2556
2557#############################################################################
2558# LIBRARY FUNCTIONS -   These functions are used in both gtkdoc-mkdb and
2559#                       gtkdoc-mktmpl and should eventually be moved to a
2560#                       separate library.
2561#############################################################################
2562
2563#############################################################################
2564# Function    : ReadDeclarationsFile
2565# Description : This reads in a file containing the function/macro/enum etc.
2566#               declarations.
2567#               
2568#               Note that in some cases there are several declarations with
2569#               the same name, e.g. for conditional macros. In this case we
2570#               set a flag in the %DeclarationConditional hash so the
2571#               declaration is not shown in the docs.
2572#
2573#               If a macro and a function have the same name, e.g. for
2574#               gtk_object_ref, the function declaration takes precedence.
2575#
2576#               Some opaque structs are just declared with 'typedef struct
2577#               _name name;' in which case the declaration may be empty.
2578#               The structure may have been found later in the header, so
2579#               that overrides the empty declaration.
2580#               
2581# Arguments   : $file - the declarations file to read
2582#               $override - if declarations in this file should override
2583#                       any current declaration.
2584#############################################################################
2585
2586sub ReadDeclarationsFile {
2587    my ($file, $override) = @_;
2588
2589    if ($override == 0) {
2590        %Declarations = ();
2591        %DeclarationTypes = ();
2592        %DeclarationConditional = ();
2593        %DeclarationOutput = ();
2594    }
2595
2596    open (INPUT, $file)
2597        || die "Can't open $file";
2598    my $declaration_type = "";
2599    my $declaration_name;
2600    my $declaration;
2601    my $is_deprecated = 0;
2602    while (<INPUT>) {
2603        if (!$declaration_type) {
2604            if (m/^<([^>]+)>/) {
2605                $declaration_type = $1;
2606                $declaration_name = "";
2607#               print "Found declaration: $declaration_type\n";
2608                $declaration = "";
2609            }
2610        } else {
2611            if (m%^<NAME>(.*)</NAME>%) {
2612                $declaration_name = $1;
2613            } elsif (m%^<DEPRECATED/>%) {
2614                $is_deprecated = 1;
2615            } elsif (m%^</$declaration_type>%) {
2616#               print "Found end of declaration: $declaration_name\n";
2617                # Check that the declaration has a name
2618                if ($declaration_name eq "") {
2619                    print "ERROR: $declaration_type has no name $file:$.\n";
2620                }
2621
2622                # Check if the symbol is already defined.
2623                if (defined ($Declarations{$declaration_name})
2624                    && $override == 0) {
2625                    # Function declarations take precedence.
2626                    if ($DeclarationTypes{$declaration_name} eq 'FUNCTION') {
2627                        # Ignore it.
2628                    } elsif ($declaration_type eq 'FUNCTION') {
2629                        if ($is_deprecated) {
2630                            $Deprecated{$declaration_name} = "";
2631                        }
2632                        $Declarations{$declaration_name} = $declaration;
2633                        $DeclarationTypes{$declaration_name} = $declaration_type;
2634                    } elsif ($DeclarationTypes{$declaration_name}
2635                              eq $declaration_type) {
2636                        # If the existing declaration is empty override it.
2637                        if ($declaration_type eq 'STRUCT') {
2638                            if ($Declarations{$declaration_name} =~ m/^\s*$/) {
2639                                if ($is_deprecated) {
2640                                    $Deprecated{$declaration_name} = "";
2641                                }
2642                                $Declarations{$declaration_name} = $declaration;
2643                            } elsif ($declaration =~ m/^\s*$/) {
2644                                # Ignore an empty declaration.
2645                            } else {
2646                                print "WARNING: Structure has multiple definitions: $declaration_name\n";
2647                            }
2648
2649                        } else {
2650                            # set flag in %DeclarationConditional hash for
2651                            # multiply defined macros/typedefs.
2652                            $DeclarationConditional{$declaration_name} = 1;
2653                        }
2654                    } else {
2655                        print "ERROR: $declaration_name has multiple definitions\n";
2656                    }
2657                } else {
2658                    if ($is_deprecated) {
2659                        $Deprecated{$declaration_name} = "";
2660                    }
2661                    $Declarations{$declaration_name} = $declaration;
2662                    $DeclarationTypes{$declaration_name} = $declaration_type;
2663                }
2664
2665                $declaration_type = "";
2666                $is_deprecated = 0;
2667            } else {
2668                $declaration .= $_;
2669            }
2670        }
2671    }
2672    close (INPUT);
2673}
2674
2675
2676#############################################################################
2677# Function    : ReadSignalsFile
2678# Description : This reads in an existing file which contains information on
2679#               all GTK signals. It creates the arrays @SignalNames and
2680#               @SignalPrototypes containing info on the signals. The first
2681#               line of the SignalPrototype is the return type of the signal
2682#               handler. The remaining lines are the parameters passed to it.
2683#               The last parameter, "gpointer user_data" is always the same
2684#               so is not included.
2685# Arguments   : $file - the file containing the signal handler prototype
2686#                       information.
2687#############################################################################
2688
2689sub ReadSignalsFile {
2690    my ($file) = @_;
2691
2692    my $in_signal = 0;
2693    my $signal_object;
2694    my $signal_name;
2695    my $signal_returns;
2696    my $signal_prototype;
2697
2698    # Reset the signal info.
2699    @SignalObjects = ();
2700    @SignalNames = ();
2701    @SignalReturns = ();
2702    @SignalPrototypes = ();
2703
2704    if (! -f $file) {
2705        return;
2706    }
2707    if (!open (INPUT, $file)) {
2708        warn "Can't open $file - skipping signals\n";
2709        return;
2710    }
2711    while (<INPUT>) {
2712        if (!$in_signal) {
2713            if (m/^<SIGNAL>/) {
2714                $in_signal = 1;
2715                $signal_object = "";
2716                $signal_name = "";
2717                $signal_returns = "";
2718                $signal_prototype = "";
2719            }
2720        } else {
2721            if (m/^<NAME>(.*)<\/NAME>/) {
2722                $signal_name = $1;
2723                if ($signal_name =~ m/^(.*)::(.*)$/) {
2724                    $signal_object = $1;
2725                    ($signal_name = $2) =~ s/_/-/g;
2726#                   print "Found signal: $signal_name\n";
2727                } else {
2728                    print "Invalid signal name: $signal_name\n";
2729                }
2730            } elsif (m/^<RETURNS>(.*)<\/RETURNS>/) {
2731                $signal_returns = $1;
2732            } elsif (m%^</SIGNAL>%) {
2733#               print "Found end of signal: ${signal_object}::${signal_name}\nReturns: ${signal_returns}\n${signal_prototype}";
2734                push (@SignalObjects, $signal_object);
2735                push (@SignalNames, $signal_name);
2736                push (@SignalReturns, $signal_returns);
2737                push (@SignalPrototypes, $signal_prototype);
2738                $in_signal = 0;
2739            } else {
2740                $signal_prototype .= $_;
2741            }
2742        }
2743    }
2744    close (INPUT);
2745}
2746
2747
2748#############################################################################
2749# Function    : ReadTemplateFile
2750# Description : This reads in the manually-edited documentation file
2751#               corresponding to the file currently being created, so we can
2752#               insert the documentation at the appropriate places.
2753#               It outputs %SymbolTypes, %SymbolDocs and %SymbolParams, which
2754#               is a hash of arrays.
2755#               NOTE: This function is duplicated in gtkdoc-mkdb (but
2756#               slightly different).
2757# Arguments   : $docsfile - the template file to read in.
2758#               $skip_unused_params - 1 if the unused parameters should be
2759#                       skipped.
2760#############################################################################
2761
2762sub ReadTemplateFile {
2763    my ($docsfile, $skip_unused_params) = @_;
2764
2765    my $template = "$docsfile.sgml";
2766#    print "Reading $template\n";
2767    if (! -f $template) {
2768        print "File doesn't exist: $template\n";
2769        return;
2770    }
2771
2772    my $current_type = "";      # Type of symbol being read.
2773    my $current_symbol = "";    # Name of symbol being read.
2774    my $symbol_doc = "";                # Description of symbol being read.
2775    my @params;                 # Parameter names and descriptions of current
2776                                #   function/macro/function typedef.
2777    my $current_param = -1;     # Index of parameter currently being read.
2778                                #   Note that the param array contains pairs
2779                                #   of param name & description.
2780    my $in_unused_params = 0;   # True if we are reading in the unused params.
2781
2782    open (DOCS, "$template")
2783        || die "Can't open file $template: $!";
2784    while (<DOCS>) {
2785        if (m/^<!-- ##### ([A-Z_]+) (\S+) ##### -->/) {
2786            my $type = $1;
2787            my $symbol = $2;
2788            if ($symbol eq "Title"
2789                || $symbol eq "Short_Description"
2790                || $symbol eq "Long_Description"
2791                || $symbol eq "See_Also") {
2792                $symbol = $docsfile . ":" . $symbol;
2793            }
2794#           print "Found symbol: $symbol\n";
2795
2796            # Store previous symbol, but remove any trailing blank lines.
2797            if ($current_symbol ne "") {
2798                $symbol_doc =~ s/\s+$//;
2799                $SymbolTypes{$current_symbol} = $current_type;
2800                $SymbolDocs{$current_symbol} = $symbol_doc;
2801                if ($current_param >= 0) {
2802                    if ($current_param > 0) {
2803                        if ($params[$current_param - 1] eq "Deprecated") {
2804                            $Deprecated{$current_symbol} = pop (@params);
2805                            pop (@params);
2806                            $current_param -= 2;
2807                        }
2808                    }
2809                    if ($current_param > 0) {
2810                        if ($params[$current_param - 1] eq "Since") {
2811                            $Since{$current_symbol} = pop (@params);
2812                            pop (@params);
2813                            $current_param -= 2;
2814                        }
2815                    }
2816                    # look for deprecated again to support both orders
2817                    if ($current_param > 0) {
2818                        if ($params[$current_param - 1] eq "Deprecated") {
2819                            $Deprecated{$current_symbol} = pop (@params);
2820                            pop (@params);
2821                            $current_param -= 2;
2822                        }
2823                    }
2824                    $SymbolParams{$current_symbol} = [ @params ];
2825                } else {
2826                    # Delete any existing params in case we are overriding a
2827                    # previously read template.
2828                    delete $SymbolParams{$current_symbol};
2829                }
2830            }
2831            $current_type = $type;
2832            $current_symbol = $symbol;
2833            $current_param = -1;
2834            $in_unused_params = 0;
2835            $symbol_doc = "";
2836            @params = ();
2837
2838        } elsif (m/^<!-- # Unused Parameters # -->/) {
2839#           print "DEBUG: Found unused parameters\n";
2840            $in_unused_params = 1;
2841            next;
2842
2843        } elsif ($in_unused_params && $skip_unused_params) {
2844            # When outputting the DocBook we skip unused parameters.
2845#           print "DEBUG: Skipping unused param: $_";
2846            next;
2847
2848        } else {
2849            # Check if param found
2850            if (s/^\@(\S+):\040?//) {
2851                my $param_name = $1;
2852                # Allow variations of 'Returns'
2853                if ($param_name =~ m/^[Rr]eturns?$/) {
2854                    $param_name = "Returns";
2855                }
2856#               print "Found param: $param_name\n";
2857                push (@params, $param_name);
2858                push (@params, $_);
2859                $current_param += 2;
2860                next;
2861            }
2862
2863            if ($current_param >= 0) {
2864                $params[$current_param] .= $_;
2865            } else {
2866                $symbol_doc .= $_;
2867            }
2868        }
2869    }
2870
2871    # Remember to finish the current symbol doccs.
2872    if ($current_symbol ne "") {
2873        $symbol_doc =~ s/\s+$//;
2874        $SymbolTypes{$current_symbol} = $current_type;
2875        $SymbolDocs{$current_symbol} = $symbol_doc;
2876        if ($current_param >= 0) {
2877            if ($current_param > 0) {
2878                if ($params[$current_param - 1] eq "Deprecated") {
2879                    $Deprecated{$current_symbol} = pop (@params);
2880                    pop (@params);
2881                    $current_param -= 2;
2882                }
2883            }
2884            if ($current_param > 0) {
2885                if ($params[$current_param - 1] eq "Since") {
2886                    $Since{$current_symbol} = pop (@params);
2887                    pop (@params);
2888                    $current_param -= 2;
2889                }
2890            }
2891            if ($current_param > 0) {
2892                if ($params[$current_param - 1] eq "Deprecated") {
2893                    $Deprecated{$current_symbol} = pop (@params);
2894                    pop (@params);
2895                    $current_param -= 2;
2896                }
2897            }
2898            $SymbolParams{$current_symbol} = [ @params ];
2899        } else {
2900            delete $SymbolParams{$current_symbol};
2901        }
2902    }
2903
2904    close (DOCS);
2905}
2906
2907
2908#############################################################################
2909# Function    : ReadObjectHierarchy
2910# Description : This reads in the $MODULE-hierarchy.txt file containing all
2911#               the GtkObject subclasses described in this module (and their
2912#               ancestors).
2913#               It places them in the @Objects array, and places their level
2914#               in the widget hierarchy in the @ObjectLevels array, at the
2915#               same index. GtkObject, the root object, has a level of 1.
2916#   
2917#               FIXME: the version in gtkdoc-mkdb also generates tree_index.sgml
2918#               as it goes along, this should be split out into a separate
2919#               function.
2920#
2921# Arguments   : none
2922#############################################################################
2923
2924sub ReadObjectHierarchy {
2925    @Objects = ();
2926    @ObjectLevels = ();
2927
2928    if (! -f $OBJECT_TREE_FILE) {
2929        return;
2930    }
2931    if (!open (INPUT, $OBJECT_TREE_FILE)) {
2932        warn "Can't open $OBJECT_TREE_FILE - skipping object tree\n";
2933        return;
2934    }
2935
2936    my $old_tree_index = "$SGML_OUTPUT_DIR/tree_index.sgml";
2937    my $new_tree_index = "$SGML_OUTPUT_DIR/tree_index.new";
2938    my $tree_header = $doctype_header;
2939    $tree_header =~ s/<!DOCTYPE \w+/<!DOCTYPE screen/;
2940
2941    open (OUTPUT, ">$new_tree_index")
2942        || die "Can't create $new_tree_index";
2943    print (OUTPUT "$tree_header<screen>\n");
2944
2945    while (<INPUT>) {
2946        if (m/\S+/) {
2947            my $object = $&;
2948            my $level = (length($`)) / 2 + 1;
2949#            print ("Level: $level  Object: $object\n");
2950
2951            my $xref = &MakeXRef ($object);
2952            print (OUTPUT ' ' x ($level * 4), "$xref\n");
2953            push (@Objects, $object);
2954            push (@ObjectLevels, $level);
2955        }
2956    }
2957    print (OUTPUT "</screen>\n");
2958
2959    close (INPUT);
2960    close (OUTPUT);
2961
2962    &UpdateFileIfChanged ($old_tree_index, $new_tree_index, 0);
2963
2964    &OutputObjectList;
2965}
2966
2967#############################################################################
2968# Function    : ReadInterfaces
2969# Description : This reads in the $MODULE.interfaces file.
2970#
2971# Arguments   : none
2972#############################################################################
2973
2974sub ReadInterfaces {
2975    %Interfaces = ();
2976
2977    if (! -f $INTERFACES_FILE) {
2978        return;
2979    }
2980    if (!open (INPUT, $INTERFACES_FILE)) {
2981        warn "Can't open $INTERFACES_FILE - skipping interfaces\n";
2982        return;
2983    }
2984
2985    while (<INPUT>) {
2986       chomp;
2987       my ($object, @ifaces) = split;
2988       $Interfaces{$object} = join(' ', @ifaces);
2989    }
2990    close (INPUT);
2991}
2992
2993#############################################################################
2994# Function    : ReadPrerequisites
2995# Description : This reads in the $MODULE.prerequisites file.
2996#
2997# Arguments   : none
2998#############################################################################
2999
3000sub ReadPrerequisites {
3001    %Prerequisites = ();
3002
3003    if (! -f $PREREQUISITES_FILE) {
3004        return;
3005    }
3006    if (!open (INPUT, $PREREQUISITES_FILE)) {
3007        warn "Can't open $PREREQUISITES_FILE - skipping prerequisites\n";
3008        return;
3009    }
3010
3011    while (<INPUT>) {
3012       chomp;
3013       my ($iface, @prereqs) = split;
3014       $Prerequisites{$iface} = join(' ', @prereqs);
3015    }
3016    close (INPUT);
3017}
3018
3019#############################################################################
3020# Function    : ReadArgsFile
3021# Description : This reads in an existing file which contains information on
3022#               all GTK args. It creates the arrays @ArgObjects, @ArgNames,
3023#               @ArgTypes, @ArgFlags, @ArgNicks and @ArgBlurbs containing info
3024#               on the args.
3025# Arguments   : $file - the file containing the arg information.
3026#############################################################################
3027
3028sub ReadArgsFile {
3029    my ($file) = @_;
3030
3031    my $in_arg = 0;
3032    my $arg_object;
3033    my $arg_name;
3034    my $arg_type;
3035    my $arg_flags;
3036    my $arg_nick;
3037    my $arg_blurb;
3038
3039    # Reset the args info.
3040    @ArgObjects = ();
3041    @ArgNames = ();
3042    @ArgTypes = ();
3043    @ArgFlags = ();
3044    @ArgNicks = ();
3045    @ArgBlurbs = ();
3046
3047    if (! -f $file) {
3048        return;
3049    }
3050    if (!open (INPUT, $file)) {
3051        warn "Can't open $file - skipping args\n";
3052        return;
3053    }
3054    while (<INPUT>) {
3055        if (!$in_arg) {
3056            if (m/^<ARG>/) {
3057                $in_arg = 1;
3058                $arg_object = "";
3059                $arg_name = "";
3060                $arg_type = "";
3061                $arg_flags = "";
3062                $arg_nick = "";
3063                $arg_blurb = "";
3064            }
3065        } else {
3066            if (m/^<NAME>(.*)<\/NAME>/) {
3067                $arg_name = $1;
3068                if ($arg_name =~ m/^(.*)::(.*)$/) {
3069                    $arg_object = $1;
3070                    ($arg_name = $2) =~ s/_/-/g;
3071#                   print "Found arg: $arg_name\n";
3072                } else {
3073                    print "Invalid arg name: $arg_name\n";
3074                }
3075            } elsif (m/^<TYPE>(.*)<\/TYPE>/) {
3076                $arg_type = $1;
3077            } elsif (m/^<FLAGS>(.*)<\/FLAGS>/) {
3078                $arg_flags = $1;
3079            } elsif (m/^<NICK>(.*)<\/NICK>/) {
3080                $arg_nick = $1;
3081            } elsif (m/^<BLURB>(.*)<\/BLURB>/) {
3082                $arg_blurb = $1;
3083                if ($arg_blurb eq "(null)") {
3084                  $arg_blurb = "";
3085                  print <<EOF;
3086WARNING: Property ${arg_object}::${arg_name} has NULL blurb.
3087EOF
3088                }
3089            } elsif (m%^</ARG>%) {
3090#               print "Found end of arg: ${arg_object}::${arg_name}\n${arg_type} : ${arg_flags}\n";
3091                push (@ArgObjects, $arg_object);
3092                push (@ArgNames, $arg_name);
3093                push (@ArgTypes, $arg_type);
3094                push (@ArgFlags, $arg_flags);
3095                push (@ArgNicks, $arg_nick);
3096                push (@ArgBlurbs, $arg_blurb);
3097                $in_arg = 0;
3098            }
3099        }
3100    }
3101    close (INPUT);
3102}
3103
3104
3105#############################################################################
3106# Function    : CheckIsObject
3107# Description : Returns 1 if the given name is a GtkObject or a subclass.
3108#               It uses the global @Objects array.
3109#               Note that the @Objects array only contains classes in the
3110#               current module and their ancestors - not all GTK classes.
3111# Arguments   : $name - the name to check.
3112#############################################################################
3113
3114sub CheckIsObject {
3115    my ($name) = @_;
3116
3117    my $object;
3118    foreach $object (@Objects) {
3119        if ($object eq $name) {
3120            return 1;
3121        }
3122    }
3123    return 0;
3124}
3125
3126
3127#############################################################################
3128# Function    : ParseStructDeclaration
3129# Description : This function takes a structure declaration and
3130#               breaks it into individual type declarations.
3131# Arguments   : $declaration - the declaration to parse
3132#               $is_object - true if this is an object structure
3133#               $typefunc - function reference to apply to type
3134#               $namefunc - function reference to apply to name
3135#############################################################################
3136
3137sub ParseStructDeclaration {
3138    my ($declaration, $is_object, $typefunc, $namefunc) = @_;
3139
3140    # Remove all private parts of the declaration
3141
3142    # For objects, assume private
3143    if ($is_object) {
3144        $declaration =~ s!(struct\s+\w*\s*\{)
3145                          .*?
3146                          (?:/\*\s*<\s*public\s*>\s*\*/|(?=\}))!$1!msgx;
3147    }
3148   
3149    # Assume end of declaration if line begins with '}'
3150    $declaration =~ s!\n?[ \t]*/\*\s*<\s*(private|protected)\s*>\s*\*/
3151                      .*?
3152                      (?:/\*\s*<\s*public\s*>\s*\*/|(?=^\}))!!msgx;
3153   
3154    # Remove all other comments;
3155    $declaration =~ s@/\*([^*]+|\*(?!/))*\*/@ @g;
3156
3157    my @result = ();
3158
3159    if ($declaration =~ /^\s*$/) {
3160        return @result;
3161    }
3162
3163    # Prime match after "struct {" declaration
3164    if (!scalar($declaration =~ m/struct\s+\w*\s*\{/msg)) {
3165        die "Structure declaration '$declaration' does not begin with struct [NAME] {\n";
3166    }
3167
3168    # Treat lines in sequence, allowing singly nested anonymous structs
3169    # and unions.
3170    while ($declaration =~ m/\s*([^{;]+(\{[^\}]*\}[^{;]+)?);/msg) {
3171        my $line = $1;
3172       
3173        last if $line =~ /^\s*\}\s*\w*\s*$/;
3174
3175        # FIXME: Just ignore nested structs and unions for now
3176        next if $line =~ /{/;
3177
3178        # FIXME: The regexes here are the same as in OutputFunction;
3179        #        this functionality should be separated out.
3180
3181        if ($line =~ m/^
3182            (const\s+|unsigned\s+|volatile\s+)*(struct\s+)? # mod1
3183            (\w+)\s*                            # type
3184            (\**)\s*                            # ptr1
3185            (const\s+)?                         # mod2
3186            (\**)?\s*                           # ptr2
3187            (\w+(?:\s*,\s*\w+)*)\s*             # name
3188            (?:((?:\[[^\]]*\]\s*)+) |           # array
3189               (:\s*\d+))?\s*                   # bits
3190                       $/x) {
3191            my $mod1 = defined($1) ? $1 : "";
3192            if (defined($2)) { $mod1 .= $2; }
3193            my $type = $3;
3194            my $ptr1 = $4;
3195            my $mod2 = defined($5) ? $5 : "";
3196            my $ptr2 = $6;
3197            my $name = $7;
3198            $ptr1 = " " . $ptr1;
3199            my $array = defined($8) ? $8 : "";
3200            my $bits =  defined($9) ? " $9" : "";
3201            my $ptype = defined $typefunc ? $typefunc->($type) : $type;
3202           
3203            # FIXME:
3204            # As a hack, we allow the "name" to be of the form
3205            # "a, b, c". This isn't the correct C syntax, but
3206            # at least we get "gint16 x, y" right. Such constructs
3207            # should really be completely removed from the source.
3208            # Or we should really try to understand the C syntax
3209            # here...
3210           
3211            my @names = split /\s*,\s*/, $name;
3212            for my $n (@names) {
3213                push @result, $n;
3214                if (defined $namefunc) {
3215                    $n = $namefunc->($n);
3216                }
3217                push @result, "$mod1$ptype$ptr1$mod2$ptr2$n$array$bits";
3218            }
3219           
3220        # Try to match structure members which are functions
3221        } elsif ($line =~ m/^
3222                 (const\s+|G_CONST_RETURN\s+|unsigned\s+)*(struct\s+)?  # mod1
3223                 (\w+)\s*                             # type
3224                 (\**)\s*                             # ptr1
3225                 (const\s+)?                          # mod2
3226                 \(\s*\*\s*(\w+)\s*\)\s*              # name
3227                 \(([^)]*)\)\s*                       # func_params
3228                            $/x) {
3229
3230            my $mod1 = defined($1) ? $1 : "";
3231            if (defined($2)) { $mod1 .= $2; }
3232            my $type = $3;
3233            my $ptr1 = $4;
3234            my $mod2 = defined($5) ? $5 : "";
3235            my $name = $6;
3236            my $func_params = $7;
3237            my $ptype = defined $typefunc ? $typefunc->($type) : $type;
3238            my $pname = defined $namefunc ? $namefunc->($name) : $name;
3239           
3240            push @result, $name;
3241            push @result, "$mod1$ptype$ptr1$mod2 (*$pname) ($func_params)";
3242           
3243        } else {
3244            warn "Cannot parse structure field \"$line\"";
3245        }
3246    }
3247   
3248    return @result;
3249}
3250
3251
3252#############################################################################
3253# Function    : ParseEnumDeclaration
3254# Description : This function takes a enumeration declaration and
3255#               breaks it into individual enum member declarations.
3256# Arguments   : $declaration - the declaration to parse
3257#############################################################################
3258
3259sub ParseEnumDeclaration {
3260    my ($declaration, $is_object) = @_;
3261
3262    # Remove comments;
3263    $declaration =~ s@/\*([^*]+|\*(?!/))*\*/@ @g;
3264
3265    my @result = ();
3266
3267    if ($declaration =~ /^\s*$/) {
3268        return @result;
3269    }
3270
3271    # Remove parenthesized expressions (in macros like GTK_BLAH = BLAH(1,3))
3272    # to avoid getting confused by commas they might contain. This
3273    # doesn't handle nested parentheses correctly.
3274
3275    $declaration =~ s/\([^)]+\)//g;
3276
3277    # Remove comma from comma - possible whitespace - closing brace sequence
3278    # since it is legal in GNU C and C99 to have a trailing comma but doesn't
3279    # result in an actual enum member
3280
3281    $declaration =~ s/,(\s*})/$1/g;
3282
3283    # Prime match after "typedef enum {" declaration
3284    if (!scalar($declaration =~ m/typedef\s+enum\s*\{/msg)) {
3285        die "Enum declaration '$declaration' does not begin with typedef enum {\n";
3286    }
3287
3288    # Treat lines in sequence.
3289    while ($declaration =~ m/\s*([^,\}]+)([,\}])/msg) {
3290        my $line = $1;
3291        my $terminator = $2;
3292
3293        if ($line =~ m/^(\w+)\s*(=.*)?$/msg) {
3294            push @result, $1;
3295           
3296        # Special case for GIOCondition, where the values are specified by
3297        # macros which expand to include the equal sign like '=1'.
3298        } elsif ($line =~ m/^(\w+)\s*GLIB_SYSDEF_POLL/msg) {
3299            push @result, $1;
3300           
3301        # Special case include of <gdk/gdkcursors.h>, just ignore it
3302        } elsif ($line =~ m/^#include/) {
3303            last;
3304
3305        } else {
3306            warn "Cannot parse enumeration member \"$line\"";
3307        }
3308
3309        last if $terminator eq '}';
3310    }
3311   
3312    return @result;
3313}
Note: See TracBrowser for help on using the repository browser.