4 # gtk-doc - GTK DocBook documentation generator.
5 # Copyright (C) 1998 Damon Chaplin
6 # 2007,2008,2009 Stefan Kost
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #############################################################################
24 # Script : gtkdoc-mkdb
25 # Description : This creates the DocBook files from the edited templates.
26 #############################################################################
32 push @INC, '@PACKAGE_DATA_DIR@';
33 require "gtkdoc-common.pl";
37 # name of documentation module
42 my $SOURCE_SUFFIXES = "";
43 my $IGNORE_FILES = "";
47 my $EXPAND_CONTENT_FILES = "";
48 my $INLINE_MARKUP_MODE;
49 my $DEFAULT_STABILITY;
53 my $OUTPUT_ALL_SYMBOLS;
54 my $OUTPUT_SYMBOLS_WITHOUT_SINCE;
58 my $PREREQUISITES_FILE;
62 # These global arrays store information on signals. Each signal has an entry
63 # in each of these arrays at the same index, like a multi-dimensional array.
64 my @SignalObjects; # The GtkObject which emits the signal.
65 my @SignalNames; # The signal name.
66 my @SignalReturns; # The return type.
67 my @SignalFlags; # Flags for the signal
68 my @SignalPrototypes; # The rest of the prototype of the signal handler.
70 # These global arrays store information on Args. Each Arg has an entry
71 # in each of these arrays at the same index, like a multi-dimensional array.
72 my @ArgObjects; # The GtkObject which has the Arg.
73 my @ArgNames; # The Arg name.
74 my @ArgTypes; # The Arg type - gint, GtkArrowType etc.
75 my @ArgFlags; # How the Arg can be used - readable/writable etc.
76 my @ArgNicks; # The nickname of the Arg.
77 my @ArgBlurbs; # Docstring of the Arg.
78 my @ArgDefaults; # Default value of the Arg.
79 my @ArgRanges; # The range of the Arg type
80 # These global hashes store declaration info keyed on a symbol name.
83 my %DeclarationConditional;
84 my %DeclarationOutput;
90 # These global hashes store the existing documentation.
96 my %SymbolAnnotations;
98 # These global hashes store documentation scanned from the source files.
100 my %SourceSymbolParams;
101 my %SourceSymbolSourceFile;
102 my %SourceSymbolSourceLine;
104 # all documentation goes in here, so we can do coverage analysis
106 my %AllIncompleteSymbols;
107 my %AllUnusedSymbols;
108 my %AllDocumentedSymbols;
110 # Undeclared yet documented symbols
111 my %UndeclaredSymbols;
113 # These global arrays store GObject, subclasses and the hierarchy (also of
114 # non-object derived types).
122 # holds the symbols which are mentioned in $MODULE-sections.txt and in which
123 # section they are defined
128 # collects index entries
129 my %IndexEntriesFull;
130 my %IndexEntriesSince;
131 my %IndexEntriesDeprecated;
133 # Standard C preprocessor directives, which we ignore for '#' abbreviations.
134 my %PreProcessorDirectives = (
152 # remember used annotation (to write minimal glossary)
155 my %AnnotationDefinition = (
156 # the GObjectIntrospection annotations are defined at:
157 # https://live.gnome.org/GObjectIntrospection/Annotations
158 'allow-none' => "NULL is OK, both for passing and for returning.",
159 'nullable' => "NULL may be passed as the value in, out, in-out; or as a return value.",
160 'optional' => "NULL may be passed instead of a pointer to a location.",
161 'array' => "Parameter points to an array of items.",
162 'attribute' => "Deprecated free-form custom annotation, replaced by (attributes) annotation.",
163 'attributes' => "Free-form key-value pairs.",
164 'closure' => "This parameter is a 'user_data', for callbacks; many bindings can pass NULL here.",
165 'constructor' => "This symbol is a constructor, not a static method.",
166 'destroy' => "This parameter is a 'destroy_data', for callbacks.",
167 'default' => "Default parameter value (for in case the <acronym>shadows</acronym>-to function has less parameters).",
168 'element-type' => "Generics and defining elements of containers and arrays.",
169 'error-domains' => "Typed errors. Similar to throws in Java.",
170 'foreign' => "This is a foreign struct.",
171 'get-value-func' => "The specified function is used to convert a struct from a GValue, must be a GTypeInstance.",
172 'in' => "Parameter for input. Default is <acronym>transfer none</acronym>.",
173 'inout' => "Parameter for input and for returning results. Default is <acronym>transfer full</acronym>.",
174 'in-out' => "Parameter for input and for returning results. Default is <acronym>transfer full</acronym>.",
175 'method' => "This is a method",
176 'not-error' => "A GError parameter is not to be handled like a normal GError.",
177 'out' => "Parameter for returning results. Default is <acronym>transfer full</acronym>.",
178 'out caller-allocates' => "Out parameter, where caller must allocate storage.",
179 'out callee-allocates' => "Out parameter, where caller must allocate storage.",
180 'ref-func' => "The specified function is used to ref a struct, must be a GTypeInstance.",
181 'rename-to' => "Rename the original symbol's name to SYMBOL.",
182 'scope call' => "The callback is valid only during the call to the method.",
183 'scope async' => "The callback is valid until first called.",
184 'scope notified' => "The callback is valid until the GDestroyNotify argument is called.",
185 'set-value-func' => "The specified function is used to convert from a struct to a GValue, must be a GTypeInstance.",
186 'skip' => "Exposed in C code, not necessarily available in other languages.",
187 'transfer container' => "Free data container after the code is done.",
188 'transfer floating' => "Alias for <acronym>transfer none</acronym>, used for objects with floating refs.",
189 'transfer full' => "Free data after the code is done.",
190 'transfer none' => "Don't free data after the code is done.",
191 'type' => "Override the parsed C type with given type.",
192 'unref-func' => "The specified function is used to unref a struct, must be a GTypeInstance.",
193 'virtual' => "This is the invoker for a virtual method.",
194 'value' => "The specified value overrides the evaluated value of the constant.",
195 # Stability Level definition
196 # https://bugzilla.gnome.org/show_bug.cgi?id=170860
198 The intention of a Stable interface is to enable arbitrary third parties to
199 develop applications to these interfaces, release them, and have confidence that
200 they will run on all minor releases of the product (after the one in which the
201 interface was introduced, and within the same major release). Even at a major
202 release, incompatible changes are expected to be rare, and to have strong
206 Unstable interfaces are experimental or transitional. They are typically used to
207 give outside developers early access to new or rapidly changing technology, or
208 to provide an interim solution to a problem where a more general solution is
209 anticipated. No claims are made about either source or binary compatibility from
210 one minor release to the next.
212 The Unstable interface level is a warning that these interfaces are subject to
213 change without warning and should not be used in unbundled products.
215 Given such caveats, customer impact need not be a factor when considering
216 incompatible changes to an Unstable interface in a major or minor release.
217 Nonetheless, when such changes are introduced, the changes should still be
218 mentioned in the release notes for the affected release.
221 An interface that can be used within the GNOME stack itself, but that is not
222 documented for end-users. Such functions should only be used in specified and
227 # Elements to consider non-block items in MarkDown parsing
228 my %MD_TEXT_LEVEL_ELEMENTS = ( "literal" => 1,
242 my %MD_ESCAPABLE_CHARS = ( "\\" => 1,
258 my %MD_GTK_ESCAPABLE_CHARS = ( "@" => 1,
261 # Function and other declaration output settings.
262 my $RETURN_TYPE_FIELD_WIDTH = 20;
263 my $SYMBOL_FIELD_WIDTH = 36;
264 my $MAX_SYMBOL_FIELD_WIDTH = 40;
265 my $SIGNAL_FIELD_WIDTH = 16;
266 my $PARAM_FIELD_COUNT = 2;
268 # XML, SGML formatting helper
272 run() unless caller; # Run program unless loaded as a module
276 my %optctl = ('module' => \$MODULE,
277 'source-dir' => \@SOURCE_DIRS,
278 'source-suffixes' => \$SOURCE_SUFFIXES,
279 'ignore-files' => \$IGNORE_FILES,
280 'output-dir' => \$DB_OUTPUT_DIR,
281 'tmpl-dir' => \$TMPL_DIR,
282 'version' => \$PRINT_VERSION,
283 'help' => \$PRINT_HELP,
284 'main-sgml-file' => \$MAIN_SGML_FILE,
285 'expand-content-files' => \$EXPAND_CONTENT_FILES,
286 'sgml-mode' => \$INLINE_MARKUP_MODE,
287 'xml-mode' => \$INLINE_MARKUP_MODE,
288 'default-stability' => \$DEFAULT_STABILITY,
289 'default-includes' => \$DEFAULT_INCLUDES,
290 'output-format' => \$OUTPUT_FORMAT,
291 'name-space' => \$NAME_SPACE,
292 'outputallsymbols' => \$OUTPUT_ALL_SYMBOLS,
293 'outputsymbolswithoutsince' => \$OUTPUT_SYMBOLS_WITHOUT_SINCE
295 GetOptions(\%optctl, "module=s", "source-dir:s", "source-suffixes:s",
296 "ignore-files:s", "output-dir:s", "tmpl-dir:s", "version",
297 "outputallsymbols", "outputsymbolswithoutsince",
298 "expand-content-files:s", "main-sgml-file:s", "extra-db-files:s", "help",
299 "sgml-mode", "xml-mode", "default-stability:s", "default-includes:s",
300 "output-format:s", "name-space:s");
302 if ($PRINT_VERSION) {
311 if ($DEFAULT_STABILITY && $DEFAULT_STABILITY ne "Stable"
312 && $DEFAULT_STABILITY ne "Private" && $DEFAULT_STABILITY ne "Unstable") {
318 gtkdoc-mkdb version @VERSION@ - generate docbook files
320 --module=MODULE_NAME Name of the doc module being parsed
321 --source-dir=DIRNAME Directories which contain inline reference material
322 --source-suffixes=SUFFIXES Suffixes of source files to scan, comma-separated
323 --ignore-files=FILES A space-separated list of header files/dirs not to
325 --output-dir=DIRNAME Directory to put the generated DocBook files in
326 --tmpl-dir=DIRNAME Directory in which template files may be found
327 --main-sgml-file=FILE File containing the toplevel DocBook file.
328 --expand-content-files=FILES Extra DocBook files to expand abbreviations in.
329 --output-format=FORMAT Format to use for the generated docbook, XML or SGML.
330 --{xml,sgml}-mode Allow DocBook markup in inline documentation.
331 --default-stability=LEVEL Specify default stability Level. Valid values are
332 Stable, Unstable, or Private.
333 --default-includes=FILENAMES Specify default includes for section Synopsis
334 --name-space=NS Omit namespace in index.
335 --version Print the version of this program
336 --help Print this help
341 @TRACE@(" ignore files: [$IGNORE_FILES]\n");
343 # check output format
344 if (! defined($OUTPUT_FORMAT) || ($OUTPUT_FORMAT eq "")) {
345 $OUTPUT_FORMAT = "xml";
347 $OUTPUT_FORMAT = lc($OUTPUT_FORMAT);
349 if ($OUTPUT_FORMAT ne "xml") {
350 die "Invalid format '$OUTPUT_FORMAT' passed to --output.format"
353 if (!$MAIN_SGML_FILE) {
354 # backwards compatibility
355 if (-e "${MODULE}-docs.sgml") {
356 $MAIN_SGML_FILE = "${MODULE}-docs.sgml";
358 $MAIN_SGML_FILE = "${MODULE}-docs.xml";
362 # extract docbook header or define default
363 if (-e $MAIN_SGML_FILE) {
364 open(INPUT, "<$MAIN_SGML_FILE") || die "Can't open $MAIN_SGML_FILE";
365 $doctype_header = "";
367 if (/^\s*<(book|chapter|article)/) {
368 # check that the top-level tagSYSTEM or the doctype decl contain the xinclude namespace decl
369 if (($_ !~ m/http:\/\/www.w3.org\/200[13]\/XInclude/) && ($doctype_header !~ m/http:\/\/www.w3.org\/200[13]\/XInclude/m)) {
370 $doctype_header = "";
374 # if there are SYSTEM ENTITIES here, we should prepend "../" to the path
375 # FIXME: not sure if we can do this now, as people already work-around the problem
376 # s#<!ENTITY % ([a-zA-Z-]+) SYSTEM \"([^/][a-zA-Z./]+)\">#<!ENTITY % $1 SYSTEM \"../$2\">#;
377 s#<!ENTITY % gtkdocentities SYSTEM \"([^"]*)\">#<!ENTITY % gtkdocentities SYSTEM \"../$1\">#;
378 $doctype_header .= $_;
382 $doctype_header = <<EOF;
383 <?xml version="1.0"?>
384 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
385 "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
387 <!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
388 <!ENTITY % gtkdocentities SYSTEM "../xml/gtkdocentities.ent">
393 chomp($doctype_header);
395 # All the files are written in subdirectories beneath here.
396 $TMPL_DIR = $TMPL_DIR ? $TMPL_DIR : "$ROOT_DIR/tmpl";
398 # This is where we put all the DocBook output.
399 $DB_OUTPUT_DIR = $DB_OUTPUT_DIR ? $DB_OUTPUT_DIR : "$ROOT_DIR/xml";
401 # This file contains the object hierarchy.
402 $OBJECT_TREE_FILE = "$ROOT_DIR/$MODULE.hierarchy";
404 # This file contains the interfaces.
405 $INTERFACES_FILE = "$ROOT_DIR/$MODULE.interfaces";
407 # This file contains the prerequisites.
408 $PREREQUISITES_FILE = "$ROOT_DIR/$MODULE.prerequisites";
410 # This file contains signal arguments and names.
411 $SIGNALS_FILE = "$ROOT_DIR/$MODULE.signals";
413 # The file containing Arg information.
414 $ARGS_FILE = "$ROOT_DIR/$MODULE.args";
416 # Create the root DocBook output directory if it doens't exist.
417 if (! -e $DB_OUTPUT_DIR) {
418 mkdir ("$DB_OUTPUT_DIR", 0777)
419 || die "Can't create directory: $DB_OUTPUT_DIR";
422 &ReadKnownSymbols ("$ROOT_DIR/$MODULE-sections.txt");
423 &ReadSignalsFile ($SIGNALS_FILE);
424 &ReadArgsFile ($ARGS_FILE);
425 &ReadObjectHierarchy;
429 &ReadDeclarationsFile ("$ROOT_DIR/$MODULE-decl.txt", 0);
430 if (-f "$ROOT_DIR/$MODULE-overrides.txt") {
431 &ReadDeclarationsFile ("$ROOT_DIR/$MODULE-overrides.txt", 1);
434 for my $dir (@SOURCE_DIRS) {
435 &ReadSourceDocumentation ($dir);
438 my $changed = &OutputDB ("$ROOT_DIR/$MODULE-sections.txt");
440 # If any of the DocBook files have changed, update the timestamp file (so
441 # it can be used for Makefile dependencies).
442 if ($changed || ! -e "$ROOT_DIR/sgml.stamp") {
444 # try to detect the common prefix
445 # GtkWidget, GTK_WIDGET, gtk_widget -> gtk
446 if ($NAME_SPACE eq "") {
453 foreach my $symbol (keys(%IndexEntriesFull)) {
454 if(($NAME_SPACE eq "") || $symbol =~ /^$NAME_SPACE/i) {
455 if (length($symbol)>$pos) {
456 $letter=substr($symbol,$pos,1);
457 # stop prefix scanning
458 if ($letter eq "_") {
462 # Should we also stop on a uppercase char, if last was lowercase
463 # GtkWidget, if we have the 'W' and had the 't' before
464 # or should we count upper and lowercase, and stop one 2nd uppercase, if we already had a lowercase
465 # GtkWidget, the 'W' would be the 2nd uppercase and with 't','k' we had lowercase chars before
466 # need to recound each time as this is per symbol
467 $prefix{uc($letter)}++;
471 if ($letter ne "" && $letter ne "_") {
474 foreach $letter (keys(%prefix)) {
475 #print "$letter: $prefix{$letter}.\n";
476 if ($prefix{$letter}>$maxsymbols) {
478 $maxsymbols=$prefix{$letter};
481 $ratio = scalar(keys(%IndexEntriesFull)) / $prefix{$maxletter};
482 #print "most symbols start with $maxletter, that is ". (100 * $ratio) ." %\n";
485 $NAME_SPACE .= $maxletter;
492 } while ($ratio > 0.9);
493 #print "most symbols start with $NAME_SPACE\n";
497 &OutputDeprecatedIndex;
499 &OutputAnnotationGlossary;
501 open (TIMESTAMP, ">$ROOT_DIR/sgml.stamp")
502 || die "Can't create $ROOT_DIR/sgml.stamp: $!";
503 print (TIMESTAMP "timestamp");
508 #############################################################################
509 # Function : OutputObjectList
510 # Description : This outputs the alphabetical list of objects, in a columned
512 # FIXME: Currently this also outputs ancestor objects
513 # which may not actually be in this module.
515 #############################################################################
517 sub OutputObjectList {
521 # my $old_object_index = "$DB_OUTPUT_DIR/object_index.xml";
522 my $old_object_index = "$DB_OUTPUT_DIR/object_index.sgml";
523 my $new_object_index = "$DB_OUTPUT_DIR/object_index.new";
525 open (OUTPUT, ">$new_object_index")
526 || die "Can't create $new_object_index: $!";
528 print (OUTPUT <<EOF);
529 ${\( MakeDocHeader ("informaltable") )}
530 <informaltable pgwide="1" frame="none">
531 <tgroup cols="$cols">
532 <colspec colwidth="1*"/>
533 <colspec colwidth="1*"/>
534 <colspec colwidth="1*"/>
540 foreach $object (sort (@Objects)) {
541 my $xref = &MakeXRef ($object);
542 if ($count % $cols == 0) { print (OUTPUT "<row>\n"); }
543 print (OUTPUT "<entry>$xref</entry>\n");
544 if ($count % $cols == ($cols - 1)) { print (OUTPUT "</row>\n"); }
548 # emit an empty row, since empty tables are invalid
549 print (OUTPUT "<row><entry> </entry></row>\n");
552 if ($count % $cols > 0) {
553 print (OUTPUT "</row>\n");
557 print (OUTPUT <<EOF);
558 </tbody></tgroup></informaltable>
562 &UpdateFileIfChanged ($old_object_index, $new_object_index, 0);
565 #############################################################################
566 # Function : TrimTextBlock
567 # Description : Trims extra whitespace. Empty lines inside a block are
569 # Arguments : $desc - the text block to trim. May contain newlines.
570 #############################################################################
575 # strip leading spaces on the block
577 # strip trailing spaces on every line
578 $desc =~ s/\s+$/\n/mg;
584 #############################################################################
585 # Function : OutputDB
586 # Description : This collects the output for each section of the docs, and
587 # outputs each file when the end of the section is found.
588 # Arguments : $file - the $MODULE-sections.txt file which contains all of
589 # the functions/macros/structs etc. being documented, organised
590 # into sections and subsections.
591 #############################################################################
596 @TRACE@("Reading: $file\n");
598 || die "Can't open $file: $!";
601 my $book_bottom = "";
602 my $includes = (defined $DEFAULT_INCLUDES) ? $DEFAULT_INCLUDES : "";
603 my $section_includes = "";
610 my $functions_synop = "";
611 my $other_synop = "";
612 my $functions_details = "";
613 my $other_details = "";
614 my $signals_synop = "";
615 my $signals_desc = "";
617 my $child_args_synop = "";
618 my $style_args_synop = "";
620 my $child_args_desc = "";
621 my $style_args_desc = "";
622 my $hierarchy_str = "";
625 my $implementations = "";
626 my $prerequisites = "";
628 my @file_objects = ();
630 my %symbol_def_line = ();
632 # merge the source docs, in case there are no templates
633 &MergeSourceDocumentation;
639 } elsif (m/^<SECTION>/) {
643 %symbol_def_line = ();
645 } elsif (m/^<SUBSECTION\s*(.*)>/i) {
646 $other_synop .= "\n";
647 $functions_synop .= "\n";
650 } elsif (m/^<SUBSECTION>/) {
652 } elsif (m/^<TITLE>(.*)<\/TITLE>/) {
654 @TRACE@("Section: $title\n");
656 # We don't want warnings if object & class structs aren't used.
657 $DeclarationOutput{$title} = 1;
658 $DeclarationOutput{"${title}Class"} = 1;
659 $DeclarationOutput{"${title}Iface"} = 1;
660 $DeclarationOutput{"${title}Interface"} = 1;
662 } elsif (m/^<FILE>(.*)<\/FILE>/) {
664 if (! defined $templates{$filename}) {
665 if (&ReadTemplateFile ("$TMPL_DIR/$filename", 1)) {
666 &MergeSourceDocumentation;
667 $templates{$filename}=$.;
670 &LogWarning ($file, $., "Double <FILE>$filename</FILE> entry. ".
671 "Previous occurrence on line ".$templates{$filename}.".");
673 if (($title eq "") and (defined $SourceSymbolDocs{"$TMPL_DIR/$filename:Title"})) {
674 $title = $SourceSymbolDocs{"$TMPL_DIR/$filename:Title"};
675 # Remove trailing blanks
679 } elsif (m/^<INCLUDE>(.*)<\/INCLUDE>/) {
681 $section_includes = $1;
683 if (defined $DEFAULT_INCLUDES) {
684 &LogWarning ($file, $., "Default <INCLUDE> being overridden by command line option.");
691 } elsif (m/^<\/SECTION>/) {
692 @TRACE@("End of section: $title\n");
693 if ($num_symbols > 0) {
695 $book_bottom .= " <xi:include href=\"xml/$filename.xml\"/>\n";
697 if (defined ($SourceSymbolDocs{"$TMPL_DIR/$filename:Include"})) {
698 if ($section_includes) {
699 &LogWarning ($file, $., "Section <INCLUDE> being overridden by inline comments.");
701 $section_includes = $SourceSymbolDocs{"$TMPL_DIR/$filename:Include"};
703 if ($section_includes eq "") {
704 $section_includes = $includes;
707 $signals_synop =~ s/^\n*//g;
708 $signals_synop =~ s/\n+$/\n/g;
709 if ($signals_synop ne '') {
710 $signals_synop = <<EOF;
711 <refsect1 id="$section_id.signals" role="signal_proto">
712 <title role="signal_proto.title">Signals</title>
713 <informaltable frame="none">
715 <colspec colname="signals_return" colwidth="150px"/>
716 <colspec colname="signals_name" colwidth="300px"/>
717 <colspec colname="signals_flags" colwidth="200px"/>
725 $signals_desc = TrimTextBlock($signals_desc);
726 $signals_desc = <<EOF;
727 <refsect1 id="$section_id.signal-details" role="signals">
728 <title role="signals.title">Signal Details</title>
734 $args_synop =~ s/^\n*//g;
735 $args_synop =~ s/\n+$/\n/g;
736 if ($args_synop ne '') {
738 <refsect1 id="$section_id.properties" role="properties">
739 <title role="properties.title">Properties</title>
740 <informaltable frame="none">
742 <colspec colname="properties_type" colwidth="150px"/>
743 <colspec colname="properties_name" colwidth="300px"/>
744 <colspec colname="properties_flags" colwidth="200px"/>
752 $args_desc = TrimTextBlock($args_desc);
754 <refsect1 id="$section_id.property-details" role="property_details">
755 <title role="property_details.title">Property Details</title>
761 $child_args_synop =~ s/^\n*//g;
762 $child_args_synop =~ s/\n+$/\n/g;
763 if ($child_args_synop ne '') {
764 $args_synop .= <<EOF;
765 <refsect1 id="$section_id.child-properties" role="child_properties">
766 <title role="child_properties.title">Child Properties</title>
767 <informaltable frame="none">
769 <colspec colname="child_properties_type" colwidth="150px"/>
770 <colspec colname="child_properties_name" colwidth="300px"/>
771 <colspec colname="child_properties_flags" colwidth="200px"/>
779 $child_args_desc = TrimTextBlock($child_args_desc);
781 <refsect1 id="$section_id.child-property-details" role="child_property_details">
782 <title role="child_property_details.title">Child Property Details</title>
788 $style_args_synop =~ s/^\n*//g;
789 $style_args_synop =~ s/\n+$/\n/g;
790 if ($style_args_synop ne '') {
791 $args_synop .= <<EOF;
792 <refsect1 id="$section_id.style-properties" role="style_properties">
793 <title role="style_properties.title">Style Properties</title>
794 <informaltable frame="none">
796 <colspec colname="style_properties_type" colwidth="150px"/>
797 <colspec colname="style_properties_name" colwidth="300px"/>
798 <colspec colname="style_properties_flags" colwidth="200px"/>
806 $style_args_desc = TrimTextBlock($style_args_desc);
808 <refsect1 id="$section_id.style-property-details" role="style_properties_details">
809 <title role="style_properties_details.title">Style Property Details</title>
815 $hierarchy_str = &AddTreeLineArt(\@hierarchy);
816 if ($hierarchy_str ne "") {
817 $hierarchy_str = <<EOF;
818 <refsect1 id="$section_id.object-hierarchy" role="object_hierarchy">
819 <title role="object_hierarchy.title">Object Hierarchy</title>
820 <screen>$hierarchy_str
826 $interfaces =~ TrimTextBlock($interfaces);
827 if ($interfaces ne "") {
829 <refsect1 id="$section_id.implemented-interfaces" role="impl_interfaces">
830 <title role="impl_interfaces.title">Implemented Interfaces</title>
836 $implementations = TrimTextBlock($implementations);
837 if ($implementations ne "") {
838 $implementations = <<EOF;
839 <refsect1 id="$section_id.implementations" role="implementations">
840 <title role="implementations.title">Known Implementations</title>
846 $prerequisites = TrimTextBlock($prerequisites);
847 if ($prerequisites ne "") {
848 $prerequisites = <<EOF;
849 <refsect1 id="$section_id.prerequisites" role="prerequisites">
850 <title role="prerequisites.title">Prerequisites</title>
856 $derived = TrimTextBlock($derived);
857 if ($derived ne "") {
859 <refsect1 id="$section_id.derived-interfaces" role="derived_interfaces">
860 <title role="derived_interfaces.title">Known Derived Interfaces</title>
866 $functions_synop =~ s/^\n*//g;
867 $functions_synop =~ s/\n+$/\n/g;
868 if ($functions_synop ne '') {
869 $functions_synop = <<EOF;
870 <refsect1 id="$section_id.functions" role="functions_proto">
871 <title role="functions_proto.title">Functions</title>
872 <informaltable pgwide="1" frame="none">
874 <colspec colname="functions_return" colwidth="150px"/>
875 <colspec colname="functions_name"/>
885 $other_synop =~ s/^\n*//g;
886 $other_synop =~ s/\n+$/\n/g;
887 if ($other_synop ne '') {
888 $other_synop = <<EOF;
889 <refsect1 id="$section_id.other" role="other_proto">
890 <title role="other_proto.title">Types and Values</title>
891 <informaltable role="enum_members_table" pgwide="1" frame="none">
893 <colspec colname="name" colwidth="150px"/>
894 <colspec colname="description"/>
904 my $file_changed = &OutputDBFile ($filename, $title, $section_id,
906 \$functions_synop, \$other_synop,
907 \$functions_details, \$other_details,
908 \$signals_synop, \$signals_desc,
909 \$args_synop, \$args_desc,
910 \$hierarchy_str, \$interfaces,
912 \$prerequisites, \$derived,
922 $section_includes = "";
923 $functions_synop = "";
925 $functions_details = "";
930 $child_args_synop = "";
931 $style_args_synop = "";
933 $child_args_desc = "";
934 $style_args_desc = "";
938 $implementations = "";
942 } elsif (m/^(\S+)/) {
944 @TRACE@(" Symbol: $symbol in subsection: $subsection\n");
946 # check for duplicate entries
947 if (! defined $symbol_def_line{$symbol}) {
948 my $declaration = $Declarations{$symbol};
949 if (defined ($declaration)) {
950 if (&CheckIsObject ($symbol)) {
951 push @file_objects, $symbol;
953 # We don't want standard macros/functions of GObjects,
954 # or private declarations.
955 if ($subsection ne "Standard" && $subsection ne "Private") {
956 my ($synop, $desc) = &OutputDeclaration ($symbol,
958 my $type = $DeclarationTypes {$symbol};
960 if ($type eq 'FUNCTION' || $type eq 'USER_FUNCTION') {
961 $functions_synop .= $synop;
962 $functions_details .= $desc;
963 } elsif ($type eq 'MACRO' && $declaration =~ /$symbol[ ]*\(/) {
964 $functions_synop .= $synop;
965 $functions_details .= $desc;
967 $other_synop .= $synop;
968 $other_details .= $desc;
971 my ($sig_synop, $sig_desc) = &GetSignals ($symbol);
972 my ($arg_synop, $child_arg_synop, $style_arg_synop,
973 $arg_desc, $child_arg_desc, $style_arg_desc) = &GetArgs ($symbol);
974 my $ifaces = &GetInterfaces ($symbol);
975 my $impls = &GetImplementations ($symbol);
976 my $prereqs = &GetPrerequisites ($symbol);
977 my $der = &GetDerived ($symbol);
978 @hierarchy = &GetHierarchy ($symbol, \@hierarchy);
980 $signals_synop .= $sig_synop;
981 $signals_desc .= $sig_desc;
982 $args_synop .= $arg_synop;
983 $child_args_synop .= $child_arg_synop;
984 $style_args_synop .= $style_arg_synop;
985 $args_desc .= $arg_desc;
986 $child_args_desc .= $child_arg_desc;
987 $style_args_desc .= $style_arg_desc;
988 $interfaces .= $ifaces;
989 $implementations .= $impls;
990 $prerequisites .= $prereqs;
993 # Note that the declaration has been output.
994 $DeclarationOutput{$symbol} = 1;
995 } elsif ($subsection ne "Standard" && $subsection ne "Private") {
996 $UndeclaredSymbols{$symbol} = 1;
997 &LogWarning ($file, $., "No declaration found for $symbol.");
1000 $symbol_def_line{$symbol}=$.;
1002 if ($section_id eq "") {
1003 if($title eq "" && $filename eq "") {
1004 &LogWarning ($file, $., "Section has no title and no file.");
1006 # FIXME: one of those would be enough
1007 # filename should be an internal detail for gtk-doc
1010 } elsif ($filename eq "") {
1013 $filename =~ s/\s/_/g;
1015 $section_id = $SourceSymbolDocs{"$TMPL_DIR/$filename:Section_Id"};
1016 if (defined ($section_id) && $section_id !~ m/^\s*$/) {
1017 # Remove trailing blanks and use as is
1018 $section_id =~ s/\s+$//;
1019 } elsif (&CheckIsObject ($title)) {
1020 # GObjects use their class name as the ID.
1021 $section_id = &CreateValidSGMLID ($title);
1023 $section_id = &CreateValidSGMLID ("$MODULE-$title");
1026 $SymbolSection{$symbol}=$title;
1027 $SymbolSectionId{$symbol}=$section_id;
1030 &LogWarning ($file, $., "Double symbol entry for $symbol. ".
1031 "Previous occurrence on line ".$symbol_def_line{$symbol}.".");
1037 &OutputMissingDocumentation;
1038 &OutputUndeclaredSymbols;
1039 &OutputUnusedSymbols;
1041 if ($OUTPUT_ALL_SYMBOLS) {
1044 if ($OUTPUT_SYMBOLS_WITHOUT_SINCE) {
1045 &OutputSymbolsWithoutSince;
1048 for $filename (split (' ', $EXPAND_CONTENT_FILES)) {
1049 my $file_changed = &OutputExtraFile ($filename);
1050 if ($file_changed) {
1055 &OutputBook ($book_top, $book_bottom);
1060 #############################################################################
1061 # Function : OutputIndex
1062 # Description : This writes an indexlist that can be included into the main-
1063 # document into an <index> tag.
1064 #############################################################################
1067 my ($basename, $apiindexref ) = @_;
1068 my %apiindex = %{$apiindexref};
1069 my $old_index = "$DB_OUTPUT_DIR/$basename.xml";
1070 my $new_index = "$DB_OUTPUT_DIR/$basename.new";
1071 my $lastletter = " ";
1076 open (OUTPUT, ">$new_index")
1077 || die "Can't create $new_index";
1079 print (OUTPUT &MakeDocHeader ("indexdiv")."\n<indexdiv id=\"$basename\">\n");
1081 @TRACE@("generate $basename index (".%apiindex." entries)\n");
1083 # do a case insensitive sort while chopping off the prefix
1085 sort { $$a{criteria} cmp $$b{criteria} or $$a{original} cmp $$b{original} }
1086 map { my $x = uc($_); $x =~ s/^$NAME_SPACE\_?(.*)/$1/i; { criteria => $x, original => $_, short => $1 } }
1089 $symbol = $$hash{original};
1090 if (defined($$hash{short})) {
1091 $short_symbol = $$hash{short};
1093 $short_symbol = $symbol;
1096 # generate a short symbol description
1097 my $symbol_desc = "";
1098 my $symbol_section = "";
1099 my $symbol_section_id = "";
1100 my $symbol_type = "";
1101 if (defined($DeclarationTypes{$symbol})) {
1102 $symbol_type = lc($DeclarationTypes{$symbol});
1104 if ($symbol_type eq "") {
1105 @TRACE@("trying symbol $symbol\n");
1106 if ($symbol =~ m/(.*)::(.*)/) {
1110 @TRACE@(" trying object signal ${oname}:$osym in ".$#SignalNames." signals\n");
1111 for ($i = 0; $i <= $#SignalNames; $i++) {
1112 if ($SignalNames[$i] eq $osym) {
1113 $symbol_type = "object signal";
1114 if (defined($SymbolSection{$oname})) {
1115 $symbol_section = $SymbolSection{$oname};
1116 $symbol_section_id = $SymbolSectionId{$oname};
1121 } elsif ($symbol =~ m/(.*):(.*)/) {
1125 @TRACE@(" trying object property ${oname}::$osym in ".$#ArgNames." properties\n");
1126 for ($i = 0; $i <= $#ArgNames; $i++) {
1127 @TRACE@(" ".$ArgNames[$i]."\n");
1128 if ($ArgNames[$i] eq $osym) {
1129 $symbol_type = "object property";
1130 if (defined($SymbolSection{$oname})) {
1131 $symbol_section = $SymbolSection{$oname};
1132 $symbol_section_id = $SymbolSectionId{$oname};
1139 if (defined($SymbolSection{$symbol})) {
1140 $symbol_section = $SymbolSection{$symbol};
1141 $symbol_section_id = $SymbolSectionId{$symbol};
1144 if ($symbol_type ne "") {
1145 $symbol_desc=", $symbol_type";
1146 if ($symbol_section ne "") {
1147 $symbol_desc.=" in <link linkend=\"$symbol_section_id\">$symbol_section</link>";
1148 #$symbol_desc.=" in ". &ExpandAbbreviations($symbol, "#$symbol_section");
1152 my $curletter = uc(substr($short_symbol,0,1));
1153 my $id = $apiindex{$symbol};
1155 @TRACE@(" add symbol $symbol with $id to index in section $curletter\n");
1157 if ($curletter ne $lastletter) {
1158 $lastletter = $curletter;
1160 if ($divopen == 1) {
1161 print (OUTPUT "</indexdiv>\n");
1163 print (OUTPUT "<indexdiv><title>$curletter</title>\n");
1167 print (OUTPUT <<EOF);
1168 <indexentry><primaryie linkends="$id"><link linkend="$id">$symbol</link>$symbol_desc</primaryie></indexentry>
1172 if ($divopen == 1) {
1173 print (OUTPUT "</indexdiv>\n");
1175 print (OUTPUT "</indexdiv>\n");
1178 &UpdateFileIfChanged ($old_index, $new_index, 0);
1182 #############################################################################
1183 # Function : OutputIndexFull
1184 # Description : This writes the full api indexlist that can be included into the
1185 # main document into an <index> tag.
1186 #############################################################################
1188 sub OutputIndexFull {
1189 &OutputIndex ("api-index-full", \%IndexEntriesFull);
1193 #############################################################################
1194 # Function : OutputDeprecatedIndex
1195 # Description : This writes the deprecated api indexlist that can be included
1196 # into the main document into an <index> tag.
1197 #############################################################################
1199 sub OutputDeprecatedIndex {
1200 &OutputIndex ("api-index-deprecated", \%IndexEntriesDeprecated);
1204 #############################################################################
1205 # Function : OutputSinceIndexes
1206 # Description : This writes the 'since' api indexlists that can be included into
1207 # the main document into an <index> tag.
1208 #############################################################################
1210 sub OutputSinceIndexes {
1211 my @sinces = keys %{{ map { $_ => 1 } values %Since }};
1213 foreach my $version (@sinces) {
1214 @TRACE@("Since : [$version]\n");
1215 # TODO make filtered hash
1216 #my %index = grep { $Since{$_} eq $version } %IndexEntriesSince;
1217 my %index = map { $_ => $IndexEntriesSince{$_} } grep { $Since{$_} eq $version } keys %IndexEntriesSince;
1219 &OutputIndex ("api-index-$version", \%index);
1223 #############################################################################
1224 # Function : OutputAnnotationGlossary
1225 # Description : This writes a glossary of the used annotation terms into a
1226 # separate glossary file that can be included into the main
1228 #############################################################################
1230 sub OutputAnnotationGlossary {
1231 my $old_glossary = "$DB_OUTPUT_DIR/annotation-glossary.xml";
1232 my $new_glossary = "$DB_OUTPUT_DIR/annotation-glossary.new";
1233 my $lastletter = " ";
1236 # if there are no annotations used return
1237 return if (! keys(%AnnotationsUsed));
1239 # add acronyms that are referenced from acronym text
1241 foreach my $annotation (keys(%AnnotationsUsed)) {
1242 if(defined($AnnotationDefinition{$annotation})) {
1243 if($AnnotationDefinition{$annotation} =~ m/<acronym>([\w ]+)<\/acronym>/) {
1244 if (!exists($AnnotationsUsed{$1})) {
1245 $AnnotationsUsed{$1} = 1;
1252 open (OUTPUT, ">$new_glossary")
1253 || die "Can't create $new_glossary";
1255 print (OUTPUT <<EOF);
1256 ${\( MakeDocHeader ("glossary") )}
1257 <glossary id="annotation-glossary">
1258 <title>Annotation Glossary</title>
1261 foreach my $annotation (sort({lc $a cmp lc $b} keys(%AnnotationsUsed))) {
1262 if(defined($AnnotationDefinition{$annotation})) {
1263 my $def = $AnnotationDefinition{$annotation};
1264 my $curletter = uc(substr($annotation,0,1));
1266 if ($curletter ne $lastletter) {
1267 $lastletter = $curletter;
1269 if ($divopen == 1) {
1270 print (OUTPUT "</glossdiv>\n");
1272 print (OUTPUT "<glossdiv><title>$curletter</title>\n");
1275 print (OUTPUT <<EOF);
1277 <glossterm><anchor id="annotation-glossterm-$annotation"/>$annotation</glossterm>
1286 if ($divopen == 1) {
1287 print (OUTPUT "</glossdiv>\n");
1289 print (OUTPUT "</glossary>\n");
1292 &UpdateFileIfChanged ($old_glossary, $new_glossary, 0);
1295 #############################################################################
1296 # Function : ReadKnownSymbols
1297 # Description : This collects the names of non-private symbols from the
1298 # $MODULE-sections.txt file.
1299 # Arguments : $file - the $MODULE-sections.txt file which contains all of
1300 # the functions/macros/structs etc. being documented, organised
1301 # into sections and subsections.
1302 #############################################################################
1304 sub ReadKnownSymbols {
1307 my $subsection = "";
1309 @TRACE@("Reading: $file\n");
1311 || die "Can't open $file: $!";
1317 } elsif (m/^<SECTION>/) {
1320 } elsif (m/^<SUBSECTION\s*(.*)>/i) {
1323 } elsif (m/^<SUBSECTION>/) {
1326 } elsif (m/^<TITLE>(.*)<\/TITLE>/) {
1329 } elsif (m/^<FILE>(.*)<\/FILE>/) {
1330 $KnownSymbols{"$TMPL_DIR/$1:Long_Description"} = 1;
1331 $KnownSymbols{"$TMPL_DIR/$1:Short_Description"} = 1;
1334 } elsif (m/^<INCLUDE>(.*)<\/INCLUDE>/) {
1337 } elsif (m/^<\/SECTION>/) {
1340 } elsif (m/^(\S+)/) {
1343 if ($subsection ne "Standard" && $subsection ne "Private") {
1344 $KnownSymbols{$symbol} = 1;
1347 $KnownSymbols{$symbol} = 0;
1355 #############################################################################
1356 # Function : OutputDeclaration
1357 # Description : Returns the synopsis and detailed description DocBook
1358 # describing one function/macro etc.
1359 # Arguments : $symbol - the name of the function/macro begin described.
1360 # $declaration - the declaration of the function/macro.
1361 #############################################################################
1363 sub OutputDeclaration {
1364 my ($symbol, $declaration) = @_;
1366 my $type = $DeclarationTypes {$symbol};
1367 if ($type eq 'MACRO') {
1368 return &OutputMacro ($symbol, $declaration);
1369 } elsif ($type eq 'TYPEDEF') {
1370 return &OutputTypedef ($symbol, $declaration);
1371 } elsif ($type eq 'STRUCT') {
1372 return &OutputStruct ($symbol, $declaration);
1373 } elsif ($type eq 'ENUM') {
1374 return &OutputEnum ($symbol, $declaration);
1375 } elsif ($type eq 'UNION') {
1376 return &OutputUnion ($symbol, $declaration);
1377 } elsif ($type eq 'VARIABLE') {
1378 return &OutputVariable ($symbol, $declaration);
1379 } elsif ($type eq 'FUNCTION') {
1380 return &OutputFunction ($symbol, $declaration, $type);
1381 } elsif ($type eq 'USER_FUNCTION') {
1382 return &OutputFunction ($symbol, $declaration, $type);
1384 die "Unknown symbol type";
1389 #############################################################################
1390 # Function : OutputSymbolTraits
1391 # Description : Returns the Since and StabilityLevel paragraphs for a symbol.
1392 # Arguments : $symbol - the name of the function/macro begin described.
1393 #############################################################################
1395 sub OutputSymbolTraits {
1399 if (exists $Since{$symbol}) {
1400 my $link_id = "api-index-".$Since{$symbol};
1401 $desc .= "<para role=\"since\">Since: <link linkend=\"$link_id\">$Since{$symbol}</link></para>";
1403 if (exists $StabilityLevel{$symbol}) {
1404 my $stability = $StabilityLevel{$symbol};
1405 $AnnotationsUsed{$stability} = 1;
1406 $desc .= "<para role=\"stability\">Stability Level: <acronym>$stability</acronym></para>";
1411 #############################################################################
1412 # Function : Output{Symbol,Section}ExtraLinks
1413 # Description : Returns extralinks for the symbol (if enabled).
1414 # Arguments : $symbol - the name of the function/macro begin described.
1415 #############################################################################
1419 return undef unless defined $text;
1421 # Build a char to hex map
1424 $escapes{chr($_)} = sprintf("%%%02X", $_);
1427 # Default unsafe characters. RFC 2732 ^(uric - reserved)
1428 $text =~ s/([^A-Za-z0-9\-_.!~*'()])/$escapes{$1}/g;
1433 sub OutputSymbolExtraLinks {
1437 if (0) { # NEW FEATURE: needs configurability
1438 my $sstr = &uri_escape($symbol);
1439 my $mstr = &uri_escape($MODULE);
1441 <ulink role="extralinks" url="http://www.google.com/codesearch?q=$sstr">code search</ulink>
1442 <ulink role="extralinks" url="http://library.gnome.org/edit?module=$mstr&symbol=$sstr">edit documentation</ulink>
1448 sub OutputSectionExtraLinks {
1449 my ($symbol,$docsymbol) = @_;
1452 if (0) { # NEW FEATURE: needs configurability
1453 my $sstr = &uri_escape($symbol);
1454 my $mstr = &uri_escape($MODULE);
1455 my $dsstr = &uri_escape($docsymbol);
1457 <ulink role="extralinks" url="http://www.google.com/codesearch?q=$sstr">code search</ulink>
1458 <ulink role="extralinks" url="http://library.gnome.org/edit?module=$mstr&symbol=$dsstr">edit documentation</ulink>
1465 #############################################################################
1466 # Function : OutputMacro
1467 # Description : Returns the synopsis and detailed description of a macro.
1468 # Arguments : $symbol - the macro.
1469 # $declaration - the declaration of the macro.
1470 #############################################################################
1473 my ($symbol, $declaration) = @_;
1474 my $id = &CreateValidSGMLID ($symbol);
1475 my $condition = &MakeConditionDescription ($symbol);
1476 my $synop = "<row><entry role=\"define_keyword\">#define</entry><entry role=\"function_name\"><link linkend=\"$id\">$symbol</link>";
1479 my @fields = ParseMacroDeclaration($declaration, \&CreateValidSGML);
1480 my $title = $symbol . (@fields ? "()" : "");
1482 $desc = "<refsect2 id=\"$id\" role=\"macro\"$condition>\n<title>$title</title>\n";
1483 $desc .= MakeIndexterms($symbol, $id);
1485 $desc .= OutputSymbolExtraLinks($symbol);
1488 $synop .= "<phrase role=\"c_punctuation\">()</phrase>";
1490 $synop .= "</entry></row>\n";
1492 # Don't output the macro definition if is is a conditional macro or it
1493 # looks like a function, i.e. starts with "g_" or "_?gnome_", or it is
1494 # longer than 2 lines, otherwise we get lots of complicated macros like
1496 if (!defined ($DeclarationConditional{$symbol}) && ($symbol !~ m/^g_/)
1497 && ($symbol !~ m/^_?gnome_/) && (($declaration =~ tr/\n//) < 2)) {
1498 my $decl_out = &CreateValidSGML ($declaration);
1499 $desc .= "<programlisting language=\"C\">$decl_out</programlisting>\n";
1501 $desc .= "<programlisting language=\"C\">" . &MakeReturnField("#define") . "$symbol";
1502 if ($declaration =~ m/^\s*#\s*define\s+\w+(\([^\)]*\))/) {
1504 my $pad = ' ' x ($RETURN_TYPE_FIELD_WIDTH - length ("#define "));
1505 # Align each line so that if should all line up OK.
1506 $args =~ s/\n/\n$pad/gm;
1507 $desc .= &CreateValidSGML ($args);
1509 $desc .= "</programlisting>\n";
1512 $desc .= &MakeDeprecationNote($symbol);
1514 my $parameters = &OutputParamDescriptions ("MACRO", $symbol, @fields);
1516 if (defined ($SymbolDocs{$symbol})) {
1517 my $symbol_docs = &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
1518 $desc .= $symbol_docs;
1521 $desc .= $parameters;
1522 $desc .= OutputSymbolTraits ($symbol);
1523 $desc .= "</refsect2>\n";
1524 return ($synop, $desc);
1528 #############################################################################
1529 # Function : OutputTypedef
1530 # Description : Returns the synopsis and detailed description of a typedef.
1531 # Arguments : $symbol - the typedef.
1532 # $declaration - the declaration of the typedef,
1533 # e.g. 'typedef unsigned int guint;'
1534 #############################################################################
1537 my ($symbol, $declaration) = @_;
1538 my $id = &CreateValidSGMLID ($symbol);
1539 my $condition = &MakeConditionDescription ($symbol);
1540 my $desc = "<refsect2 id=\"$id\" role=\"typedef\"$condition>\n<title>$symbol</title>\n";
1541 my $synop = "<row><entry role=\"typedef_keyword\">typedef</entry><entry role=\"function_name\"><link linkend=\"$id\">$symbol</link></entry></row>\n";
1543 $desc .= MakeIndexterms($symbol, $id);
1545 $desc .= OutputSymbolExtraLinks($symbol);
1547 if (!defined ($DeclarationConditional{$symbol})) {
1548 my $decl_out = &CreateValidSGML ($declaration);
1549 $desc .= "<programlisting language=\"C\">$decl_out</programlisting>\n";
1552 $desc .= &MakeDeprecationNote($symbol);
1554 if (defined ($SymbolDocs{$symbol})) {
1555 $desc .= &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
1557 $desc .= OutputSymbolTraits ($symbol);
1558 $desc .= "</refsect2>\n";
1559 return ($synop, $desc);
1563 #############################################################################
1564 # Function : OutputStruct
1565 # Description : Returns the synopsis and detailed description of a struct.
1566 # We check if it is a object struct, and if so we only output
1567 # parts of it that are noted as public fields.
1568 # We also use a different IDs for object structs, since the
1569 # original ID is used for the entire RefEntry.
1570 # Arguments : $symbol - the struct.
1571 # $declaration - the declaration of the struct.
1572 #############################################################################
1575 my ($symbol, $declaration) = @_;
1578 my $default_to_public = 1;
1579 if (&CheckIsObject ($symbol)) {
1580 @TRACE@("Found struct gtype: $symbol\n");
1582 $default_to_public = $ObjectRoots{$symbol} eq 'GBoxed';
1588 $id = &CreateValidSGMLID ($symbol . "_struct");
1589 $condition = &MakeConditionDescription ($symbol . "_struct");
1591 $id = &CreateValidSGMLID ($symbol);
1592 $condition = &MakeConditionDescription ($symbol);
1595 # Determine if it is a simple struct or it also has a typedef.
1596 my $has_typedef = 0;
1597 if ($StructHasTypedef{$symbol} || $declaration =~ m/^\s*typedef\s+/) {
1604 # For structs with typedefs we just output the struct name.
1606 $desc = "<refsect2 id=\"$id\" role=\"struct\"$condition>\n<title>$symbol</title>\n";
1608 $type_output = "struct";
1609 $desc = "<refsect2 id=\"$id\" role=\"struct\"$condition>\n<title>struct $symbol</title>\n";
1611 my $synop = "<row><entry role=\"datatype_keyword\">${type_output}</entry><entry role=\"function_name\"><link linkend=\"$id\">$symbol</link></entry></row>\n";
1613 $desc .= MakeIndexterms($symbol, $id);
1615 $desc .= OutputSymbolExtraLinks($symbol);
1617 # Form a pretty-printed, private-data-removed form of the declaration
1620 if ($declaration =~ m/^\s*$/) {
1621 @TRACE@("Found opaque struct: $symbol\n");
1622 $decl_out = "typedef struct _$symbol $symbol;";
1623 } elsif ($declaration =~ m/^\s*struct\s+\w+\s*;\s*$/) {
1624 @TRACE@("Found opaque struct: $symbol\n");
1625 $decl_out = "struct $symbol;";
1627 my $public = $default_to_public;
1628 my $new_declaration = "";
1630 my $decl = $declaration;
1632 if ($decl =~ m/^\s*(typedef\s+)?struct\s*\w*\s*(?:\/\*.*\*\/)?\s*{(.*)}\s*\w*\s*;\s*$/s) {
1633 my $struct_contents = $2;
1635 foreach $decl_line (split (/\n/, $struct_contents)) {
1636 @TRACE@("Struct line: $decl_line\n");
1637 if ($decl_line =~ m%/\*\s*<\s*public\s*>\s*\*/%) {
1639 } elsif ($decl_line =~ m%/\*\s*<\s*(private|protected)\s*>\s*\*/%) {
1642 $new_declaration .= $decl_line . "\n";
1646 if ($new_declaration) {
1647 # Strip any blank lines off the ends.
1648 $new_declaration =~ s/^\s*\n//;
1649 $new_declaration =~ s/\n\s*$/\n/;
1652 $decl_out = "typedef struct {\n" . $new_declaration
1655 $decl_out = "struct $symbol {\n" . $new_declaration
1660 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
1661 "Couldn't parse struct:\n$declaration");
1664 # If we couldn't parse the struct or it was all private, output an
1665 # empty struct declaration.
1666 if ($decl_out eq "") {
1668 $decl_out = "typedef struct _$symbol $symbol;";
1670 $decl_out = "struct $symbol;";
1675 $decl_out = &CreateValidSGML ($decl_out);
1676 $desc .= "<programlisting language=\"C\">$decl_out</programlisting>\n";
1678 $desc .= &MakeDeprecationNote($symbol);
1680 if (defined ($SymbolDocs{$symbol})) {
1681 $desc .= &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
1684 # Create a table of fields and descriptions
1686 # FIXME: Inserting  's into the produced type declarations here would
1687 # improve the output in most situations ... except for function
1688 # members of structs!
1689 my @fields = ParseStructDeclaration($declaration, !$default_to_public,
1692 "<structfield id=\"".&CreateValidSGMLID("$id.$_[0]")."\">$_[0]</structfield>";
1694 my $params = $SymbolParams{$symbol};
1696 # If no parameters are filled in, we don't generate the description
1697 # table, for backwards compatibility.
1700 if (defined $params) {
1701 for (my $i = 1; $i <= $#$params; $i += $PARAM_FIELD_COUNT) {
1702 if ($params->[$i] =~ /\S/) {
1710 my %field_descrs = @$params;
1711 my $missing_parameters = "";
1712 my $unused_parameters = "";
1715 <refsect3 role="struct_members">\n<title>Members</title>
1716 <informaltable role="struct_members_table" pgwide="1" frame="none">
1718 <colspec colname="struct_members_name" colwidth="300px"/>
1719 <colspec colname="struct_members_description"/>
1720 <colspec colname="struct_members_annotations" colwidth="200px"/>
1725 my $field_name = shift @fields;
1726 my $text = shift @fields;
1727 my $field_descr = $field_descrs{$field_name};
1728 my $param_annotations = "";
1730 $desc .= "<row role=\"member\"><entry role=\"struct_member_name\"><para>$text</para></entry>\n";
1731 if (defined $field_descr) {
1732 ($field_descr,$param_annotations) = &ExpandAnnotation($symbol, $field_descr);
1733 $field_descr = &ConvertMarkDown($symbol, $field_descr);
1735 $field_descr =~ s/^(\s|\n)+//msg;
1736 $field_descr =~ s/(\s|\n)+$//msg;
1737 $desc .= "<entry role=\"struct_member_description\">$field_descr</entry>\n<entry role=\"struct_member_annotations\">$param_annotations</entry>\n";
1738 delete $field_descrs{$field_name};
1740 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
1741 "Field description for $symbol"."::"."$field_name is missing in source code comment block.");
1742 if ($missing_parameters ne "") {
1743 $missing_parameters .= ", ".$field_name;
1745 $missing_parameters = $field_name;
1747 $desc .= "<entry /><entry />\n";
1749 $desc .= "</row>\n";
1751 $desc .= "</tbody></tgroup></informaltable>\n</refsect3>\n";
1752 foreach my $field_name (keys %field_descrs) {
1753 # Documenting those standard fields is not required anymore, but
1754 # we don't want to warn if they are documented anyway.
1755 if ($field_name =~ /(g_iface|parent_instance|parent_class)/) {
1758 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
1759 "Field description for $symbol"."::"."$field_name is not used from source code comment block.");
1760 if ($unused_parameters ne "") {
1761 $unused_parameters .= ", ".$field_name;
1763 $unused_parameters = $field_name;
1767 # remember missing/unused parameters (needed in tmpl-free build)
1768 if (($missing_parameters ne "") and (! exists ($AllIncompleteSymbols{$symbol}))) {
1769 $AllIncompleteSymbols{$symbol}=$missing_parameters;
1771 if (($unused_parameters ne "") and (! exists ($AllUnusedSymbols{$symbol}))) {
1772 $AllUnusedSymbols{$symbol}=$unused_parameters;
1776 if (scalar(@fields) > 0) {
1777 if (! exists ($AllIncompleteSymbols{$symbol})) {
1778 $AllIncompleteSymbols{$symbol}="<items>";
1779 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
1780 "Field descriptions for struct $symbol are missing in source code comment block.");
1781 @TRACE@("Remaining structs fields: ".@fields.":".join(',',@fields)."\n");
1786 $desc .= OutputSymbolTraits ($symbol);
1787 $desc .= "</refsect2>\n";
1788 return ($synop, $desc);
1792 #############################################################################
1793 # Function : OutputUnion
1794 # Description : Returns the synopsis and detailed description of a union.
1795 # Arguments : $symbol - the union.
1796 # $declaration - the declaration of the union.
1797 #############################################################################
1800 my ($symbol, $declaration) = @_;
1803 if (&CheckIsObject ($symbol)) {
1804 @TRACE@("Found union gtype: $symbol\n");
1811 $id = &CreateValidSGMLID ($symbol . "_union");
1812 $condition = &MakeConditionDescription ($symbol . "_union");
1814 $id = &CreateValidSGMLID ($symbol);
1815 $condition = &MakeConditionDescription ($symbol);
1818 # Determine if it is a simple struct or it also has a typedef.
1819 my $has_typedef = 0;
1820 if ($StructHasTypedef{$symbol} || $declaration =~ m/^\s*typedef\s+/) {
1827 # For unions with typedefs we just output the union name.
1829 $desc = "<refsect2 id=\"$id\" role=\"union\"$condition>\n<title>$symbol</title>\n";
1831 $type_output = "union";
1832 $desc = "<refsect2 id=\"$id\" role=\"union\"$condition>\n<title>union $symbol</title>\n";
1834 my $synop = "<row><entry role=\"datatype_keyword\">${type_output}</entry><entry role=\"function_name\"><link linkend=\"$id\">$symbol</link></entry></row>\n";
1836 $desc .= MakeIndexterms($symbol, $id);
1838 $desc .= OutputSymbolExtraLinks($symbol);
1839 $desc .= &MakeDeprecationNote($symbol);
1841 if (defined ($SymbolDocs{$symbol})) {
1842 $desc .= &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
1845 # Create a table of fields and descriptions
1847 # FIXME: Inserting  's into the produced type declarations here would
1848 # improve the output in most situations ... except for function
1849 # members of structs!
1850 my @fields = ParseStructDeclaration($declaration, 0,
1853 "<structfield id=\"".&CreateValidSGMLID("$id.$_[0]")."\">$_[0]</structfield>";
1855 my $params = $SymbolParams{$symbol};
1857 # If no parameters are filled in, we don't generate the description
1858 # table, for backwards compatibility
1861 if (defined $params) {
1862 for (my $i = 1; $i <= $#$params; $i += $PARAM_FIELD_COUNT) {
1863 if ($params->[$i] =~ /\S/) {
1871 my %field_descrs = @$params;
1872 my $missing_parameters = "";
1873 my $unused_parameters = "";
1876 <refsect3 role="union_members">\n<title>Members</title>
1877 <informaltable role="union_members_table" pgwide="1" frame="none">
1879 <colspec colname="union_members_name" colwidth="300px"/>
1880 <colspec colname="union_members_description"/>
1881 <colspec colname="union_members_annotations" colwidth="200px"/>
1886 my $field_name = shift @fields;
1887 my $text = shift @fields;
1888 my $field_descr = $field_descrs{$field_name};
1889 my $param_annotations = "";
1891 $desc .= "<row><entry role=\"union_member_name\"><para>$text</para></entry>\n";
1892 if (defined $field_descr) {
1893 ($field_descr,$param_annotations) = &ExpandAnnotation($symbol, $field_descr);
1894 $field_descr = &ConvertMarkDown($symbol, $field_descr);
1897 $field_descr =~ s/^(\s|\n)+//msg;
1898 $field_descr =~ s/(\s|\n)+$//msg;
1899 $desc .= "<entry role=\"union_member_description\">$field_descr</entry>\n<entry role=\"union_member_annotations\">$param_annotations</entry>\n";
1900 delete $field_descrs{$field_name};
1902 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
1903 "Field description for $symbol"."::"."$field_name is missing in source code comment block.");
1904 if ($missing_parameters ne "") {
1905 $missing_parameters .= ", ".$field_name;
1907 $missing_parameters = $field_name;
1909 $desc .= "<entry /><entry />\n";
1911 $desc .= "</row>\n";
1913 $desc .= "</tbody></tgroup></informaltable>\n</refsect3>";
1914 foreach my $field_name (keys %field_descrs) {
1915 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
1916 "Field description for $symbol"."::"."$field_name is not used from source code comment block.");
1917 if ($unused_parameters ne "") {
1918 $unused_parameters .= ", ".$field_name;
1920 $unused_parameters = $field_name;
1924 # remember missing/unused parameters (needed in tmpl-free build)
1925 if (($missing_parameters ne "") and (! exists ($AllIncompleteSymbols{$symbol}))) {
1926 $AllIncompleteSymbols{$symbol}=$missing_parameters;
1928 if (($unused_parameters ne "") and (! exists ($AllUnusedSymbols{$symbol}))) {
1929 $AllUnusedSymbols{$symbol}=$unused_parameters;
1933 if (scalar(@fields) > 0) {
1934 if (! exists ($AllIncompleteSymbols{$symbol})) {
1935 $AllIncompleteSymbols{$symbol}="<items>";
1936 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
1937 "Field descriptions for union $symbol are missing in source code comment block.");
1938 @TRACE@("Remaining union fields: ".@fields.":".join(',',@fields)."\n");
1943 $desc .= OutputSymbolTraits ($symbol);
1944 $desc .= "</refsect2>\n";
1945 return ($synop, $desc);
1949 #############################################################################
1950 # Function : OutputEnum
1951 # Description : Returns the synopsis and detailed description of a enum.
1952 # Arguments : $symbol - the enum.
1953 # $declaration - the declaration of the enum.
1954 #############################################################################
1957 my ($symbol, $declaration) = @_;
1960 if (&CheckIsObject ($symbol)) {
1961 @TRACE@("Found enum gtype: $symbol\n");
1968 $id = &CreateValidSGMLID ($symbol . "_enum");
1969 $condition = &MakeConditionDescription ($symbol . "_enum");
1971 $id = &CreateValidSGMLID ($symbol);
1972 $condition = &MakeConditionDescription ($symbol);
1975 my $synop = "<row><entry role=\"datatype_keyword\">enum</entry><entry role=\"function_name\"><link linkend=\"$id\">$symbol</link></entry></row>\n";
1976 my $desc = "<refsect2 id=\"$id\" role=\"enum\"$condition>\n<title>enum $symbol</title>\n";
1978 $desc .= MakeIndexterms($symbol, $id);
1980 $desc .= OutputSymbolExtraLinks($symbol);
1981 $desc .= &MakeDeprecationNote($symbol);
1983 if (defined ($SymbolDocs{$symbol})) {
1984 $desc .= &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
1987 # Create a table of fields and descriptions
1989 my @fields = ParseEnumDeclaration($declaration);
1990 my $params = $SymbolParams{$symbol};
1992 # If nothing at all is documented log a single summary warning at the end.
1993 # Otherwise, warn about each undocumented item.
1996 if (defined $params) {
1997 for (my $i = 1; $i <= $#$params; $i += $PARAM_FIELD_COUNT) {
1998 if ($params->[$i] =~ /\S/) {
2005 my %field_descrs = (defined $params ? @$params : ());
2006 my $missing_parameters = "";
2007 my $unused_parameters = "";
2010 <refsect3 role="enum_members">\n<title>Members</title>
2011 <informaltable role="enum_members_table" pgwide="1" frame="none">
2013 <colspec colname="enum_members_name" colwidth="300px"/>
2014 <colspec colname="enum_members_description"/>
2015 <colspec colname="enum_members_annotations" colwidth="200px"/>
2019 for my $field_name (@fields) {
2020 my $field_descr = $field_descrs{$field_name};
2021 my $param_annotations = "";
2023 $id = &CreateValidSGMLID ($field_name);
2024 $condition = &MakeConditionDescription ($field_name);
2025 $desc .= "<row role=\"constant\"><entry role=\"enum_member_name\"><para id=\"$id\">$field_name</para></entry>\n";
2026 if (defined $field_descr) {
2027 ($field_descr,$param_annotations) = &ExpandAnnotation($symbol, $field_descr);
2028 $field_descr = &ConvertMarkDown($symbol, $field_descr);
2029 $desc .= "<entry role=\"enum_member_description\">$field_descr</entry>\n<entry role=\"enum_member_annotations\">$param_annotations</entry>\n";
2030 delete $field_descrs{$field_name};
2033 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
2034 "Value description for $symbol"."::"."$field_name is missing in source code comment block.");
2035 if ($missing_parameters ne "") {
2036 $missing_parameters .= ", ".$field_name;
2038 $missing_parameters = $field_name;
2041 $desc .= "<entry /><entry />\n";
2043 $desc .= "</row>\n";
2045 $desc .= "</tbody></tgroup></informaltable>\n</refsect3>";
2046 foreach my $field_name (keys %field_descrs) {
2047 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
2048 "Value description for $symbol"."::"."$field_name is not used from source code comment block.");
2049 if ($unused_parameters ne "") {
2050 $unused_parameters .= ", ".$field_name;
2052 $unused_parameters = $field_name;
2056 # remember missing/unused parameters (needed in tmpl-free build)
2057 if (($missing_parameters ne "") and (! exists ($AllIncompleteSymbols{$symbol}))) {
2058 $AllIncompleteSymbols{$symbol}=$missing_parameters;
2060 if (($unused_parameters ne "") and (! exists ($AllUnusedSymbols{$symbol}))) {
2061 $AllUnusedSymbols{$symbol}=$unused_parameters;
2065 if (scalar(@fields) > 0) {
2066 if (! exists ($AllIncompleteSymbols{$symbol})) {
2067 $AllIncompleteSymbols{$symbol}="<items>";
2068 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
2069 "Value descriptions for $symbol are missing in source code comment block.");
2074 $desc .= OutputSymbolTraits ($symbol);
2075 $desc .= "</refsect2>\n";
2076 return ($synop, $desc);
2080 #############################################################################
2081 # Function : OutputVariable
2082 # Description : Returns the synopsis and detailed description of a variable.
2083 # Arguments : $symbol - the extern'ed variable.
2084 # $declaration - the declaration of the variable.
2085 #############################################################################
2087 sub OutputVariable {
2088 my ($symbol, $declaration) = @_;
2089 my $id = &CreateValidSGMLID ($symbol);
2090 my $condition = &MakeConditionDescription ($symbol);
2092 @TRACE@("ouputing variable: '$symbol' '$declaration'");
2095 if ($declaration =~ m/^\s*extern\s+((const\s+|signed\s+|unsigned\s+|long\s+|short\s+)*\w+)(\s+\*+|\*+|\s)(\s*)(const\s+)*([A-Za-z]\w*)\s*;/) {
2096 my $mod1 = defined ($1) ? $1 : "";
2097 my $ptr = defined ($3) ? $3 : "";
2098 my $space = defined ($4) ? $4 : "";
2099 my $mod2 = defined ($5) ? $5 : "";
2100 $type_output = "extern $mod1$ptr$space$mod2";
2101 } elsif ($declaration =~ m/^\s*((const\s+|signed\s+|unsigned\s+|long\s+|short\s+)*\w+)(\s+\*+|\*+|\s)(\s*)(const\s+)*([A-Za-z]\w*)\s*=/) {
2102 my $mod1 = defined ($1) ? $1 : "";
2103 my $ptr = defined ($3) ? $3 : "";
2104 my $space = defined ($4) ? $4 : "";
2105 my $mod2 = defined ($5) ? $5 : "";
2106 $type_output = "$mod1$ptr$space$mod2";
2108 $type_output = "extern";
2110 my $synop = "<row><entry role=\"variable_type\">${type_output}</entry><entry role=\"function_name\"><link linkend=\"$id\">$symbol</link></entry></row>\n";
2112 my $desc = "<refsect2 id=\"$id\" role=\"variable\"$condition>\n<title>$symbol</title>\n";
2114 $desc .= MakeIndexterms($symbol, $id);
2116 $desc .= OutputSymbolExtraLinks($symbol);
2118 my $decl_out = &CreateValidSGML ($declaration);
2119 $desc .= "<programlisting language=\"C\">$decl_out</programlisting>\n";
2121 $desc .= &MakeDeprecationNote($symbol);
2123 if (defined ($SymbolDocs{$symbol})) {
2124 $desc .= &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
2126 if (defined ($SymbolAnnotations{$symbol})) {
2127 my $param_desc = $SymbolAnnotations{$symbol};
2128 my $param_annotations = "";
2129 ($param_desc,$param_annotations) = &ExpandAnnotation($symbol, $param_desc);
2130 if ($param_annotations ne "") {
2131 $desc .= "\n<para>$param_annotations</para>";
2135 $desc .= OutputSymbolTraits ($symbol);
2136 $desc .= "</refsect2>\n";
2137 return ($synop, $desc);
2141 #############################################################################
2142 # Function : OutputFunction
2143 # Description : Returns the synopsis and detailed description of a function.
2144 # Arguments : $symbol - the function.
2145 # $declaration - the declaration of the function.
2146 #############################################################################
2148 sub OutputFunction {
2149 my ($symbol, $declaration, $symbol_type) = @_;
2150 my $id = &CreateValidSGMLID ($symbol);
2151 my $condition = &MakeConditionDescription ($symbol);
2153 # Take out the return type $1 $2 $3
2154 $declaration =~ s/<RETURNS>\s*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|enum\s+)*)(\w+)(\s*\**\s*(?:const|G_CONST_RETURN)?\s*\**\s*(?:restrict)?\s*)<\/RETURNS>\n//;
2155 my $type_modifier = defined($1) ? $1 : "";
2158 # Trim trailing spaces as we are going to pad to $RETURN_TYPE_FIELD_WIDTH below anyway
2159 $pointer =~ s/\s+$//;
2160 my $xref = &MakeXRef ($type, &tagify($type, "returnvalue"));
2162 #if ($symbol_type eq 'USER_FUNCTION') {
2163 # $start = "typedef ";
2166 # We output const rather than G_CONST_RETURN.
2167 $type_modifier =~ s/G_CONST_RETURN/const/g;
2168 $pointer =~ s/G_CONST_RETURN/const/g;
2169 $pointer =~ s/^\s+/ /g;
2171 my $ret_type_output;
2172 $ret_type_output = "$start$type_modifier$xref$pointer\n";
2175 $indent_len = length ($symbol) + 2;
2176 my $char1 = my $char2 = my $char3 = "";
2177 if ($symbol_type eq 'USER_FUNCTION') {
2179 $char1 = "<phrase role=\"c_punctuation\">(</phrase>";
2181 $char3 = "<phrase role=\"c_punctuation\">)</phrase>";
2184 my ($symbol_output, $symbol_desc_output);
2185 $symbol_output = "$char1<link linkend=\"$id\">$char2$symbol</link>$char3";
2186 if ($indent_len < $MAX_SYMBOL_FIELD_WIDTH) {
2187 $symbol_desc_output = "$char1$char2$symbol$char3 ";
2189 $indent_len = $MAX_SYMBOL_FIELD_WIDTH - 8;
2190 $symbol_desc_output = "$char1$char2$symbol$char3\n"
2191 . (' ' x ($indent_len - 1));
2194 my $synop = "<row><entry role=\"function_type\">${ret_type_output}</entry><entry role=\"function_name\">${symbol_output} <phrase role=\"c_punctuation\">()</phrase></entry></row>\n";
2196 my $desc = "<refsect2 id=\"$id\" role=\"function\"$condition>\n<title>${symbol} ()</title>\n";
2198 $desc .= MakeIndexterms($symbol, $id);
2200 $desc .= OutputSymbolExtraLinks($symbol);
2202 $desc .= "<programlisting language=\"C\">${ret_type_output}$symbol_desc_output(";
2204 my @fields = ParseFunctionDeclaration($declaration, \&MakeXRef,
2206 &tagify($_[0],"parameter");
2209 for (my $i = 1; $i <= $#fields; $i += 2) {
2210 my $field_name = $fields[$i];
2213 $desc .= "$field_name";
2216 . (' ' x $indent_len)
2222 $desc .= ");</programlisting>\n";
2224 $desc .= &MakeDeprecationNote($symbol);
2226 if (defined ($SymbolDocs{$symbol})) {
2227 $desc .= &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
2229 if (defined ($SymbolAnnotations{$symbol})) {
2230 my $param_desc = $SymbolAnnotations{$symbol};
2231 my $param_annotations = "";
2232 ($param_desc,$param_annotations) = &ExpandAnnotation($symbol, $param_desc);
2233 if ($param_annotations ne "") {
2234 $desc .= "\n<para>$param_annotations</para>";
2238 $desc .= &OutputParamDescriptions ("FUNCTION", $symbol, @fields);
2239 $desc .= OutputSymbolTraits ($symbol);
2240 $desc .= "</refsect2>\n";
2241 return ($synop, $desc);
2245 #############################################################################
2246 # Function : OutputParamDescriptions
2247 # Description : Returns the DocBook output describing the parameters of a
2248 # function, macro or signal handler.
2249 # Arguments : $symbol_type - 'FUNCTION', 'MACRO' or 'SIGNAL'. Signal
2250 # handlers have an implicit user_data parameter last.
2251 # $symbol - the name of the function/macro being described.
2252 # @fields - parsed fields from the declaration, used to determine
2253 # undocumented/unused entries
2254 #############################################################################
2256 sub OutputParamDescriptions {
2257 my ($symbol_type, $symbol, @fields) = @_;
2259 my $params = $SymbolParams{$symbol};
2261 my %field_descrs = ();
2264 %field_descrs = @fields;
2265 delete $field_descrs{"void"};
2266 delete $field_descrs{"Returns"};
2269 if (defined $params) {
2271 my $params_desc = "";
2272 my $missing_parameters = "";
2273 my $unused_parameters = "";
2276 for ($j = 0; $j <= $#$params; $j += $PARAM_FIELD_COUNT) {
2277 my $param_name = $$params[$j];
2278 my $param_desc = $$params[$j + 1];
2279 my $param_annotations = "";
2281 ($param_desc,$param_annotations) = &ExpandAnnotation($symbol, $param_desc);
2282 $param_desc = &ConvertMarkDown($symbol, $param_desc);
2284 $param_desc =~ s/^(\s|\n)+//msg;
2285 $param_desc =~ s/(\s|\n)+$//msg;
2286 if ($param_name eq "Returns") {
2287 $returns = $param_desc;
2288 if ($param_annotations ne "") {
2289 $returns .= "\n<para>$param_annotations</para>";
2291 } elsif ($param_name eq "void") {
2292 # FIXME: &LogWarning()?
2293 @TRACE@("!!!! void in params for $symbol?\n");
2296 if (!defined $field_descrs{$param_name}) {
2297 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
2298 "Parameter description for $symbol"."::"."$param_name is not used from source code comment block.");
2299 if ($unused_parameters ne "") {
2300 $unused_parameters .= ", ".$param_name;
2302 $unused_parameters = $param_name;
2305 delete $field_descrs{$param_name};
2308 if($param_desc ne "") {
2309 $params_desc .= "<row><entry role=\"parameter_name\"><para>$param_name</para></entry>\n<entry role=\"parameter_description\">$param_desc</entry>\n<entry role=\"parameter_annotations\">$param_annotations</entry></row>\n";
2314 foreach my $param_name (keys %field_descrs) {
2315 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
2316 "Parameter description for $symbol"."::"."$param_name is missing in source code comment block.");
2317 if ($missing_parameters ne "") {
2318 $missing_parameters .= ", ".$param_name;
2320 $missing_parameters = $param_name;
2324 # Signals have an implicit user_data parameter which we describe.
2325 if ($symbol_type eq "SIGNAL") {
2326 $params_desc .= "<row><entry role=\"parameter_name\"><simpara>user_data</simpara></entry>\n<entry role=\"parameter_description\"><simpara>user data set when the signal handler was connected.</simpara></entry>\n<entry role=\"parameter_annotations\"></entry></row>\n";
2329 # Start a table if we need one.
2330 if ($params_desc ne "") {
2332 <refsect3 role="parameters">\n<title>Parameters</title>
2333 <informaltable role="parameters_table" pgwide="1" frame="none">
2335 <colspec colname="parameters_name" colwidth="150px"/>
2336 <colspec colname="parameters_description"/>
2337 <colspec colname="parameters_annotations" colwidth="200px"/>
2340 $output .= $params_desc;
2341 $output .= "</tbody></tgroup></informaltable>\n</refsect3>";
2344 # Output the returns info last
2345 if ($returns ne "") {
2347 <refsect3 role=\"returns\">\n<title>Returns</title>
2349 $output .= $returns;
2350 $output .= "\n</refsect3>";
2353 # remember missing/unused parameters (needed in tmpl-free build)
2354 if (($missing_parameters ne "") and (! exists ($AllIncompleteSymbols{$symbol}))) {
2355 $AllIncompleteSymbols{$symbol}=$missing_parameters;
2357 if (($unused_parameters ne "") and (! exists ($AllUnusedSymbols{$symbol}))) {
2358 $AllUnusedSymbols{$symbol}=$unused_parameters;
2361 if (($num_params == 0) && @fields && (scalar(keys(%field_descrs)) > 0)) {
2362 if (! exists ($AllIncompleteSymbols{$symbol})) {
2363 $AllIncompleteSymbols{$symbol}="<parameters>";
2371 #############################################################################
2372 # Function : ParseStabilityLevel
2373 # Description : Parses a stability level and outputs a warning if it isn't
2375 # Arguments : $stability - the stability text.
2376 # $file, $line - context for error message
2377 # $message - description of where the level is from, to use in
2378 # any error message.
2379 # Returns : The parsed stability level string.
2380 #############################################################################
2382 sub ParseStabilityLevel {
2383 my ($stability, $file, $line, $message) = @_;
2385 $stability =~ s/^\s*//;
2386 $stability =~ s/\s*$//;
2387 if ($stability =~ m/^stable$/i) {
2388 $stability = "Stable";
2389 } elsif ($stability =~ m/^unstable$/i) {
2390 $stability = "Unstable";
2391 } elsif ($stability =~ m/^private$/i) {
2392 $stability = "Private";
2394 &LogWarning ($file, $line, "$message is $stability.".
2395 "It should be one of these: Stable, Unstable, or Private.");
2401 #############################################################################
2402 # Function : OutputDBFile
2403 # Description : Outputs the final DocBook file for one section.
2404 # Arguments : $file - the name of the file.
2405 # $title - the title from the $MODULE-sections.txt file, which
2406 # will be overridden by the title in the template file.
2407 # $section_id - the id to use for the toplevel tag.
2408 # $includes - comma-separates list of include files added at top of
2409 # synopsis, with '<' '>' around them (if not already enclosed in "").
2410 # $functions_synop - reference to the DocBook for the Functions Synopsis part.
2411 # $other_synop - reference to the DocBook for the Types and Values Synopsis part.
2412 # $functions_details - reference to the DocBook for the Functions Details part.
2413 # $other_details - reference to the DocBook for the Types and Values Details part.
2414 # $signal_synop - reference to the DocBook for the Signal Synopsis part
2415 # $signal_desc - reference to the DocBook for the Signal Description part
2416 # $args_synop - reference to the DocBook for the Arg Synopsis part
2417 # $args_desc - reference to the DocBook for the Arg Description part
2418 # $hierarchy - reference to the DocBook for the Object Hierarchy part
2419 # $interfaces - reference to the DocBook for the Interfaces part
2420 # $implementations - reference to the DocBook for the Known Implementations part
2421 # $prerequisites - reference to the DocBook for the Prerequisites part
2422 # $derived - reference to the DocBook for the Derived Interfaces part
2423 # $file_objects - reference to an array of objects in this file
2424 #############################################################################
2427 my ($file, $title, $section_id, $includes, $functions_synop, $other_synop, $functions_details, $other_details, $signals_synop, $signals_desc, $args_synop, $args_desc, $hierarchy, $interfaces, $implementations, $prerequisites, $derived, $file_objects) = @_;
2429 @TRACE@("Output docbook for file $file with title '$title'\n");
2431 # The edited title overrides the one from the sections file.
2432 my $new_title = $SymbolDocs{"$TMPL_DIR/$file:Title"};
2433 if (defined ($new_title) && $new_title !~ m/^\s*$/) {
2434 $title = $new_title;
2435 @TRACE@("Found title: $title\n");
2437 my $short_desc = $SymbolDocs{"$TMPL_DIR/$file:Short_Description"};
2438 if (!defined ($short_desc) || $short_desc =~ m/^\s*$/) {
2441 # Don't use ConvertMarkDown here for now since we don't want blocks
2442 $short_desc = &ExpandAbbreviations("$title:Short_description",
2444 @TRACE@("Found short_desc: $short_desc");
2446 my $long_desc = $SymbolDocs{"$TMPL_DIR/$file:Long_Description"};
2447 if (!defined ($long_desc) || $long_desc =~ m/^\s*$/) {
2450 $long_desc = &ConvertMarkDown("$title:Long_description",
2452 @TRACE@("Found long_desc: $long_desc");
2454 my $see_also = $SymbolDocs{"$TMPL_DIR/$file:See_Also"};
2455 if (!defined ($see_also) || $see_also =~ m%^\s*(<para>)?\s*(</para>)?\s*$%) {
2458 $see_also = &ConvertMarkDown("$title:See_Also", $see_also);
2459 @TRACE@("Found see_also: $see_also");
2462 $see_also = "<refsect1 id=\"$section_id.see-also\">\n<title>See Also</title>\n$see_also\n</refsect1>\n";
2464 my $stability = $SymbolDocs{"$TMPL_DIR/$file:Stability_Level"};
2465 if (!defined ($stability) || $stability =~ m/^\s*$/) {
2468 $stability = &ParseStabilityLevel($stability, $file, $., "Section stability level");
2469 @TRACE@("Found stability: $stability");
2472 $AnnotationsUsed{$stability} = 1;
2473 $stability = "<refsect1 id=\"$section_id.stability-level\">\n<title>Stability Level</title>\n<acronym>$stability</acronym>, unless otherwise indicated\n</refsect1>\n";
2474 } elsif ($DEFAULT_STABILITY) {
2475 $AnnotationsUsed{$DEFAULT_STABILITY} = 1;
2476 $stability = "<refsect1 id=\"$section_id.stability-level\">\n<title>Stability Level</title>\n<acronym>$DEFAULT_STABILITY</acronym>, unless otherwise indicated\n</refsect1>\n";
2479 my $image = $SymbolDocs{"$TMPL_DIR/$file:Image"};
2480 if (!defined ($image) || $image =~ m/^\s*$/) {
2488 if ($image =~ /jpe?g$/i) {
2489 $format = "format='JPEG'";
2490 } elsif ($image =~ /png$/i) {
2491 $format = "format='PNG'";
2492 } elsif ($image =~ /svg$/i) {
2493 $format = "format='SVG'";
2498 $image = " <inlinegraphic fileref='$image' $format/>\n"
2501 my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
2503 my $month = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$mon];
2506 my $include_output = "";
2508 $include_output .= "<refsect1 id=\"$section_id.includes\"><title>Includes</title><synopsis>";
2510 foreach $include (split (/,/, $includes)) {
2511 if ($include =~ m/^\".+\"$/) {
2512 $include_output .= "#include ${include}\n";
2515 $include =~ s/^\s+|\s+$//gs;
2516 $include_output .= "#include <${include}>\n";
2519 $include_output .= "</synopsis></refsect1>\n";
2522 my $extralinks = OutputSectionExtraLinks($title,"Section:$file");
2524 my $old_db_file = "$DB_OUTPUT_DIR/$file.xml";
2525 my $new_db_file = "$DB_OUTPUT_DIR/$file.xml.new";
2527 open (OUTPUT, ">$new_db_file")
2528 || die "Can't create $new_db_file: $!";
2530 my $object_anchors = "";
2531 foreach my $object (@$file_objects) {
2532 next if ($object eq $section_id);
2533 my $id = CreateValidSGMLID($object);
2534 @TRACE@("Adding anchor for $object\n");
2535 $object_anchors .= "<anchor id=\"$id\"/>";
2538 # Make sure we produce valid docbook
2539 $$functions_details ||= "<para />";
2541 # We used to output this, but is messes up our UpdateFileIfChanged code
2542 # since it changes every day (and it is only used in the man pages):
2543 # "<refentry id="$section_id" revision="$mday $month $year">"
2546 ${\( MakeDocHeader ("refentry") )}
2547 <refentry id="$section_id">
2549 <refentrytitle role="top_of_page" id="$section_id.top_of_page">$title</refentrytitle>
2550 <manvolnum>3</manvolnum>
2551 <refmiscinfo>\U$MODULE\E Library$image</refmiscinfo>
2554 <refname>$title</refname>
2555 <refpurpose>$short_desc</refpurpose>
2558 $$functions_synop$$args_synop$$signals_synop$object_anchors$$other_synop$$hierarchy$$prerequisites$$derived$$interfaces$$implementations
2560 <refsect1 id="$section_id.description" role="desc">
2561 <title role="desc.title">Description</title>
2562 $extralinks$long_desc
2564 <refsect1 id="$section_id.functions_details" role="details">
2565 <title role="details.title">Functions</title>
2568 <refsect1 id="$section_id.other_details" role="details">
2569 <title role="details.title">Types and Values</title>
2572 $$args_desc$$signals_desc$see_also
2577 return &UpdateFileIfChanged ($old_db_file, $new_db_file, 0);
2581 #############################################################################
2582 # Function : OutputExtraFile
2583 # Description : Copies an "extra" DocBook file into the output directory,
2584 # expanding abbreviations
2585 # Arguments : $file - the source file.
2586 #############################################################################
2587 sub OutputExtraFile {
2592 ($basename = $file) =~ s!^.*/!!;
2594 my $old_db_file = "$DB_OUTPUT_DIR/$basename";
2595 my $new_db_file = "$DB_OUTPUT_DIR/$basename.new";
2599 open(EXTRA_FILE, "<$file") || die "Can't open $file";
2603 $contents = <EXTRA_FILE>;
2606 open (OUTPUT, ">$new_db_file")
2607 || die "Can't create $new_db_file: $!";
2609 print OUTPUT &ExpandAbbreviations ("$basename file", $contents);
2612 return &UpdateFileIfChanged ($old_db_file, $new_db_file, 0);
2614 #############################################################################
2615 # Function : OutputBook
2616 # Description : Outputs the entities that need to be included into the
2617 # main docbook file for the module.
2618 # Arguments : $book_top - the declarations of the entities, which are added
2619 # at the top of the main docbook file.
2620 # $book_bottom - the references to the entities, which are
2621 # added in the main docbook file at the desired position.
2622 #############################################################################
2625 my ($book_top, $book_bottom) = @_;
2627 my $old_file = "$DB_OUTPUT_DIR/$MODULE-doc.top";
2628 my $new_file = "$DB_OUTPUT_DIR/$MODULE-doc.top.new";
2630 open (OUTPUT, ">$new_file")
2631 || die "Can't create $new_file: $!";
2632 print OUTPUT $book_top;
2635 &UpdateFileIfChanged ($old_file, $new_file, 0);
2638 $old_file = "$DB_OUTPUT_DIR/$MODULE-doc.bottom";
2639 $new_file = "$DB_OUTPUT_DIR/$MODULE-doc.bottom.new";
2641 open (OUTPUT, ">$new_file")
2642 || die "Can't create $new_file: $!";
2643 print OUTPUT $book_bottom;
2646 &UpdateFileIfChanged ($old_file, $new_file, 0);
2649 # If the main docbook file hasn't been created yet, we create it here.
2650 # The user can tweak it later.
2651 if ($MAIN_SGML_FILE && ! -e $MAIN_SGML_FILE) {
2652 open (OUTPUT, ">$MAIN_SGML_FILE")
2653 || die "Can't create $MAIN_SGML_FILE: $!";
2656 ${\( MakeDocHeader ("book") )}
2659 <title>&package_name; Reference Manual</title>
2661 for &package_string;.
2662 The latest version of this documentation can be found on-line at
2663 <ulink role="online-location" url="http://[SERVER]/&package_name;/index.html">http://[SERVER]/&package_name;/</ulink>.
2668 <title>[Insert title here]</title>
2672 if (-e $OBJECT_TREE_FILE) {
2674 <chapter id="object-tree">
2675 <title>Object Hierarchy</title>
2676 <xi:include href="xml/tree_index.sgml"/>
2681 <!-- enable this when you use gobject types
2682 <chapter id="object-tree">
2683 <title>Object Hierarchy</title>
2684 <xi:include href="xml/tree_index.sgml"/>
2690 <index id="api-index-full">
2691 <title>API Index</title>
2692 <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
2694 <index id="deprecated-api-index" role="deprecated">
2695 <title>Index of deprecated API</title>
2696 <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
2699 if (keys(%AnnotationsUsed)) {
2701 <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
2705 <!-- enable this when you use gobject introspection annotations
2706 <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
2719 #############################################################################
2720 # Function : CreateValidSGML
2721 # Description : This turns any chars which are used in SGML into entities,
2722 # e.g. '<' into '<'
2723 # Arguments : $text - the text to turn into proper SGML.
2724 #############################################################################
2726 sub CreateValidSGML {
2728 $text =~ s/&/&/g; # Do this first, or the others get messed up.
2729 $text =~ s/</</g;
2730 $text =~ s/>/>/g;
2731 # browers render single tabs inconsistently
2732 $text =~ s/([^\s])\t([^\s])/$1 $2/g;
2736 #############################################################################
2737 # Function : ConvertSGMLChars
2738 # Description : This is used for text in source code comment blocks, to turn
2739 # chars which are used in SGML into entities, e.g. '<' into
2740 # '<'. Depending on $INLINE_MARKUP_MODE, this is done
2741 # unconditionally or only if the character doesn't seem to be
2742 # part of an SGML construct (tag or entity reference).
2743 # Arguments : $text - the text to turn into proper SGML.
2744 #############################################################################
2746 sub ConvertSGMLChars {
2747 my ($symbol, $text) = @_;
2749 if ($INLINE_MARKUP_MODE) {
2750 # For the XML/SGML mode only convert to entities outside CDATA sections.
2751 return &ModifyXMLElements ($text, $symbol,
2752 "<!\\[CDATA\\[|<programlisting[^>]*>",
2753 \&ConvertSGMLCharsEndTag,
2754 \&ConvertSGMLCharsCallback);
2756 # For the simple non-sgml mode, convert to entities everywhere.
2758 # First, convert freestanding & to &
2759 $text =~ s/&(?![a-zA-Z#]+;)/&/g;
2760 $text =~ s/</</g;
2761 # Allow ">" at beginning of string for blockquote markdown
2762 $text =~ s/(?<=[^\w\n"'\/-])>/>/g;
2769 sub ConvertSGMLCharsEndTag {
2770 if ($_[0] eq "<!\[CDATA\[") {
2773 return "</programlisting>";
2777 sub ConvertSGMLCharsCallback {
2778 my ($text, $symbol, $tag) = @_;
2780 if ($tag =~ m/^<programlisting/) {
2781 # We can handle <programlisting> specially here.
2782 return &ModifyXMLElements ($text, $symbol,
2784 \&ConvertSGMLCharsEndTag,
2785 \&ConvertSGMLCharsCallback2);
2786 } elsif ($tag eq "") {
2787 # If we're not in CDATA convert to entities.
2788 $text =~ s/&(?![a-zA-Z#]+;)/&/g; # Do this first, or the others get messed up.
2789 $text =~ s/<(?![a-zA-Z\/!])/</g;
2790 # Allow ">" at beginning of string for blockquote markdown
2791 $text =~ s/(?<=[^\w\n"'\/-])>/>/g;
2793 # Handle "#include <xxxxx>"
2794 $text =~ s/#include(\s+)<([^>]+)>/#include$1<$2>/g;
2800 sub ConvertSGMLCharsCallback2 {
2801 my ($text, $symbol, $tag) = @_;
2803 # If we're not in CDATA convert to entities.
2804 # We could handle <programlisting> differently, though I'm not sure it helps.
2806 # replace only if its not a tag
2807 $text =~ s/&(?![a-zA-Z#]+;)/&/g; # Do this first, or the others get messed up.
2808 $text =~ s/<(?![a-zA-Z\/!])/</g;
2809 $text =~ s/(?<![a-zA-Z0-9"'\/-])>/>/g;
2811 # Handle "#include <xxxxx>"
2812 $text =~ s/#include(\s+)<([^>]+)>/#include$1<$2>/g;
2818 #############################################################################
2819 # Function : ExpandAnnotation
2820 # Description : This turns annotations into acronym tags.
2821 # Arguments : $symbol - the symbol being documented, for error messages.
2822 # $text - the text to expand.
2823 #############################################################################
2824 sub ExpandAnnotation {
2825 my ($symbol, $param_desc) = @_;
2826 my $param_annotations = "";
2828 # look for annotations at the start of the comment part
2829 # function level annotations don't end with a colon ':'
2830 if ($param_desc =~ m%^\s*\((.*?)\)(:|$)%) {
2835 @annotations = split(/\)\s*\(/,$1);
2836 @TRACE@("annotations for $symbol: '$1'\n");
2837 foreach $annotation (@annotations) {
2838 # need to search for the longest key-match in %AnnotationDefinition
2840 my $match_annotation="";
2842 foreach $annotationdef (keys %AnnotationDefinition) {
2843 if ($annotation =~ m/^$annotationdef/) {
2844 if (length($annotationdef)>$match_length) {
2845 $match_length=length($annotationdef);
2846 $match_annotation=$annotationdef;
2850 my $annotation_extra = "";
2851 if ($match_annotation ne "") {
2852 if ($annotation =~ m%$match_annotation\s+(.*)%) {
2853 $annotation_extra = " $1";
2855 $AnnotationsUsed{$match_annotation} = 1;
2856 $param_annotations .= "[<acronym>$match_annotation</acronym>$annotation_extra]";
2859 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
2860 "unknown annotation \"$annotation\" in documentation for $symbol.");
2861 $param_annotations .= "[$annotation]";
2865 $param_desc =~ m/^(.*?)\.*\s*$/s;
2866 $param_desc = "$1. ";
2868 if ($param_annotations ne "") {
2869 $param_annotations = "<emphasis role=\"annotation\">$param_annotations</emphasis>";
2871 return ($param_desc, $param_annotations);
2874 #############################################################################
2875 # Function : ExpandAbbreviations
2876 # Description : This turns the abbreviations function(), macro(), @param,
2877 # %constant, and #symbol into appropriate DocBook markup.
2878 # CDATA sections and <programlisting> parts are skipped.
2879 # Arguments : $symbol - the symbol being documented, for error messages.
2880 # $text - the text to expand.
2881 #############################################################################
2883 sub ExpandAbbreviations {
2884 my ($symbol, $text) = @_;
2886 # Note: This is a fallback and normally done in the markdown parser
2888 # Convert "|[" and "]|" into the start and end of program listing examples.
2889 # Support \[<!-- language="C" --> modifiers
2890 $text =~ s%\|\[<!-- language="([^"]+)" -->%<informalexample><programlisting language="$1"><![CDATA[%g;
2891 $text =~ s%\|\[%<informalexample><programlisting><![CDATA[%g;
2892 $text =~ s%\]\|%]]></programlisting></informalexample>%g;
2894 # keep CDATA unmodified, preserve ulink tags (ideally we preseve all tags
2896 return &ModifyXMLElements ($text, $symbol,
2897 "<!\\[CDATA\\[|<ulink[^>]*>|<programlisting[^>]*>|<!DOCTYPE",
2898 \&ExpandAbbreviationsEndTag,
2899 \&ExpandAbbreviationsCallback);
2903 # Returns the end tag (as a regexp) corresponding to the given start tag.
2904 sub ExpandAbbreviationsEndTag {
2905 my ($start_tag) = @_;
2907 if ($start_tag eq "<!\[CDATA\[") {
2909 } elsif ($start_tag eq "<!DOCTYPE") {
2911 } elsif ($start_tag =~ m/<(\w+)/) {
2916 # Called inside or outside each CDATA or <programlisting> section.
2917 sub ExpandAbbreviationsCallback {
2918 my ($text, $symbol, $tag) = @_;
2920 if ($tag =~ m/^<programlisting/) {
2921 # Handle any embedded CDATA sections.
2922 return &ModifyXMLElements ($text, $symbol,
2924 \&ExpandAbbreviationsEndTag,
2925 \&ExpandAbbreviationsCallback2);
2926 } elsif ($tag eq "") {
2927 # NOTE: this is a fallback. It is normally done by the Markdown parser.
2929 # We are outside any CDATA or <programlisting> sections, so we expand
2930 # any gtk-doc abbreviations.
2932 # Convert '@param()'
2933 # FIXME: we could make those also links ($symbol.$2), but that would be less
2934 # useful as the link target is a few lines up or down
2935 $text =~ s/(\A|[^\\])\@(\w+((\.|->)\w+)*)\s*\(\)/$1<parameter>$2()<\/parameter>/g;
2937 # Convert 'function()' or 'macro()'.
2938 # if there is abc_*_def() we don't want to make a link to _def()
2939 # FIXME: also handle abc(def(....)) : but that would need to be done recursively :/
2940 $text =~ s/([^\*.\w])(\w+)\s*\(\)/$1.&MakeXRef($2, &tagify($2 . "()", "function"));/eg;
2941 # handle #Object.func()
2942 $text =~ s/(\A|[^\\])#([\w\-:\.]+[\w]+)\s*\(\)/$1.&MakeXRef($2, &tagify($2 . "()", "function"));/eg;
2944 # Convert '@param', but not '\@param'.
2945 $text =~ s/(\A|[^\\])\@(\w+((\.|->)\w+)*)/$1<parameter>$2<\/parameter>/g;
2946 $text =~ s/\\\@/\@/g;
2948 # Convert '%constant', but not '\%constant'.
2949 # Also allow negative numbers, e.g. %-1.
2950 $text =~ s/(\A|[^\\])\%(-?\w+)/$1.&MakeXRef($2, &tagify($2, "literal"));/eg;
2951 $text =~ s/\\\%/\%/g;
2953 # Convert '#symbol', but not '\#symbol'.
2954 $text =~ s/(\A|[^\\])#([\w\-:\.]+[\w]+)/$1.&MakeHashXRef($2, "type");/eg;
2961 # This is called inside a <programlisting>
2962 sub ExpandAbbreviationsCallback2 {
2963 my ($text, $symbol, $tag) = @_;
2966 # We are inside a <programlisting> but outside any CDATA sections,
2967 # so we expand any gtk-doc abbreviations.
2968 # FIXME: why is this different from &ExpandAbbreviationsCallback(),
2969 # why not just call it
2970 $text =~ s/#(\w+)/&MakeHashXRef($1, "");/eg;
2971 } elsif ($tag eq "<![CDATA[") {
2972 # NOTE: this is a fallback. It is normally done by the Markdown parser.
2973 $text = &ReplaceEntities ($text, $symbol);
2980 my ($symbol, $tag) = @_;;
2983 # Check for things like '#include', '#define', and skip them.
2984 if ($PreProcessorDirectives{$symbol}) {
2988 # Get rid of special suffixes ('-struct','-enum').
2989 $text =~ s/-struct$//;
2990 $text =~ s/-enum$//;
2992 # If the symbol is in the form "Object::signal", then change the symbol to
2993 # "Object-signal" and use "signal" as the text.
2994 if ($symbol =~ s/::/-/) {
2998 # If the symbol is in the form "Object:property", then change the symbol to
2999 # "Object--property" and use "property" as the text.
3000 if ($symbol =~ s/:/--/) {
3005 $text = tagify ($text, $tag);
3008 return &MakeXRef($symbol, $text);
3012 #############################################################################
3013 # Function : ModifyXMLElements
3014 # Description : Looks for given XML element tags within the text, and calls
3015 # the callback on pieces of text inside & outside those elements.
3016 # Used for special handling of text inside things like CDATA
3017 # and <programlisting>.
3018 # Arguments : $text - the text.
3019 # $symbol - the symbol currently being documented (only used for
3021 # $start_tag_regexp - the regular expression to match start tags.
3022 # e.g. "<!\\[CDATA\\[|<programlisting[^>]*>" to match
3023 # CDATA sections or programlisting elements.
3024 # $end_tag_func - function which is passed the matched start tag
3025 # and should return the appropriate end tag string regexp.
3026 # $callback - callback called with each part of the text. It is
3027 # called with a piece of text, the symbol being
3028 # documented, and the matched start tag or "" if the text
3029 # is outside the XML elements being matched.
3030 #############################################################################
3031 sub ModifyXMLElements {
3032 my ($text, $symbol, $start_tag_regexp, $end_tag_func, $callback) = @_;
3033 my ($before_tag, $start_tag, $end_tag_regexp, $end_tag);
3036 while ($text =~ m/$start_tag_regexp/s) {
3037 $before_tag = $`; # Prematch for last successful match string
3038 $start_tag = $&; # Last successful match
3039 $text = $'; # Postmatch for last successful match string
3041 $result .= &$callback ($before_tag, $symbol, "");
3042 $result .= $start_tag;
3044 # get the matching end-tag for current tag
3045 $end_tag_regexp = &$end_tag_func ($start_tag);
3047 if ($text =~ m/$end_tag_regexp/s) {
3052 $result .= &$callback ($before_tag, $symbol, $start_tag);
3053 $result .= $end_tag;
3055 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
3056 "Can't find tag end: $end_tag_regexp in docs for: $symbol.");
3057 # Just assume it is all inside the tag.
3058 $result .= &$callback ($text, $symbol, $start_tag);
3063 # Handle any remaining text outside the tags.
3064 $result .= &$callback ($text, $symbol, "");
3073 # Adds a tag around some text.
3074 # e.g tagify("Text", "literal") => "<literal>Text</literal>".
3076 my ($text, $elem) = @_;
3077 return "<" . $elem . ">" . $text . "</" . $elem . ">";
3080 #############################################################################
3081 # Function : MakeDocHeader
3082 # Description : Builds a docbook header for the given tag
3083 # Arguments : $tag - doctype tag
3084 #############################################################################
3088 my $header = $doctype_header;
3089 $header =~ s/<!DOCTYPE \w+/<!DOCTYPE $tag/;
3091 # fix the path for book since this is one level up
3092 if ($tag eq "book") {
3093 $header =~ s#<!ENTITY % gtkdocentities SYSTEM \"../([a-zA-Z./]+)\">#<!ENTITY % gtkdocentities SYSTEM \"$1\">#;
3100 #############################################################################
3101 # Function : MakeXRef
3102 # Description : This returns a cross-reference link to the given symbol.
3103 # Though it doesn't try to do this for a few standard C types
3104 # that it knows won't be in the documentation.
3105 # Arguments : $symbol - the symbol to try to create a XRef to.
3106 # $text - text text to put inside the XRef, defaults to $symbol
3107 #############################################################################
3110 my ($symbol, $text) = ($_[0], $_[1]);
3112 $symbol =~ s/^\s+//;
3113 $symbol =~ s/\s+$//;
3115 if (!defined($text)) {
3118 # Get rid of special suffixes ('-struct','-enum').
3119 $text =~ s/-struct$//;
3120 $text =~ s/-enum$//;
3123 if ($symbol =~ m/ /) {
3127 @TRACE@("Getting type link for $symbol -> $text\n");
3129 my $symbol_id = &CreateValidSGMLID ($symbol);
3130 return "<link linkend=\"$symbol_id\">$text</link>";
3134 #############################################################################
3135 # Function : MakeIndexterms
3136 # Description : This returns a indexterm elements for the given symbol
3137 # Arguments : $symbol - the symbol to create indexterms for
3138 #############################################################################
3140 sub MakeIndexterms {
3141 my ($symbol, $id) = @_;
3145 # make the index useful, by ommiting the namespace when sorting
3146 if ($NAME_SPACE ne "") {
3147 if ($symbol =~ m/^$NAME_SPACE\_?(.*)/i) {
3148 $sortas=" sortas=\"$1\"";
3152 if (exists $Deprecated{$symbol}) {
3153 $terms .= "<indexterm zone=\"$id\" role=\"deprecated\"><primary$sortas>$symbol</primary></indexterm>";
3154 $IndexEntriesDeprecated{$symbol}=$id;
3155 $IndexEntriesFull{$symbol}=$id;
3157 if (exists $Since{$symbol}) {
3158 my $since = $Since{$symbol};
3162 $terms .= "<indexterm zone=\"$id\" role=\"$since\"><primary$sortas>$symbol</primary></indexterm>";
3164 $IndexEntriesSince{$symbol}=$id;
3165 $IndexEntriesFull{$symbol}=$id;
3168 $terms .= "<indexterm zone=\"$id\"><primary$sortas>$symbol</primary></indexterm>";
3169 $IndexEntriesFull{$symbol}=$id;
3175 #############################################################################
3176 # Function : MakeDeprecationNote
3177 # Description : This returns a deprecation warning for the given symbol.
3178 # Arguments : $symbol - the symbol to try to create a warning for.
3179 #############################################################################
3181 sub MakeDeprecationNote {
3182 my ($symbol) = $_[0];
3184 if (exists $Deprecated{$symbol}) {
3187 $desc .= "<warning><para><literal>$symbol</literal> ";
3189 $note = $Deprecated{$symbol};
3191 if ($note =~ /^\s*([0-9\.]+)\s*:?/) {
3192 $desc .= "has been deprecated since version $1 and should not be used in newly-written code.</para>";
3194 $desc .= "is deprecated and should not be used in newly-written code.</para>";
3196 $note =~ s/^\s*([0-9\.]+)\s*:?\s*//;
3200 $note = &ConvertMarkDown($symbol, $note);
3201 $desc .= " " . $note;
3203 $desc .= "</warning>\n";
3208 #############################################################################
3209 # Function : MakeConditionDescription
3210 # Description : This returns a sumary of conditions for the given symbol.
3211 # Arguments : $symbol - the symbol to try to create the sumary.
3212 #############################################################################
3214 sub MakeConditionDescription {
3215 my ($symbol) = $_[0];
3218 if (exists $Deprecated{$symbol}) {
3223 if ($Deprecated{$symbol} =~ /^\s*(.*?)\s*$/) {
3224 $desc .= "deprecated:$1";
3226 $desc .= "deprecated";
3230 if (exists $Since{$symbol}) {
3235 if ($Since{$symbol} =~ /^\s*(.*?)\s*$/) {
3236 $desc .= "since:$1";
3242 if (exists $StabilityLevel{$symbol}) {
3246 $desc .= "stability:".$StabilityLevel{$symbol};
3251 $cond =~ s/\"/"/g;
3252 $desc=" condition=\"".$cond."\"";
3253 @TRACE@("condition for '$symbol' = '$desc'\n");
3258 #############################################################################
3259 # Function : GetHierarchy
3260 # Description : Returns the DocBook output describing the ancestors and
3261 # immediate children of a GObject subclass. It uses the
3262 # global @Objects and @ObjectLevels arrays to walk the tree.
3264 # Arguments : $object - the GtkObject subclass.
3265 # @hierarchy - previous hierarchy
3266 #############################################################################
3269 my ($object,$hierarchy_ref) = @_;
3270 my @hierarchy = @{$hierarchy_ref};
3272 # Find object in the objects array.
3278 for ($i = 0; $i < @Objects; $i++) {
3280 if ($ObjectLevels[$i] <= $level) {
3283 elsif ($ObjectLevels[$i] == $level + 1) {
3284 push (@children, $Objects[$i]);
3287 elsif ($Objects[$i] eq $object) {
3290 $level = $ObjectLevels[$i];
3297 # Walk up the hierarchy, pushing ancestors onto the ancestors array.
3299 push (@ancestors, $object);
3300 @TRACE@("Level: $level\n");
3301 while ($level > 1) {
3303 if ($ObjectLevels[$j] < $level) {
3304 push (@ancestors, $Objects[$j]);
3305 $level = $ObjectLevels[$j];
3306 @TRACE@("Level: $level\n");
3310 # Output the ancestors, indented and with links.
3313 for ($i = $#ancestors; $i >= 0; $i--) {
3316 my $ancestor = $ancestors[$i];
3317 my $ancestor_id = &CreateValidSGMLID ($ancestor);
3318 my $indent = ' ' x ($level * 4);
3319 # Don't add a link to the current object, i.e. when i == 0.
3321 $entry_text = $indent . "<link linkend=\"$ancestor_id\">$ancestor</link>";
3322 $alt_text = $indent . $ancestor;
3324 $entry_text = $indent . $ancestor;
3325 $alt_text = $indent . "<link linkend=\"$ancestor_id\">$ancestor</link>";
3327 @TRACE@("Checking for '$entry_text' or '$alt_text'");
3328 # Check if we already have this object
3330 for ($j = 0; $j <= $#hierarchy; $j++) {
3331 if (($hierarchy[$j] eq $entry_text) or ($hierarchy[$j] eq $alt_text)) {
3337 # We have a new entry, find insert position in alphabetical order
3339 for ($j = $last_index; $j <= $#hierarchy; $j++) {
3340 if ($hierarchy[$j] !~ m/^${indent}/) {
3344 } elsif ($hierarchy[$j] =~ m/^${indent}[^ ]/) {
3345 my $stripped_text = $hierarchy[$j];
3346 if ($entry_text !~ m/<link linkend/) {
3347 $stripped_text =~ s%<link linkend="[A-Za-z]*">%%;
3348 $stripped_text =~ s%</link>%%;
3350 if ($entry_text lt $stripped_text) {
3359 $last_index = 1 + $#hierarchy;
3361 splice @hierarchy, $last_index, 0, ($entry_text);
3364 # Already have this one, make sure we use the not linked version
3365 if ($entry_text !~ m/<link linkend=/) {
3366 $hierarchy[$j] = $entry_text;
3368 # Remember index as base insert point
3369 $last_index = $index + 1;
3373 # Output the children, indented and with links.
3374 for ($i = 0; $i <= $#children; $i++) {
3375 my $id = &CreateValidSGMLID ($children[$i]);
3376 my $indented_text = ' ' x ($level * 4) . "<link linkend=\"$id\">$children[$i]</link>";
3377 splice @hierarchy, $last_index, 0, ($indented_text);
3384 #############################################################################
3385 # Function : GetInterfaces
3386 # Description : Returns the DocBook output describing the interfaces
3387 # implemented by a class. It uses the global %Interfaces hash.
3388 # Arguments : $object - the GtkObject subclass.
3389 #############################################################################
3396 # Find object in the objects array.
3397 if (exists($Interfaces{$object})) {
3398 my @ifaces = split(' ', $Interfaces{$object});
3403 for ($i = 0; $i <= $#ifaces; $i++) {
3404 my $id = &CreateValidSGMLID ($ifaces[$i]);
3405 $text .= " <link linkend=\"$id\">$ifaces[$i]</link>";
3406 if ($i < $#ifaces - 1) {
3409 elsif ($i < $#ifaces) {
3424 #############################################################################
3425 # Function : GetImplementations
3426 # Description : Returns the DocBook output describing the implementations
3427 # of an interface. It uses the global %Interfaces hash.
3428 # Arguments : $object - the GtkObject subclass.
3429 #############################################################################
3431 sub GetImplementations {
3436 foreach my $key (keys %Interfaces) {
3437 if ($Interfaces{$key} =~ /\b$object\b/) {
3438 push (@impls, $key);
3442 @impls = sort @impls;
3445 $object is implemented by
3447 for ($i = 0; $i <= $#impls; $i++) {
3448 my $id = &CreateValidSGMLID ($impls[$i]);
3449 $text .= " <link linkend=\"$id\">$impls[$i]</link>";
3450 if ($i < $#impls - 1) {
3453 elsif ($i < $#impls) {
3468 #############################################################################
3469 # Function : GetPrerequisites
3470 # Description : Returns the DocBook output describing the prerequisites
3471 # of an interface. It uses the global %Prerequisites hash.
3472 # Arguments : $iface - the interface.
3473 #############################################################################
3475 sub GetPrerequisites {
3480 if (exists($Prerequisites{$iface})) {
3485 my @prereqs = split(' ', $Prerequisites{$iface});
3486 for ($i = 0; $i <= $#prereqs; $i++) {
3487 my $id = &CreateValidSGMLID ($prereqs[$i]);
3488 $text .= " <link linkend=\"$id\">$prereqs[$i]</link>";
3489 if ($i < $#prereqs - 1) {
3492 elsif ($i < $#prereqs) {
3506 #############################################################################
3507 # Function : GetDerived
3508 # Description : Returns the DocBook output describing the derived interfaces
3509 # of an interface. It uses the global %Prerequisites hash.
3510 # Arguments : $iface - the interface.
3511 #############################################################################
3519 foreach my $key (keys %Prerequisites) {
3520 if ($Prerequisites{$key} =~ /\b$iface\b/) {
3521 push (@derived, $key);
3524 if ($#derived >= 0) {
3525 @derived = sort @derived;
3528 $iface is required by
3530 for ($i = 0; $i <= $#derived; $i++) {
3531 my $id = &CreateValidSGMLID ($derived[$i]);
3532 $text .= " <link linkend=\"$id\">$derived[$i]</link>";
3533 if ($i < $#derived - 1) {
3536 elsif ($i < $#derived) {
3551 #############################################################################
3552 # Function : GetSignals
3553 # Description : Returns the synopsis and detailed description DocBook output
3554 # for the signal handlers of a given GtkObject subclass.
3555 # Arguments : $object - the GtkObject subclass, e.g. 'GtkButton'.
3556 #############################################################################
3564 for ($i = 0; $i <= $#SignalObjects; $i++) {
3565 if ($SignalObjects[$i] eq $object) {
3566 @TRACE@("Found signal: $SignalNames[$i]\n");
3567 my $name = $SignalNames[$i];
3568 my $symbol = "${object}::${name}";
3569 my $id = &CreateValidSGMLID ("$object-$name");
3571 $desc .= "<refsect2 id=\"$id\" role=\"signal\"><title>The <literal>“$name”</literal> signal</title>\n";
3572 $desc .= MakeIndexterms($symbol, $id);
3574 $desc .= OutputSymbolExtraLinks($symbol);
3576 $desc .= "<programlisting language=\"C\">";
3578 $SignalReturns[$i] =~ m/\s*(const\s+)?(\w+)\s*(\**)/;
3579 my $type_modifier = defined($1) ? $1 : "";
3582 my $xref = &MakeXRef ($type, &tagify($type, "returnvalue"));
3584 my $ret_type_output = "$type_modifier$xref$pointer";
3585 my $callback_name = "user_function";
3586 $desc .= "${ret_type_output}\n${callback_name} (";
3588 my $indentation = ' ' x (length($callback_name) + 2);
3589 my $pad = $indentation;
3591 my $sourceparams = $SourceSymbolParams{$symbol};
3592 my @params = split ("\n", $SignalPrototypes[$i]);
3595 my $type_len = length("gpointer");
3596 my $name_len = length("user_data");
3597 # do two passes, the first one is to calculate padding
3598 for ($l = 0; $l < 2; $l++) {
3599 for ($j = 0; $j <= $#params; $j++) {
3601 # allow alphanumerics, '_', '[' & ']' in param names
3602 if ($params[$j] =~ m/^\s*(\w+)\s*(\**)\s*([\w\[\]]+)\s*$/) {
3605 if (defined($sourceparams)) {
3606 $param_name = $$sourceparams[$PARAM_FIELD_COUNT * $j];
3611 if (!defined($param_name)) {
3612 $param_name = "arg$j";
3615 if (length($type) + length($pointer) > $type_len) {
3616 $type_len = length($type) + length($pointer);
3618 if (length($param_name) > $name_len) {
3619 $name_len = length($param_name);
3623 $xref = &MakeXRef ($type, &tagify($type, "type"));
3624 $pad = ' ' x ($type_len - length($type) - length($pointer));
3625 $desc .= "$xref$pad $pointer${param_name},\n";
3626 $desc .= $indentation;
3629 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
3630 "Can't parse arg: $params[$j]\nArgs:$SignalPrototypes[$i]");
3634 $xref = &MakeXRef ("gpointer", &tagify("gpointer", "type"));
3635 $pad = ' ' x ($type_len - length("gpointer"));
3636 $desc .= "$xref$pad user_data)";
3637 $desc .= "</programlisting>\n";
3639 my $flags = $SignalFlags[$i];
3640 my $flags_string = "";
3642 if (defined ($flags)) {
3643 if ($flags =~ m/f/) {
3644 $flags_string = "<link linkend=\"G-SIGNAL-RUN-FIRST:CAPS\">Run First</link>";
3646 elsif ($flags =~ m/l/) {
3647 $flags_string = "<link linkend=\"G-SIGNAL-RUN-LAST:CAPS\">Run Last</link>";
3649 elsif ($flags =~ m/c/) {
3650 $flags_string = "<link linkend=\"G-SIGNAL-RUN-CLEANUP:CAPS\">Cleanup</link>";
3651 $flags_string = "Cleanup";
3653 if ($flags =~ m/r/) {
3654 if ($flags_string) { $flags_string .= " / "; }
3655 $flags_string = "<link linkend=\"G-SIGNAL-NO-RECURSE:CAPS\">No Recursion</link>";
3657 if ($flags =~ m/d/) {
3658 if ($flags_string) { $flags_string .= " / "; }
3659 $flags_string = "<link linkend=\"G-SIGNAL-DETAILED:CAPS\">Has Details</link>";
3661 if ($flags =~ m/a/) {
3662 if ($flags_string) { $flags_string .= " / "; }
3663 $flags_string = "<link linkend=\"G-SIGNAL-ACTION:CAPS\">Action</link>";
3665 if ($flags =~ m/h/) {
3666 if ($flags_string) { $flags_string .= " / "; }
3667 $flags_string = "<link linkend=\"G-SIGNAL-NO-HOOKS:CAPS\">No Hooks</link>";
3671 $synop .= "<row><entry role=\"signal_type\">${ret_type_output}</entry><entry role=\"signal_name\"><link linkend=\"$id\">${name}</link></entry><entry role=\"signal_flags\">${flags_string}</entry></row>\n";
3673 my $parameters = &OutputParamDescriptions ("SIGNAL", $symbol);
3675 $AllSymbols{$symbol} = 1;
3676 if (defined ($SymbolDocs{$symbol})) {
3677 my $symbol_docs = &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
3679 $desc .= $symbol_docs;
3681 if (!IsEmptyDoc($SymbolDocs{$symbol})) {
3682 $AllDocumentedSymbols{$symbol} = 1;
3685 if (defined ($SymbolAnnotations{$symbol})) {
3686 my $param_desc = $SymbolAnnotations{$symbol};
3687 my $param_annotations = "";
3688 ($param_desc,$param_annotations) = &ExpandAnnotation($symbol, $param_desc);
3689 if ($param_annotations ne "") {
3690 $desc .= "\n<para>$param_annotations</para>";
3693 $desc .= &MakeDeprecationNote($symbol);
3695 $desc .= $parameters;
3696 if ($flags_string) {
3697 $desc .= "<para>Flags: $flags_string</para>\n";
3699 $desc .= OutputSymbolTraits ($symbol);
3700 $desc .= "</refsect2>";
3703 return ($synop, $desc);
3707 #############################################################################
3708 # Function : GetArgs
3709 # Description : Returns the synopsis and detailed description DocBook output
3710 # for the Args of a given GtkObject subclass.
3711 # Arguments : $object - the GtkObject subclass, e.g. 'GtkButton'.
3712 #############################################################################
3718 my $child_synop = "";
3719 my $child_desc = "";
3720 my $style_synop = "";
3721 my $style_desc = "";
3724 for ($i = 0; $i <= $#ArgObjects; $i++) {
3725 if ($ArgObjects[$i] eq $object) {
3726 @TRACE@("Found arg: $ArgNames[$i]\n");
3727 my $name = $ArgNames[$i];
3728 my $flags = $ArgFlags[$i];
3729 my $flags_string = "";
3733 if ($flags =~ m/c/) {
3734 $kind = "child property";
3737 elsif ($flags =~ m/s/) {
3738 $kind = "style property";
3745 # Remember only one colon so we don't clash with signals.
3746 my $symbol = "${object}:${name}";
3747 # use two dashes and ev. an extra separator here for the same reason.
3748 my $id = &CreateValidSGMLID ("$object--$id_sep$name");
3750 my $type = $ArgTypes[$i];
3752 my $range = $ArgRanges[$i];
3753 my $range_output = CreateValidSGML ($range);
3754 my $default = $ArgDefaults[$i];
3755 my $default_output = CreateValidSGML ($default);
3757 if ($type eq "GtkString") {
3758 $type = "char *";
3760 if ($type eq "GtkSignal") {
3761 $type = "GtkSignalFunc, gpointer";
3762 $type_output = &MakeXRef ("GtkSignalFunc") . ", "
3763 . &MakeXRef ("gpointer");
3764 } elsif ($type =~ m/^(\w+)\*$/) {
3765 $type_output = &MakeXRef ($1, &tagify($1, "type")) . " *";
3767 $type_output = &MakeXRef ($type, &tagify($type, "type"));
3770 if ($flags =~ m/r/) {
3771 $flags_string = "Read";
3773 if ($flags =~ m/w/) {
3774 if ($flags_string) { $flags_string .= " / "; }
3775 $flags_string .= "Write";
3777 if ($flags =~ m/x/) {
3778 if ($flags_string) { $flags_string .= " / "; }
3779 $flags_string .= "Construct";
3781 if ($flags =~ m/X/) {
3782 if ($flags_string) { $flags_string .= " / "; }
3783 $flags_string .= "Construct Only";
3786 $AllSymbols{$symbol} = 1;
3788 if (defined($SymbolDocs{$symbol}) &&
3789 !IsEmptyDoc($SymbolDocs{$symbol})) {
3790 $blurb = &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
3791 @TRACE@(".. [$SymbolDocs{$symbol}][$blurb]\n");
3792 $AllDocumentedSymbols{$symbol} = 1;
3795 if ($ArgBlurbs[$i] ne "") {
3796 $blurb = "<para>" . &CreateValidSGML ($ArgBlurbs[$i]) . "</para>";
3797 $AllDocumentedSymbols{$symbol} = 1;
3799 # FIXME: print a warning?
3800 @TRACE@(".. no description\n");
3804 my $pad1 = " " x (24 - length ($name));
3806 my $arg_synop = "<row><entry role=\"property_type\">$type_output</entry><entry role=\"property_name\"><link linkend=\"$id\">$name</link></entry><entry role=\"property_flags\">$flags_string</entry></row>\n";
3807 my $arg_desc = "<refsect2 id=\"$id\" role=\"property\"><title>The <literal>“$name”</literal> $kind</title>\n";
3808 $arg_desc .= MakeIndexterms($symbol, $id);
3810 $arg_desc .= OutputSymbolExtraLinks($symbol);
3812 $arg_desc .= "<programlisting> “$name”$pad1 $type_output</programlisting>\n";
3813 $arg_desc .= $blurb;
3814 if (defined ($SymbolAnnotations{$symbol})) {
3815 my $param_desc = $SymbolAnnotations{$symbol};
3816 my $param_annotations = "";
3817 ($param_desc,$param_annotations) = &ExpandAnnotation($symbol, $param_desc);
3818 if ($param_annotations ne "") {
3819 $arg_desc .= "\n<para>$param_annotations</para>";
3822 $arg_desc .= &MakeDeprecationNote($symbol);
3824 if ($flags_string) {
3825 $arg_desc .= "<para>Flags: $flags_string</para>\n";
3828 $arg_desc .= "<para>Allowed values: $range_output</para>\n";
3830 if ($default ne "") {
3831 $arg_desc .= "<para>Default value: $default_output</para>\n";
3833 $arg_desc .= OutputSymbolTraits ($symbol);
3834 $arg_desc .= "</refsect2>\n";
3836 if ($flags =~ m/c/) {
3837 $child_synop .= $arg_synop;
3838 $child_desc .= $arg_desc;
3840 elsif ($flags =~ m/s/) {
3841 $style_synop .= $arg_synop;
3842 $style_desc .= $arg_desc;
3845 $synop .= $arg_synop;
3850 return ($synop, $child_synop, $style_synop, $desc, $child_desc, $style_desc);
3854 #############################################################################
3855 # Function : ReadSourceDocumentation
3856 # Description : This reads in the documentation embedded in comment blocks
3857 # in the source code (for Gnome).
3859 # Parameter descriptions override any in the template files.
3860 # Function descriptions are placed before any description from
3861 # the template files.
3863 # It recursively descends the source directory looking for .c
3864 # files and scans them looking for specially-formatted comment
3867 # Arguments : $source_dir - the directory to scan.
3868 #############m###############################################################
3870 sub ReadSourceDocumentation {
3871 my ($source_dir) = @_;
3872 my ($file, $dir, @suffix_list, $suffix);
3874 # prepend entries from @SOURCE_DIR
3875 for my $dir (@SOURCE_DIRS) {
3876 # Check if the filename is in the ignore list.
3877 if ($source_dir =~ m%^\Q$dir\E/(.*)$% and $IGNORE_FILES =~ m/(\s|^)\Q$1\E(\s|$)/) {
3878 @TRACE@("Skipping source directory: $source_dir");
3881 @TRACE@("No match for: ".($1 || $source_dir));
3885 @TRACE@("Scanning source directory: $source_dir");
3887 # This array holds any subdirectories found.
3890 @suffix_list = split (/,/, $SOURCE_SUFFIXES);
3892 opendir (SRCDIR, $source_dir)
3893 || die "Can't open source directory $source_dir: $!";
3895 foreach $file (readdir (SRCDIR)) {
3896 if ($file =~ /^\./) {
3898 } elsif (-d "$source_dir/$file") {
3899 push (@subdirs, $file);
3900 } elsif (@suffix_list) {
3901 foreach $suffix (@suffix_list) {
3902 if ($file =~ m/\.\Q${suffix}\E$/) {
3903 &ScanSourceFile ("$source_dir/$file");
3906 } elsif ($file =~ m/\.[ch]$/) {
3907 &ScanSourceFile ("$source_dir/$file");
3912 # Now recursively scan the subdirectories.
3913 foreach $dir (@subdirs) {
3914 &ReadSourceDocumentation ("$source_dir/$dir");
3919 #############################################################################
3920 # Function : ScanSourceFile
3921 # Description : Scans one source file looking for specially-formatted comment
3922 # blocks. Later &MergeSourceDocumentation is used to merge any
3923 # documentation found with the documentation already read in
3924 # from the template files.
3926 # Arguments : $file - the file to scan.
3927 #############################################################################
3929 sub ScanSourceFile {
3933 # prepend entries from @SOURCE_DIR
3934 for my $dir (@SOURCE_DIRS) {
3935 # Check if the filename is in the ignore list.
3936 if ($file =~ m%^\Q$dir\E/(.*)$% and $IGNORE_FILES =~ m/(\s|^)\Q$1\E(\s|$)/) {
3937 @TRACE@("Skipping source file: $file");
3942 if ($file =~ m/^.*[\/\\]([^\/\\]*)$/) {
3945 &LogWarning ($file, 1, "Can't find basename for this filename.");
3949 # Check if the basename is in the list of files to ignore.
3950 if ($IGNORE_FILES =~ m/(\s|^)\Q${basename}\E(\s|$)/) {
3951 @TRACE@("Skipping source file: $file");
3955 @TRACE@("Scanning source file: $file");
3957 open (SRCFILE, $file)
3958 || die "Can't open $file: $!";
3959 my $in_comment_block = 0;
3962 my ($description, $return_desc);
3963 my ($since_desc, $stability_desc, $deprecated_desc);
3967 # Look for the start of a comment block.
3968 if (!$in_comment_block) {
3969 if (m%^\s*/\*.*\*/%) {
3970 #one-line comment - not gtkdoc
3971 } elsif (m%^\s*/\*\*\s%) {
3972 @TRACE@("Found comment block start\n");
3974 $in_comment_block = 1;
3976 # Reset all the symbol data.
3982 $deprecated_desc = "";
3983 $stability_desc = "";
3984 $current_param = -1;
3990 # We're in a comment block. Check if we've found the end of it.
3993 # maybe its not even meant to be a gtk-doc comment?
3994 &LogWarning ($file, $., "Symbol name not found at the start of the comment block.");
3996 # Add the return value description onto the end of the params.
3998 # TODO(ensonic): check for duplicated Return docs
3999 # &LogWarning ($file, $., "Multiple Returns for $symbol.");
4000 push (@params, "Returns");
4001 push (@params, $return_desc);
4003 # Convert special characters
4004 $description = &ConvertSGMLChars ($symbol, $description);
4006 for ($k = 1; $k <= $#params; $k += $PARAM_FIELD_COUNT) {
4007 $params[$k] = &ConvertSGMLChars ($symbol, $params[$k]);
4010 # Handle Section docs
4011 if ($symbol =~ m/SECTION:\s*(.*)/) {
4015 if (scalar %KnownSymbols) {
4016 if ((! defined($KnownSymbols{"$TMPL_DIR/$real_symbol:Long_Description"})) || $KnownSymbols{"$TMPL_DIR/$real_symbol:Long_Description"} != 1) {
4017 &LogWarning ($file, $., "Section $real_symbol is not defined in the $MODULE-sections.txt file.");
4021 @TRACE@("SECTION DOCS found in source for : '$real_symbol'\n");
4022 for ($k = 0; $k <= $#params; $k += $PARAM_FIELD_COUNT) {
4023 @TRACE@(" '".$params[$k]."'\n");
4024 $params[$k] = "\L$params[$k]";
4026 if ($params[$k] eq "short_description") {
4027 $key = "$TMPL_DIR/$real_symbol:Short_Description";
4028 } elsif ($params[$k] eq "see_also") {
4029 $key = "$TMPL_DIR/$real_symbol:See_Also";
4030 } elsif ($params[$k] eq "title") {
4031 $key = "$TMPL_DIR/$real_symbol:Title";
4032 } elsif ($params[$k] eq "stability") {
4033 $key = "$TMPL_DIR/$real_symbol:Stability_Level";
4034 } elsif ($params[$k] eq "section_id") {
4035 $key = "$TMPL_DIR/$real_symbol:Section_Id";
4036 } elsif ($params[$k] eq "include") {
4037 $key = "$TMPL_DIR/$real_symbol:Include";
4038 } elsif ($params[$k] eq "image") {
4039 $key = "$TMPL_DIR/$real_symbol:Image";
4041 if (defined($key)) {
4042 $SourceSymbolDocs{$key}=$params[$k+1];
4043 $SourceSymbolSourceFile{$key} = $file;
4044 $SourceSymbolSourceLine{$key} = $.;
4047 $SourceSymbolDocs{"$TMPL_DIR/$real_symbol:Long_Description"}=$description;
4048 $SourceSymbolSourceFile{"$TMPL_DIR/$real_symbol:Long_Description"} = $file;
4049 $SourceSymbolSourceLine{"$TMPL_DIR/$real_symbol:Long_Description"} = $.;
4050 #$SourceSymbolTypes{$symbol} = "SECTION";
4052 @TRACE@("SYMBOL DOCS found in source for : '$symbol' ",length($description), "\n");
4053 $SourceSymbolDocs{$symbol} = $description;
4054 $SourceSymbolParams{$symbol} = [ @params ];
4055 # FIXME $SourceSymbolTypes{$symbol} = "STRUCT,SIGNAL,ARG,FUNCTION,MACRO";
4056 #if (defined $DeclarationTypes{$symbol}) {
4057 # $SourceSymbolTypes{$symbol} = $DeclarationTypes{$symbol}
4059 $SourceSymbolSourceFile{$symbol} = $file;
4060 $SourceSymbolSourceLine{$symbol} = $.;
4064 ($since_desc, my @extra_lines) = split ("\n", $since_desc);
4065 $since_desc =~ s/^\s+//;
4066 $since_desc =~ s/\s+$//;
4067 @TRACE@("Since($symbol) : [$since_desc]\n");
4068 $Since{$symbol} = &ConvertSGMLChars ($symbol, $since_desc);
4069 if(scalar @extra_lines) {
4070 &LogWarning ($file, $., "multi-line since docs found");
4074 if ($stability_desc) {
4075 $stability_desc = &ParseStabilityLevel($stability_desc, $file, $., "Stability level for $symbol");
4076 $StabilityLevel{$symbol} = &ConvertSGMLChars ($symbol, $stability_desc);
4079 if ($deprecated_desc) {
4080 if (!exists $Deprecated{$symbol}) {
4081 # don't warn for signals and properties
4082 #if ($symbol !~ m/::?(.*)/) {
4083 if (defined $DeclarationTypes{$symbol}) {
4084 &LogWarning ($file, $.,
4085 "$symbol is deprecated in the inline comments, but no deprecation guards were found around the declaration.".
4086 " (See the --deprecated-guards option for gtkdoc-scan.)");
4089 $Deprecated{$symbol} = &ConvertSGMLChars ($symbol, $deprecated_desc);
4093 $in_comment_block = 0;
4097 # Get rid of ' * ' at start of every line in the comment block.
4099 # But make sure we don't get rid of the newline at the end.
4103 @TRACE@("scanning :$_");
4105 # If we haven't found the symbol name yet, look for it.
4107 if (m%^\s*(SECTION:\s*\S+)%) {
4109 @TRACE@("SECTION DOCS found in source for : '$symbol'\n");
4110 } elsif (m%^\s*([\w:-]*\w)\s*:?\s*(\([-A-Za-z0-9._() ]+?\)\s*)*$%) {
4112 my $annotation = $2;
4113 @TRACE@("SYMBOL DOCS found in source for : '$symbol'\n");
4114 if (defined($annotation)) {
4116 if ($annotation ne "") {
4117 $SymbolAnnotations{$symbol} = $annotation;
4118 @TRACE@("remaining text for $symbol: '$annotation'\n");
4125 if ($in_part eq "description") {
4126 # Get rid of 'Description:'
4127 s%^\s*Description:%%;
4130 if (m%^\s*(returns|return\s+value):%i) {
4131 # we're in param section and have not seen the blank line
4132 if($in_part ne "") {
4134 $in_part = "return";
4137 } elsif (m%^\s*since:%i) {
4138 # we're in param section and have not seen the blank line
4139 if($in_part ne "param") {
4144 } elsif (m%^\s*deprecated:%i) {
4145 # we're in param section and have not seen the blank line
4146 if($in_part ne "param") {
4147 $deprecated_desc = $';
4148 $in_part = "deprecated";
4151 } elsif (m%^\s*stability:%i) {
4152 $stability_desc = $';
4153 $in_part = "stability";
4157 if ($in_part eq "description") {
4160 } elsif ($in_part eq "return") {
4163 } elsif ($in_part eq "since") {
4166 } elsif ($in_part eq "stability") {
4167 $stability_desc .= $_;
4169 } elsif ($in_part eq "deprecated") {
4170 $deprecated_desc .= $_;
4174 # We must be in the parameters. Check for the empty line below them.
4176 $in_part = "description";
4180 # Look for a parameter name.
4181 if (m%^\s*@(\S+)\s*:\s*%) {
4182 my $param_name = $1;
4183 my $param_desc = $';
4185 @TRACE@("Found parameter: $param_name\n");
4186 # Allow varargs variations
4187 if ($param_name =~ m/^\.\.\.$/) {
4188 $param_name = "...";
4190 @TRACE@("Found param for symbol $symbol : '$param_name'= '$_'");
4192 push (@params, $param_name);
4193 push (@params, $param_desc);
4194 $current_param += $PARAM_FIELD_COUNT;
4197 } elsif ($in_part eq "") {
4198 @TRACE@("continuation for $symbol annotation '$_'");
4199 my $annotation = $_;
4200 $annotation =~ s/^\s+|\s+$//g ;
4201 $SymbolAnnotations{$symbol} .= $annotation;
4205 # We must be in the middle of a parameter description, so add it on
4206 # to the last element in @params.
4207 if ($current_param == -1) {
4208 &LogWarning ($file, $., "Parsing comment block file : parameter expected, but got '$_'");
4210 $params[$#params] .= $_;
4216 #############################################################################
4217 # Function : OutputMissingDocumentation
4218 # Description : Outputs report of documentation coverage to a file
4221 #############################################################################
4223 sub OutputMissingDocumentation {
4224 my $old_undocumented_file = "$ROOT_DIR/$MODULE-undocumented.txt";
4225 my $new_undocumented_file = "$ROOT_DIR/$MODULE-undocumented.new";
4227 my $n_documented = 0;
4228 my $n_incomplete = 0;
4234 my $buffer_deprecated = "";
4235 my $buffer_descriptions = "";
4237 open(UNDOCUMENTED, ">$new_undocumented_file")
4238 || die "Can't create $new_undocumented_file";
4240 foreach $symbol (sort (keys (%AllSymbols))) {
4241 # FIXME: should we print LogWarnings for undocumented stuff?
4243 #my $ssfile = &GetSymbolSourceFile($symbol);
4244 #my $ssline = &GetSymbolSourceLine($symbol);
4245 #my $location = "defined at " . (defined($ssfile)?$ssfile:"?") . ":" . (defined($ssline)?$ssline:"0") . "\n";
4247 if ($symbol !~ /:(Title|Long_Description|Short_Description|See_Also|Stability_Level|Include|Section_Id|Image)/) {
4249 if (exists ($AllDocumentedSymbols{$symbol})) {
4251 if (exists ($AllIncompleteSymbols{$symbol})) {
4253 $buffer .= $symbol . " (" . $AllIncompleteSymbols{$symbol} . ")\n";
4254 #$buffer .= "\t0: ".$location;
4256 } elsif (exists $Deprecated{$symbol}) {
4257 if (exists ($AllIncompleteSymbols{$symbol})) {
4259 $buffer_deprecated .= $symbol . " (" . $AllIncompleteSymbols{$symbol} . ")\n";
4260 #$buffer .= "\t1a: ".$location;
4262 $buffer_deprecated .= $symbol . "\n";
4263 #$buffer .= "\t1b: ".$location;
4266 if (exists ($AllIncompleteSymbols{$symbol})) {
4268 $buffer .= $symbol . " (" . $AllIncompleteSymbols{$symbol} . ")\n";
4269 #$buffer .= "\t2a: ".$location;
4271 $buffer .= $symbol . "\n";
4272 #$buffer .= "\t2b: ".$location;
4275 } elsif ($symbol =~ /:(Long_Description|Short_Description)/) {
4277 if (((exists ($SymbolDocs{$symbol})) && (length ($SymbolDocs{$symbol}) > 0))
4278 || ((exists ($AllDocumentedSymbols{$symbol})) && (length ($AllDocumentedSymbols{$symbol}) > 0))) {
4281 # cut off the leading namespace ($TMPL_DIR)
4282 $symbol =~ m/^.*\/(.*)$/;
4283 $buffer_descriptions .= $1 . "\n";
4291 $percent = ($n_documented / $total) * 100.0;
4294 printf UNDOCUMENTED "%.0f%% symbol docs coverage.\n", $percent;
4295 print UNDOCUMENTED "$n_documented symbols documented.\n";
4296 print UNDOCUMENTED "$n_incomplete symbols incomplete.\n";
4297 print UNDOCUMENTED ($total - $n_documented) . " not documented.\n";
4299 if ($buffer_deprecated ne "") {
4300 $buffer .= "\n" . $buffer_deprecated;
4302 if ($buffer_descriptions ne "") {
4303 $buffer .= "\n" . $buffer_descriptions;
4305 if ($buffer ne "") {
4306 print UNDOCUMENTED "\n\n$buffer";
4308 close (UNDOCUMENTED);
4310 return &UpdateFileIfChanged ($old_undocumented_file, $new_undocumented_file, 0);
4312 printf "%.0f%% symbol docs coverage", $percent;
4313 print "($n_documented symbols documented, $n_incomplete symbols incomplete, " . ($total - $n_documented) . " not documented)\n";
4314 print "See $MODULE-undocumented.txt for a list of missing docs.\nThe doc coverage percentage doesn't include intro sections.\n";
4318 #############################################################################
4319 # Function : OutputUndeclaredSymbols
4320 # Description : Outputs symbols that are listed in the section file, but not
4321 # declaration is found in the sources
4324 #############################################################################
4326 sub OutputUndeclaredSymbols {
4327 my $old_undeclared_file = "$ROOT_DIR/$MODULE-undeclared.txt";
4328 my $new_undeclared_file = "$ROOT_DIR/$MODULE-undeclared.new";
4330 open(UNDECLARED, ">$new_undeclared_file")
4331 || die "Can't create $new_undeclared_file";
4333 if (%UndeclaredSymbols) {
4334 print UNDECLARED (join("\n", sort keys %UndeclaredSymbols));
4335 print UNDECLARED "\n";
4336 print "See $MODULE-undeclared.txt for the list of undeclared symbols.\n"
4340 return &UpdateFileIfChanged ($old_undeclared_file, $new_undeclared_file, 0);
4343 #############################################################################
4344 # Function : OutputUnusedSymbols
4345 # Description : Outputs symbols that are documented in comments, but not
4346 # declared in the sources
4349 #############################################################################
4351 sub OutputUnusedSymbols {
4353 my $old_unused_file = "$ROOT_DIR/$MODULE-unused.txt";
4354 my $new_unused_file = "$ROOT_DIR/$MODULE-unused.new";
4356 open (UNUSED, ">$new_unused_file")
4357 || die "Can't open $new_unused_file";
4359 foreach $symbol (sort keys (%Declarations)) {
4360 if (!defined ($DeclarationOutput{$symbol})) {
4361 print (UNUSED "$symbol\n");
4365 foreach $symbol (sort (keys (%AllUnusedSymbols))) {
4366 print (UNUSED "$symbol(" . $AllUnusedSymbols{$symbol} . ")\n");
4370 if ($num_unused != 0) {
4371 &LogWarning ($old_unused_file, 1, "$num_unused unused declarations.".
4372 "They should be added to $MODULE-sections.txt in the appropriate place.");
4375 return &UpdateFileIfChanged ($old_unused_file, $new_unused_file, 0);
4379 #############################################################################
4380 # Function : OutputAllSymbols
4381 # Description : Outputs list of all symbols to a file
4384 #############################################################################
4386 sub OutputAllSymbols {
4387 my $n_documented = 0;
4393 open (SYMBOLS, ">$ROOT_DIR/$MODULE-symbols.txt")
4394 || die "Can't create $ROOT_DIR/$MODULE-symbols.txt: $!";
4396 foreach $symbol (sort (keys (%AllSymbols))) {
4397 print SYMBOLS $symbol . "\n";
4403 #############################################################################
4404 # Function : OutputSymbolsWithoutSince
4405 # Description : Outputs list of all symbols without a since tag to a file
4408 #############################################################################
4410 sub OutputSymbolsWithoutSince {
4411 my $n_documented = 0;
4417 open (SYMBOLS, ">$ROOT_DIR/$MODULE-nosince.txt")
4418 || die "Can't create $ROOT_DIR/$MODULE-nosince.txt: $!";
4420 foreach $symbol (sort (keys (%SourceSymbolDocs))) {
4421 if (!defined $Since{$symbol}) {
4422 print SYMBOLS $symbol . "\n";
4430 #############################################################################
4431 # Function : MergeSourceDocumentation
4432 # Description : This merges documentation read from a source file into the
4433 # documentation read in from a template file.
4435 # Parameter descriptions override any in the template files.
4436 # Function descriptions are placed before any description from
4437 # the template files.
4440 #############################################################################
4442 sub MergeSourceDocumentation {
4446 if (scalar %SymbolDocs) {
4447 @Symbols=keys (%SymbolDocs);
4448 @TRACE@("num existing entries: ".(scalar @Symbols)."\n");
4451 # filter scanned declarations, with what we suppress from -sections.txt
4453 foreach $symbol (keys (%Declarations)) {
4454 if (defined($KnownSymbols{$symbol}) && $KnownSymbols{$symbol} == 1) {
4458 # , add the rest from -sections.txt
4459 foreach $symbol (keys (%KnownSymbols)) {
4460 if ($KnownSymbols{$symbol} == 1) {
4464 # and add whats found in the source
4465 foreach $symbol (keys (%SourceSymbolDocs)) {
4468 @Symbols = keys (%tmp);
4469 @TRACE@("num source entries: ".(scalar @Symbols)."\n");
4471 foreach $symbol (@Symbols) {
4472 $AllSymbols{$symbol} = 1;
4474 my $have_tmpl_docs = 0;
4476 ## see if the symbol is documented in template
4477 my $tmpl_doc = defined ($SymbolDocs{$symbol}) ? $SymbolDocs{$symbol} : "";
4478 my $check_tmpl_doc =$tmpl_doc;
4479 # remove all xml-tags and whitespaces
4480 $check_tmpl_doc =~ s/<.*?>//g;
4481 $check_tmpl_doc =~ s/\s//g;
4483 if ($check_tmpl_doc ne "") {
4484 $have_tmpl_docs = 1;
4486 # if the docs have just an empty para, don't merge that.
4487 $check_tmpl_doc = $tmpl_doc;
4488 $check_tmpl_doc =~ s/(\s|\n)//msg;
4489 if ($check_tmpl_doc eq "<para></para>") {
4494 if (exists ($SourceSymbolDocs{$symbol})) {
4495 my $type = $DeclarationTypes {$symbol};
4497 @TRACE@("merging [$symbol] from source\n");
4499 my $item = "Parameter";
4500 if (defined ($type)) {
4501 if ($type eq 'STRUCT') {
4503 } elsif ($type eq 'ENUM') {
4505 } elsif ($type eq 'UNION') {
4512 my $src_doc = $SourceSymbolDocs{$symbol};
4513 # remove leading and training whitespaces
4514 $src_doc =~ s/^\s+//;
4515 $src_doc =~ s/\s+$//;
4517 # Don't output warnings for overridden titles as titles are
4518 # automatically generated in the -sections.txt file, and thus they
4519 # are often overridden.
4520 if ($have_tmpl_docs && $symbol !~ m/:Title$/) {
4521 # check if content is different
4522 if ($tmpl_doc ne $src_doc) {
4523 #print "[$tmpl_doc] [$src_doc]\n";
4524 &LogWarning ($SourceSymbolSourceFile{$symbol}, $SourceSymbolSourceLine{$symbol},
4525 "Documentation in template ".$SymbolSourceFile{$symbol}.":".$SymbolSourceLine{$symbol}." for $symbol being overridden by inline comments.");
4529 if ($src_doc ne "") {
4530 $AllDocumentedSymbols{$symbol} = 1;
4533 # Do not add <para> to nothing, it breaks missing docs checks.
4534 my $src_doc_para = "";
4535 if ($src_doc ne "") {
4536 $src_doc_para = $src_doc;
4539 if ($symbol =~ m/$TMPL_DIR\/.+:Long_Description/) {
4540 $SymbolDocs{$symbol} = "$src_doc_para$tmpl_doc";
4541 } elsif ($symbol =~ m/$TMPL_DIR\/.+:.+/) {
4542 # For the title/summary/see also section docs we don't want to
4543 # add any <para> tags.
4544 $SymbolDocs{$symbol} = "$src_doc"
4546 $SymbolDocs{$symbol} = "$src_doc_para$tmpl_doc";
4550 if ($symbol =~ m/.*::.*/) {
4551 # For signals we prefer the param names from the source docs,
4552 # since the ones from the templates are likely to contain the
4553 # artificial argn names which are generated by gtkdoc-scangobj.
4554 $SymbolParams{$symbol} = $SourceSymbolParams{$symbol};
4555 # FIXME: we need to check for empty docs here as well!
4557 # The templates contain the definitive parameter names and order,
4558 # so we will not change that. We only override the actual text.
4559 my $tmpl_params = $SymbolParams{$symbol};
4560 if (!defined ($tmpl_params)) {
4561 @TRACE@("No merge needed for $symbol\n");
4562 $SymbolParams{$symbol} = $SourceSymbolParams{$symbol};
4563 # FIXME: we still like to get the number of params and merge
4564 # 1) we would noticed that params have been removed/renamed
4565 # 2) we would catch undocumented params
4566 # params are not (yet) exported in -decl.txt so that we
4567 # could easily grab them :/
4569 my $params = $SourceSymbolParams{$symbol};
4571 @TRACE@("Merge needed for $symbol, tmpl_params: ",$#$tmpl_params,", source_params: ",$#$params," \n");
4572 for ($j = 0; $j <= $#$tmpl_params; $j += $PARAM_FIELD_COUNT) {
4573 my $tmpl_param_name = $$tmpl_params[$j];
4575 # Try to find the param in the source comment documentation.
4578 @TRACE@(" try merge param $tmpl_param_name\n");
4579 for ($k = 0; $k <= $#$params; $k += $PARAM_FIELD_COUNT) {
4580 my $param_name = $$params[$k];
4581 my $param_desc = $$params[$k + 1];
4583 @TRACE@(" test param $param_name\n");
4584 # We accept changes in case, since the Gnome source
4585 # docs contain a lot of these.
4586 if ("\L$param_name" eq "\L$tmpl_param_name") {
4589 # Override the description.
4590 $$tmpl_params[$j + 1] = $param_desc;
4592 # Set the name to "" to mark it as used.
4598 # If it looks like the parameters are there, but not
4599 # in the right place, try to explain a bit better.
4600 if ((!$found) && ($src_doc =~ m/\@$tmpl_param_name:/)) {
4601 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
4602 "Parameters for $symbol must start on the line immediately after the function or macro name.");
4606 # Now we output a warning if parameters have been described which
4608 for ($j = 0; $j <= $#$params; $j += $PARAM_FIELD_COUNT) {
4609 my $param_name = $$params[$j];
4611 # the template builder cannot detect if a macro returns
4613 if(($type eq "MACRO") && ($param_name eq "Returns")) {
4614 # FIXME: do we need to add it then to tmpl_params[] ?
4615 my $num=$#$tmpl_params;
4616 @TRACE@(" adding Returns: to macro docs for $symbol.\n");
4617 $$tmpl_params[$num+1]="Returns";
4618 $$tmpl_params[$num+2]=$$params[$j+1];
4621 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
4622 "$item described in source code comment block but does not exist. $type: $symbol $item: $param_name.");
4628 if ($have_tmpl_docs) {
4629 $AllDocumentedSymbols{$symbol} = 1;
4630 @TRACE@("merging [$symbol] from template\n");
4633 @TRACE@("[$symbol] undocumented\n");
4637 # if this symbol is documented, check if docs are complete
4638 $check_tmpl_doc = defined ($SymbolDocs{$symbol}) ? $SymbolDocs{$symbol} : "";
4639 # remove all xml-tags and whitespaces
4640 $check_tmpl_doc =~ s/<.*?>//g;
4641 $check_tmpl_doc =~ s/\s//g;
4642 if ($check_tmpl_doc ne "") {
4643 my $tmpl_params = $SymbolParams{$symbol};
4644 if (defined ($tmpl_params)) {
4645 my $type = $DeclarationTypes {$symbol};
4647 my $item = "Parameter";
4648 if (defined ($type)) {
4649 if ($type eq 'STRUCT') {
4651 } elsif ($type eq 'ENUM') {
4653 } elsif ($type eq 'UNION') {
4660 @TRACE@("Check param docs for $symbol, tmpl_params: ",$#$tmpl_params," entries, type=$type\n");
4662 if ($#$tmpl_params > 0) {
4664 for ($j = 0; $j <= $#$tmpl_params; $j += $PARAM_FIELD_COUNT) {
4665 # Output a warning if the parameter is empty and
4666 # remember for stats.
4667 my $tmpl_param_name = $$tmpl_params[$j];
4668 my $tmpl_param_desc = $$tmpl_params[$j + 1];
4669 if ($tmpl_param_name ne "void" && $tmpl_param_desc !~ m/\S/) {
4670 if (exists ($AllIncompleteSymbols{$symbol})) {
4671 $AllIncompleteSymbols{$symbol}.=", ".$tmpl_param_name;
4673 $AllIncompleteSymbols{$symbol}=$tmpl_param_name;
4675 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
4676 "$item description for $symbol"."::"."$tmpl_param_name is missing in source code comment block.");
4681 if ($#$tmpl_params == 0) {
4682 $AllIncompleteSymbols{$symbol}="<items>";
4683 &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
4684 "$item descriptions for $symbol are missing in source code comment block.");
4686 # $#$tmpl_params==-1 means we don't know about parameters
4687 # this unfortunately does not tell if there should be some
4692 @TRACE@("num doc entries: ".(scalar %SymbolDocs)."\n");
4695 #############################################################################
4696 # Function : IsEmptyDoc
4697 # Description : Check if a doc-string is empty. Its also regarded as empty if
4698 # it only consist of whitespace or e.g. FIXME.
4699 # Arguments : the doc-string
4700 #############################################################################
4704 if ($doc =~ /^\s*$/) {
4708 if ($doc =~ /^\s*<para>\s*(FIXME)?\s*<\/para>\s*$/) {
4715 #############################################################################
4716 # Function : ConvertMarkDown
4717 # Description : Converts mark down syntax to the respective docbook.
4718 # http://de.wikipedia.org/wiki/Markdown
4719 # Inspired by the design of ParseDown
4720 # http://parsedown.org/
4721 # Copyright (c) 2013 Emanuil Rusev, erusev.com
4722 # Arguments : the symbol name, the doc-string
4723 #############################################################################
4725 sub ConvertMarkDown {
4726 my ($symbol, $text) = @_;
4728 $text = &MarkDownParse ($text, $symbol);
4733 # SUPPORTED MARKDOWN
4734 # ==================
4743 # Setext-style Headers
4744 # --------------------
4752 # Ordered (unnested) Lists
4753 # ------------------------
4757 # 1. item 2 with loooong
4762 # Note: we require a blank line above the list items
4765 # TODO(ensonic): it would be nice to add id parameters to the refsect2 elements
4767 sub MarkDownParseBlocks {
4768 my ($linesref, $symbol, $context) = @_;
4771 my $md_block = { type => "" };
4773 OUTER: foreach $line (@$linesref) {
4774 my $first_char = substr ($line, 0, 1);
4775 my $deindented_line;
4777 @TRACE@("in '".$md_block->{"type"}."' state, parsing '$line'");
4779 if ($md_block->{"type"} eq "markup") {
4780 if (!$md_block->{"closed"}) {
4781 if (index ($line, $md_block->{"start"}) != -1) {
4782 $md_block->{"depth"}++;
4784 if (index ($line, $md_block->{"end"}) != -1) {
4785 if ($md_block->{"depth"} > 0) {
4786 $md_block->{"depth"}--;
4788 @TRACE@("closing tag '$line'");
4789 $md_block->{"closed"} = 1;
4790 # TODO(ensonic): reparse inner text with MarkDownParseLines?
4793 $md_block->{"text"} .= "\n" . $line;
4794 @TRACE@("add to markup");
4799 $deindented_line = $line;
4800 $deindented_line =~ s/^\s+//;
4802 if ($md_block->{"type"} eq "heading") {
4803 # a heading is ended by any level less than or equal
4804 if ($md_block->{"level"} == 1) {
4805 if ($line =~ /^={4,}[ \t]*$/) {
4806 my $text = pop @{$md_block->{"lines"}};
4807 $md_block->{"interrupted"} = 0;
4808 push @md_blocks, $md_block;
4810 $md_block = { type => "heading",
4815 } elsif ($line =~ /^[#][ \t]+(.+?)[ \t]*[#]*[ \t]*(?:{#([^}]+)})?[ \t]*$/) {
4816 $md_block->{"interrupted"} = 0;
4817 push @md_blocks, $md_block;
4819 $md_block = { type => "heading",
4826 # push lines into the block until the end is reached
4827 push @{$md_block->{"lines"}}, $line;
4831 if ($line =~ /^[=]{4,}[ \t]*$/) {
4832 my $text = pop @{$md_block->{"lines"}};
4833 $md_block->{"interrupted"} = 0;
4834 push @md_blocks, $md_block;
4836 $md_block = { type => "heading",
4841 } elsif ($line =~ /^[-]{4,}[ \t]*$/) {
4842 my $text = pop @{$md_block->{"lines"}};
4843 $md_block->{"interrupted"} = 0;
4844 push @md_blocks, $md_block;
4846 $md_block = { type => "heading",
4851 } elsif ($line =~ /^([#]{1,2})[ \t]+(.+?)[ \t]*[#]*[ \t]*(?:{#([^}]+)})?[ \t]*$/) {
4852 $md_block->{"interrupted"} = 0;
4853 push @md_blocks, $md_block;
4855 $md_block = { type => "heading",
4859 level => length($1) };
4862 # push lines into the block until the end is reached
4863 push @{$md_block->{"lines"}}, $line;
4867 } elsif ($md_block->{"type"} eq "code") {
4868 if ($line =~ /^[ \t]*\]\|(.*)/) {
4869 push @md_blocks, $md_block;
4870 $md_block = { type => "paragraph",
4874 push @{$md_block->{"lines"}}, $line;
4879 if ($deindented_line eq "") {
4880 $md_block->{"interrupted"} = 1;
4884 if ($md_block->{"type"} eq "quote") {
4885 if (!$md_block->{"interrupted"}) {
4886 $line =~ s/^[ ]*>[ ]?//;
4887 push @{$md_block->{"lines"}}, $line;
4890 } elsif ($md_block->{"type"} eq "li") {
4891 my $marker = $md_block->{"marker"};
4892 if ($line =~ /^([ ]{0,3})($marker)[ ](.*)/) {
4893 my $indentation = $1;
4894 if ($md_block->{"indentation"} ne $indentation) {
4895 push @{$md_block->{"lines"}}, $line;
4898 my $ordered = $md_block->{"ordered"};
4899 $lines =~ s/^[ ]{0,4}//;
4900 $md_block->{"last"} = 0;
4901 push @md_blocks, $md_block;
4902 $md_block = { type => "li",
4903 ordered => $ordered,
4904 indentation => $indentation,
4908 lines => [ $lines ] };
4913 if ($md_block->{"interrupted"}) {
4914 if ($first_char eq " ") {
4915 push @{$md_block->{"lines"}}, "";
4916 $line =~ s/^[ ]{0,4}//;
4917 push @{$md_block->{"lines"}}, $line;
4918 $md_block->{"interrupted"} = 0;
4922 $line =~ s/^[ ]{0,4}//;
4923 push @{$md_block->{"lines"}}, $line;
4928 # indentation sensitive types
4929 @TRACE@("parsing '$line'");
4931 if ($line =~ /^([#]{1,2})[ \t]+(.+?)[ \t]*[#]*[ \t]*(?:{#([^}]+)})?[ \t]*$/) {
4933 push @md_blocks, $md_block;
4935 $md_block = { type => "heading",
4939 level => length($1) };
4942 } elsif ($line =~ /^={4,}[ \t]*$/) {
4943 # setext heading (====)
4945 if ($md_block->{"type"} eq "paragraph" && $md_block->{"interrupted"}) {
4946 push @md_blocks, $md_block;
4947 $md_block->{"type"} = "heading";
4948 $md_block->{"lines"} = [];
4949 $md_block->{"level"} = 1;
4953 } elsif ($line =~ /^-{4,}[ \t]*$/) {
4954 # setext heading (-----)
4956 if ($md_block->{"type"} eq "paragraph" && $md_block->{"interrupted"}) {
4957 push @md_blocks, $md_block;
4958 $md_block->{"type"} = "heading";
4959 $md_block->{"lines"} = [];
4960 $md_block->{"level"} = 2;
4964 } elsif ($line =~ /^[ \t]*\|\[[ ]*(?:<!-- language="([^"]+?)" -->)?/) {
4966 $md_block->{"interrupted"} = 1;
4967 push @md_blocks, $md_block;
4968 $md_block = { type => "code",
4974 # indentation insensitive types
4975 if ($line =~ /^[ ]*<!DOCTYPE/) {
4976 push @md_blocks, $md_block;
4978 $md_block = { type => "markup",
4979 text => $deindented_line,
4985 } elsif ($line =~ /^[ ]*<\??(\w+)[^>]*([\/\?])?[ \t]*>/) {
4986 # markup, including <?xml version="1.0"?>
4988 my $is_self_closing = defined($2);
4990 # skip link markdown
4991 # TODO(ensonic): consider adding more uri schemes (ftp, ...)
4992 if ($tag =~ /^https?/) {
4993 @TRACE@("skipping link '$tag'");
4995 # for TEXT_LEVEL_ELEMENTS, we want to keep them as-is in the paragraph
4996 # instead of creation a markdown block.
4997 my $scanning_for_end_of_text_level_tag = (
4998 $md_block->{"type"} eq "paragraph" &&
4999 defined($md_block->{"start"}) &&
5000 !$md_block->{"closed"});
5001 @TRACE@("markup found '$tag', scanning $scanning_for_end_of_text_level_tag ?");
5002 if (!$MD_TEXT_LEVEL_ELEMENTS{$tag} && !$scanning_for_end_of_text_level_tag) {
5003 push @md_blocks, $md_block;
5005 if ($is_self_closing) {
5006 @TRACE@("self-closing docbook '$tag'");
5007 $md_block = { type => "self-closing tag",
5008 text => $deindented_line };
5009 $is_self_closing = 0;
5013 @TRACE@("new markup '$tag'");
5014 $md_block = { type => "markup",
5015 text => $deindented_line,
5016 start => "<" . $tag . ">",
5017 end => "</" . $tag . ">",
5020 if ($deindented_line =~ /<\/$tag>/) {
5021 $md_block->{"closed"} = 1;
5025 if ($MD_TEXT_LEVEL_ELEMENTS{$tag}) {
5026 @TRACE@("text level docbook '$tag' in '".$md_block->{"type"}."' state");
5027 # TODO(ensonic): handle nesting
5028 if (!$scanning_for_end_of_text_level_tag) {
5029 if ($deindented_line !~ /<\/$tag>/) {
5030 @TRACE@("new text level markup '$tag'");
5031 $md_block->{"start"} = "<" . $tag . ">";
5032 $md_block->{"end"} = "</" . $tag . ">";
5033 $md_block->{"closed"} = 0;
5034 @TRACE@("scanning for end of '$tag'");
5037 if ($deindented_line =~ /$md_block->{"end"}/) {
5038 $md_block->{"closed"} = 1;
5039 @TRACE@("found end of '$tag'");
5045 } elsif ($line =~ /^([ ]*)[*+-][ ](.*)/) {
5047 push @md_blocks, $md_block;
5049 my $indentation = $1;
5050 $lines =~ s/^[ ]{0,4}//;
5051 $md_block = { type => "li",
5053 indentation => $indentation,
5057 lines => [ $lines ] };
5059 } elsif ($line =~ /^[ ]*>[ ]?(.*)/) {
5060 push @md_blocks, $md_block;
5061 $md_block = { type => "quote",
5067 if ($line =~ /^([ ]{0,4})\d+[.][ ]+(.*)/) {
5068 push @md_blocks, $md_block;
5070 my $indentation = $1;
5071 $lines =~ s/^[ ]{0,4}//;
5073 $md_block = { type => "li",
5075 indentation => $indentation,
5076 marker => "\\d+[.]",
5079 lines => [ $lines ] };
5085 if ($md_block->{"type"} eq "paragraph") {
5086 if ($md_block->{"interrupted"}) {
5087 push @md_blocks, $md_block;
5088 $md_block = { type => "paragraph",
5091 @TRACE@("new paragraph due to interrupted");
5093 $md_block->{"text"} .= "\n" . $line;
5094 @TRACE@("add to paragraph");
5097 push @md_blocks, $md_block;
5098 $md_block = { type => "paragraph",
5100 @TRACE@("new paragraph due to different block type");
5104 push @md_blocks, $md_block;
5111 sub MarkDownParseSpanElementsInner {
5112 my ($text, $markersref) = @_;
5114 my %markers = map { $_ => 1 } @$markersref;
5116 while ($text ne "") {
5117 my $closest_marker = "";
5118 my $closest_marker_index = 0;
5119 my $closest_marker_position = -1;
5120 my $text_marker = "";
5127 while ( ($marker, $use) = each %markers ) {
5128 my $marker_position;
5134 $marker_position = index ($text, $marker);
5136 if ($marker_position < 0) {
5137 $markers{$marker} = 0;
5141 if ($closest_marker eq "" || $marker_position < $closest_marker_position) {
5142 $closest_marker = $marker;
5143 $closest_marker_index = $i;
5144 $closest_marker_position = $marker_position;
5148 if ($closest_marker_position >= 0) {
5149 $text_marker = substr ($text, $closest_marker_position);
5152 if ($text_marker eq "") {
5158 $markup .= substr ($text, 0, $closest_marker_position);
5159 $text = substr ($text, $closest_marker_position);
5160 @markers_rest = map { $markers{$_} ? ($_ eq $closest_marker ? () : $_) : () } keys %markers;
5162 if ($closest_marker eq "![" || $closest_marker eq "[") {
5165 if (index ($text, "]") && $text =~ /\[((?:[^][]|(?R))*)\]/) {
5168 %element = ( "!" => (substr ($text, 0, 1) eq "!"),
5171 $offset = length ($&);
5172 if ($element{"!"}) {
5176 $remaining_text = substr ($text, $offset);
5177 if ($remaining_text =~ /^\([ ]*([^)'"]*?)(?:[ ]+['"](.+?)['"])?[ ]*\)/) {
5182 $offset += length ($&);
5183 } elsif ($remaining_text =~ /^\s*\[([^\]<]*?)\]/) {
5184 $element{"ref"} = $1;
5185 $offset += length ($&);
5192 if ($element{"»"}) {
5193 $element{"»"} =~ s/&/&/g;
5194 $element{"»"} =~ s/</</g;
5196 if ($element{"!"}) {
5197 $markup .= "<inlinemediaobject><imageobject><imagedata fileref=\"" . $element{"»"} . "\"></imagedata></imageobject>";
5199 if (defined ($element{"a"})) {
5200 $markup .= "<textobject><phrase>" . $element{"a"} . "</phrase></textobject>";
5203 $markup .= "</inlinemediaobject>";
5204 } elsif ($element{"ref"}) {
5205 $element{"a"} = &MarkDownParseSpanElementsInner ($element{"a"}, \@markers_rest);
5206 $markup .= "<link linkend=\"" . $element{"ref"} . "\"";
5208 if (defined ($element{"#"})) {
5209 # title attribute not supported
5212 $markup .= ">" . $element{"a"} . "</link>";
5214 $element{"a"} = &MarkDownParseSpanElementsInner ($element{"a"}, \@markers_rest);
5215 $markup .= "<ulink url=\"" . $element{"»"} . "\"";
5217 if (defined ($element{"#"})) {
5218 # title attribute not supported
5221 $markup .= ">" . $element{"a"} . "</ulink>";
5224 $markup .= $closest_marker;
5225 if ($closest_marker eq "![") {
5231 } elsif ($closest_marker eq "<") {
5232 if ($text =~ /^<(https?:[\/]{2}[^\s]+?)>/i) {
5233 my $element_url = $1;
5234 $element_url =~ s/&/&/g;
5235 $element_url =~ s/</</g;
5237 $markup .= "<ulink url=\"" . $element_url . "\">" . $element_url . "</ulink>";
5238 $offset = length ($&);
5239 } elsif ($text =~ /^<([A-Za-z0-9._-]+?@[A-Za-z0-9._-]+?)>/) {
5240 $markup .= "<ulink url=\"mailto:" . $1 . "\">" . $1 . "</ulink>";
5241 $offset = length ($&);
5242 } elsif ($text =~ /^<[^>]+?>/) {
5244 $offset = length ($&);
5249 } elsif ($closest_marker eq "\\") {
5250 my $special_char = substr ($text, 1, 1);
5251 if ($MD_ESCAPABLE_CHARS{$special_char} ||
5252 $MD_GTK_ESCAPABLE_CHARS{$special_char}) {
5253 $markup .= $special_char;
5259 } elsif ($closest_marker eq "`") {
5260 if ($text =~ /^(`+)([^`]+?)\1(?!`)/) {
5261 my $element_text = $2;
5262 $markup .= "<literal>" . $element_text . "</literal>";
5263 $offset = length ($&);
5268 } elsif ($closest_marker eq "@") {
5269 # Convert '@param()'
5270 # FIXME: we could make those also links ($symbol.$2), but that would be less
5271 # useful as the link target is a few lines up or down
5272 if ($text =~ /^(\A|[^\\])\@(\w+((\.|->)\w+)*)\s*\(\)/) {
5273 $markup .= $1 . "<parameter>" . $2 . "()</parameter>\n";
5274 $offset = length ($&);
5275 } elsif ($text =~ /^(\A|[^\\])\@(\w+((\.|->)\w+)*)/) {
5276 # Convert '@param', but not '\@param'.
5277 $markup .= $1 . "<parameter>" . $2 . "</parameter>\n";
5278 $offset = length ($&);
5279 } elsif ($text =~ /^\\\@/) {
5281 $offset = length ($&);
5286 } elsif ($closest_marker eq "#") {
5287 if ($text =~ /^(\A|[^\\])#([\w\-:\.]+[\w]+)\s*\(\)/) {
5288 # handle #Object.func()
5289 $markup .= $1 . &MakeXRef ($2, &tagify ($2 . "()", "function"));
5290 $offset = length ($&);
5291 } elsif ($text =~ /^(\A|[^\\])#([\w\-:\.]+[\w]+)/) {
5292 # Convert '#symbol', but not '\#symbol'.
5293 $markup .= $1 . &MakeHashXRef ($2, "type");
5294 $offset = length ($&);
5295 } elsif ($text =~ /^\\#/) {
5297 $offset = length ($&);
5302 } elsif ($closest_marker eq "%") {
5303 if ($text =~ /^(\A|[^\\])\%(-?\w+)/) {
5304 # Convert '%constant', but not '\%constant'.
5305 # Also allow negative numbers, e.g. %-1.
5306 $markup .= $1 . &MakeXRef ($2, &tagify ($2, "literal"));
5307 $offset = length ($&);
5308 } elsif ($text =~ /^\\%/) {
5310 $offset = length ($&);
5318 $text = substr ($text, $offset);
5325 sub MarkDownParseSpanElements {
5327 my @markers = ( "\\", "<", "![", "[", "`", "%", "#", "@" );
5329 $text = &MarkDownParseSpanElementsInner ($text, \@markers);
5331 # Convert 'function()' or 'macro()'.
5332 # if there is abc_*_def() we don't want to make a link to _def()
5333 # FIXME: also handle abc(def(....)) : but that would need to be done recursively :/
5334 $text =~ s/([^\*.\w])(\w+)\s*\(\)/$1.&MakeXRef($2, &tagify($2 . "()", "function"));/eg;
5339 sub ReplaceEntities {
5340 my ($text, $symbol) = @_;
5342 my @entities = ( [ "<", "<" ],
5351 [ "&", "&" ] ); # Do this last, or the others get messed up.
5354 # Expand entities in <programlisting> even inside CDATA since
5355 # we changed the definition of |[ to add CDATA
5356 for ($i = 0; $i <= $#entities; $i++) {
5357 $text =~ s/$entities[$i][0]/$entities[$i][1]/g;
5363 sub MarkDownOutputDocBook {
5364 my ($blocksref, $symbol, $context) = @_;
5367 my @blocks = @$blocksref;
5369 foreach $block (@blocks) {
5373 #$output .= "\n<!-- beg type='" . $block->{"type"} . "'-->\n";
5375 if ($block->{"type"} eq "paragraph") {
5376 $text = &MarkDownParseSpanElements ($block->{"text"});
5377 if ($context eq "li" && $output eq "") {
5378 if ($block->{"interrupted"}) {
5379 $output .= "\n<para>$text</para>\n";
5381 $output .= "<para>$text</para>";
5387 $output .= "<para>$text</para>\n";
5390 } elsif ($block->{"type"} eq "heading") {
5393 $title = &MarkDownParseSpanElements ($block->{"text"});
5395 if ($block->{"level"} == 1) {
5401 $text = &MarkDownParseLines ($block->{"lines"}, $symbol, "heading");
5402 if (defined ($block->{"id"})) {
5403 $output .= "<$tag id=\"" . $block->{"id"} . "\">";
5405 $output .= "<$tag>";
5408 $output .= "<title>$title</title>$text</$tag>\n";
5409 } elsif ($block->{"type"} eq "li") {
5410 my $tag = "itemizedlist";
5412 if ($block->{"first"}) {
5413 if ($block->{"ordered"}) {
5414 $tag = "orderedlist";
5416 $output .= "<$tag>\n";
5419 if ($block->{"interrupted"}) {
5420 push @{$block->{"lines"}}, "";
5423 $text = &MarkDownParseLines ($block->{"lines"}, $symbol, "li");
5424 $output .= "<listitem>".$text."</listitem>\n";
5425 if ($block->{"last"}) {
5426 if ($block->{"ordered"}) {
5427 $tag = "orderedlist";
5429 $output .= "</$tag>\n";
5431 } elsif ($block->{"type"} eq "quote") {
5432 $text = &MarkDownParseLines ($block->{"lines"}, $symbol, "quote");
5433 $output .= "<blockquote>\n$text</blockquote>\n";
5434 } elsif ($block->{"type"} eq "code") {
5435 if ($block->{"language"}) {
5436 $output .= "<informalexample><programlisting language=\"" . $block->{"language"} . "\"><![CDATA[\n";
5438 $output .= "<informalexample><programlisting><![CDATA[\n";
5440 foreach (@{$block->{"lines"}}) {
5441 $output .= &ReplaceEntities ($_, $symbol) . "\n";
5443 $output .= "]]></programlisting></informalexample>\n";
5444 } elsif ($block->{"type"} eq "markup") {
5445 $text = &ExpandAbbreviations($symbol, $block->{"text"});
5446 $output .= $text."\n";
5448 $output .= $block->{"text"}."\n";
5450 #$output .= "\n<!-- end type='" . $block->{"type"} . "'-->\n";
5456 sub MarkDownParseLines {
5457 my ($linesref, $symbol, $context) = @_;
5459 my @lines = @$linesref;
5462 @blocks = &MarkDownParseBlocks (\@lines, $symbol, $context);
5463 $output = &MarkDownOutputDocBook (\@blocks, $symbol, $context);
5469 my ($text, $symbol) = @_;
5472 # take out some variability in line endings
5473 $text =~ s%\r\n%\n%g;
5477 @lines = split("\n", $text);
5478 $text = MarkDownParseLines(\@lines, $symbol, "");
5483 #############################################################################
5484 # LIBRARY FUNCTIONS - These functions are used in both gtkdoc-mkdb and
5485 # gtkdoc-mktmpl and should eventually be moved to a
5487 #############################################################################
5489 #############################################################################
5490 # Function : ReadDeclarationsFile
5491 # Description : This reads in a file containing the function/macro/enum etc.
5494 # Note that in some cases there are several declarations with
5495 # the same name, e.g. for conditional macros. In this case we
5496 # set a flag in the %DeclarationConditional hash so the
5497 # declaration is not shown in the docs.
5499 # If a macro and a function have the same name, e.g. for
5500 # gtk_object_ref, the function declaration takes precedence.
5502 # Some opaque structs are just declared with 'typedef struct
5503 # _name name;' in which case the declaration may be empty.
5504 # The structure may have been found later in the header, so
5505 # that overrides the empty declaration.
5507 # Arguments : $file - the declarations file to read
5508 # $override - if declarations in this file should override
5509 # any current declaration.
5510 #############################################################################
5512 sub ReadDeclarationsFile {
5513 my ($file, $override) = @_;
5515 if ($override == 0) {
5517 %DeclarationTypes = ();
5518 %DeclarationConditional = ();
5519 %DeclarationOutput = ();
5523 || die "Can't open $file: $!";
5524 my $declaration_type = "";
5525 my $declaration_name;
5527 my $is_deprecated = 0;
5529 if (!$declaration_type) {
5530 if (m/^<([^>]+)>/) {
5531 $declaration_type = $1;
5532 $declaration_name = "";
5533 @TRACE@("Found declaration: $declaration_type\n");
5537 if (m%^<NAME>(.*)</NAME>%) {
5538 $declaration_name = $1;
5539 } elsif (m%^<DEPRECATED/>%) {
5541 } elsif (m%^</$declaration_type>%) {
5542 @TRACE@("Found end of declaration: $declaration_name\n");
5543 # Check that the declaration has a name
5544 if ($declaration_name eq "") {
5545 &LogWarning ($file, $., "$declaration_type has no name.\n");
5548 # If the declaration is an empty typedef struct _XXX XXX
5549 # set the flag to indicate the struct has a typedef.
5550 if (($declaration_type eq 'STRUCT' || $declaration_type eq 'UNION')
5551 && $declaration =~ m/^\s*$/) {
5552 @TRACE@("Struct has typedef: $declaration_name\n");
5553 $StructHasTypedef{$declaration_name} = 1;
5556 # Check if the symbol is already defined.
5557 if (defined ($Declarations{$declaration_name})
5558 && $override == 0) {
5559 # Function declarations take precedence.
5560 if ($DeclarationTypes{$declaration_name} eq 'FUNCTION') {
5562 } elsif ($declaration_type eq 'FUNCTION') {
5563 if ($is_deprecated) {
5564 $Deprecated{$declaration_name} = "";
5566 $Declarations{$declaration_name} = $declaration;
5567 $DeclarationTypes{$declaration_name} = $declaration_type;
5568 } elsif ($DeclarationTypes{$declaration_name}
5569 eq $declaration_type) {
5570 # If the existing declaration is empty, or is just a
5571 # forward declaration of a struct, override it.
5572 if ($declaration_type eq 'STRUCT' || $declaration_type eq 'UNION') {
5573 if ($Declarations{$declaration_name} =~ m/^\s*((struct|union)\s+\w+\s*;)?\s*$/) {
5574 if ($is_deprecated) {
5575 $Deprecated{$declaration_name} = "";
5577 $Declarations{$declaration_name} = $declaration;
5578 } elsif ($declaration =~ m/^\s*((struct|union)\s+\w+\s*;)?\s*$/) {
5579 # Ignore an empty or forward declaration.
5581 &LogWarning ($file, $., "Structure $declaration_name has multiple definitions.");
5584 # set flag in %DeclarationConditional hash for
5585 # multiply defined macros/typedefs.
5586 $DeclarationConditional{$declaration_name} = 1;
5589 &LogWarning ($file, $., "$declaration_name has multiple definitions.");
5592 if ($is_deprecated) {
5593 $Deprecated{$declaration_name} = "";
5595 $Declarations{$declaration_name} = $declaration;
5596 $DeclarationTypes{$declaration_name} = $declaration_type;
5599 $declaration_type = "";
5610 #############################################################################
5611 # Function : ReadSignalsFile
5612 # Description : This reads in an existing file which contains information on
5613 # all GTK signals. It creates the arrays @SignalNames and
5614 # @SignalPrototypes containing info on the signals. The first
5615 # line of the SignalPrototype is the return type of the signal
5616 # handler. The remaining lines are the parameters passed to it.
5617 # The last parameter, "gpointer user_data" is always the same
5618 # so is not included.
5619 # Arguments : $file - the file containing the signal handler prototype
5621 #############################################################################
5623 sub ReadSignalsFile {
5631 my $signal_prototype;
5633 # Reset the signal info.
5634 @SignalObjects = ();
5636 @SignalReturns = ();
5638 @SignalPrototypes = ();
5643 if (!open (INPUT, $file)) {
5644 warn "Can't open $file - skipping signals\n";
5651 $signal_object = "";
5653 $signal_returns = "";
5654 $signal_prototype = "";
5657 if (m/^<NAME>(.*)<\/NAME>/) {
5659 if ($signal_name =~ m/^(.*)::(.*)$/) {
5660 $signal_object = $1;
5661 ($signal_name = $2) =~ s/_/-/g;
5662 @TRACE@("Found signal: $signal_name\n");
5664 &LogWarning ($file, $., "Invalid signal name: $signal_name.");
5666 } elsif (m/^<RETURNS>(.*)<\/RETURNS>/) {
5667 $signal_returns = $1;
5668 } elsif (m/^<FLAGS>(.*)<\/FLAGS>/) {
5670 } elsif (m%^</SIGNAL>%) {
5671 @TRACE@("Found end of signal: ${signal_object}::${signal_name}\nReturns: ${signal_returns}\n${signal_prototype}");
5672 push (@SignalObjects, $signal_object);
5673 push (@SignalNames, $signal_name);
5674 push (@SignalReturns, $signal_returns);
5675 push (@SignalFlags, $signal_flags);
5676 push (@SignalPrototypes, $signal_prototype);
5679 $signal_prototype .= $_;
5687 #############################################################################
5688 # Function : ReadTemplateFile
5689 # Description : This reads in the manually-edited documentation file
5690 # corresponding to the file currently being created, so we can
5691 # insert the documentation at the appropriate places.
5692 # It outputs %SymbolTypes, %SymbolDocs and %SymbolParams, which
5693 # is a hash of arrays.
5694 # NOTE: This function is duplicated in gtkdoc-mktmpl (but
5695 # slightly different).
5696 # Arguments : $docsfile - the template file to read in.
5697 # $skip_unused_params - 1 if the unused parameters should be
5699 #############################################################################
5701 sub ReadTemplateFile {
5702 my ($docsfile, $skip_unused_params) = @_;
5704 my $template = "$docsfile.sgml";
5705 if (! -f $template) {
5706 @TRACE@("File doesn't exist: $template\n");
5710 # start with empty hashes, we merge the source comment for each file
5716 my $current_type = ""; # Type of symbol being read.
5717 my $current_symbol = ""; # Name of symbol being read.
5718 my $symbol_doc = ""; # Description of symbol being read.
5719 my @params; # Parameter names and descriptions of current
5720 # function/macro/function typedef.
5721 my $current_param = -1; # Index of parameter currently being read.
5722 # Note that the param array contains pairs
5723 # of param name & description.
5724 my $in_unused_params = 0; # True if we are reading in the unused params.
5725 my $in_deprecated = 0;
5727 my $in_stability = 0;
5729 open (DOCS, "$template")
5730 || die "Can't open $template: $!";
5732 @TRACE@("reading template $template");
5735 if (m/^<!-- ##### ([A-Z_]+) (\S+) ##### -->/) {
5738 if ($symbol eq "Title"
5739 || $symbol eq "Short_Description"
5740 || $symbol eq "Long_Description"
5741 || $symbol eq "See_Also"
5742 || $symbol eq "Stability_Level"
5743 || $symbol eq "Include"
5744 || $symbol eq "Image") {
5746 $symbol = $docsfile . ":" . $symbol;
5749 @TRACE@("Found symbol: $symbol\n");
5750 # Remember file and line for the symbol
5751 $SymbolSourceFile{$symbol} = $template;
5752 $SymbolSourceLine{$symbol} = $.;
5754 # Store previous symbol, but remove any trailing blank lines.
5755 if ($current_symbol ne "") {
5756 $symbol_doc =~ s/\s+$//;
5757 $SymbolTypes{$current_symbol} = $current_type;
5758 $SymbolDocs{$current_symbol} = $symbol_doc;
5760 # Check that the stability level is valid.
5761 if ($StabilityLevel{$current_symbol}) {
5762 $StabilityLevel{$current_symbol} = &ParseStabilityLevel($StabilityLevel{$current_symbol}, $template, $., "Stability level for $current_symbol");
5765 if ($current_param >= 0) {
5766 $SymbolParams{$current_symbol} = [ @params ];
5768 # Delete any existing params in case we are overriding a
5769 # previously read template.
5770 delete $SymbolParams{$current_symbol};
5773 $current_type = $type;
5774 $current_symbol = $symbol;
5775 $current_param = -1;
5776 $in_unused_params = 0;
5783 } elsif (m/^<!-- # Unused Parameters # -->/) {
5784 @TRACE@("Found unused parameters\n");
5785 $in_unused_params = 1;
5788 } elsif ($in_unused_params && $skip_unused_params) {
5789 # When outputting the DocBook we skip unused parameters.
5790 @TRACE@("Skipping unused param: $_");
5794 # Check if param found. Need to handle "..." and "format...".
5795 if (s/^\@([\w\.]+):\040?//) {
5796 my $param_name = $1;
5797 my $param_desc = $_;
5798 # Allow variations of 'Returns'
5799 if ($param_name =~ m/^[Rr]eturns?$/) {
5800 $param_name = "Returns";
5802 # Allow varargs variations
5803 if ($param_name =~ m/^.*\.\.\.$/) {
5804 $param_name = "...";
5807 # strip trailing whitespaces and blank lines
5810 @TRACE@("Found param for symbol $current_symbol : '$param_name'= '$_'");
5812 if ($param_name eq "Deprecated") {
5814 $Deprecated{$current_symbol} = $_;
5815 } elsif ($param_name eq "Since") {
5818 $Since{$current_symbol} = $_;
5819 } elsif ($param_name eq "Stability") {
5821 $StabilityLevel{$current_symbol} = $_;
5823 push (@params, $param_name);
5824 push (@params, $param_desc);
5825 $current_param += $PARAM_FIELD_COUNT;
5828 # strip trailing whitespaces and blank lines
5833 if ($in_deprecated) {
5834 $Deprecated{$current_symbol} .= $_;
5835 } elsif ($in_since) {
5836 &LogWarning ($template, $., "multi-line since docs found");
5837 #$Since{$current_symbol} .= $_;
5838 } elsif ($in_stability) {
5839 $StabilityLevel{$current_symbol} .= $_;
5840 } elsif ($current_param >= 0) {
5841 $params[$current_param] .= $_;
5850 # Remember to finish the current symbol doccs.
5851 if ($current_symbol ne "") {
5853 $symbol_doc =~ s/\s+$//;
5854 $SymbolTypes{$current_symbol} = $current_type;
5855 $SymbolDocs{$current_symbol} = $symbol_doc;
5857 # Check that the stability level is valid.
5858 if ($StabilityLevel{$current_symbol}) {
5859 $StabilityLevel{$current_symbol} = &ParseStabilityLevel($StabilityLevel{$current_symbol}, $template, $., "Stability level for $current_symbol");
5862 if ($current_param >= 0) {
5863 $SymbolParams{$current_symbol} = [ @params ];
5865 # Delete any existing params in case we are overriding a
5866 # previously read template.
5867 delete $SymbolParams{$current_symbol};
5876 #############################################################################
5877 # Function : ReadObjectHierarchy
5878 # Description : This reads in the $MODULE-hierarchy.txt file containing all
5879 # the GtkObject subclasses described in this module (and their
5881 # It places them in the @Objects array, and places their level
5882 # in the object hierarchy in the @ObjectLevels array, at the
5883 # same index. GtkObject, the root object, has a level of 1.
5885 # This also generates tree_index.sgml as it goes along.
5888 #############################################################################
5890 sub ReadObjectHierarchy {
5894 if (! -f $OBJECT_TREE_FILE) {
5897 if (!open (INPUT, $OBJECT_TREE_FILE)) {
5898 warn "Can't open $OBJECT_TREE_FILE - skipping object tree\n";
5902 # Only emit objects if they are supposed to be documented, or if
5903 # they have documented children. To implement this, we maintain a
5904 # stack of pending objects which will be emitted if a documented
5906 my @pending_objects = ();
5907 my @pending_levels = ();
5913 my $level = (length($`)) / 2 + 1;
5920 while (($#pending_levels >= 0) && ($pending_levels[$#pending_levels] >= $level)) {
5921 my $pobject = pop(@pending_objects);
5922 my $plevel = pop(@pending_levels);
5925 push (@pending_objects, $object);
5926 push (@pending_levels, $level);
5928 if (exists($KnownSymbols{$object})) {
5929 while ($#pending_levels >= 0) {
5930 $object = shift @pending_objects;
5931 $level = shift @pending_levels;
5932 $xref = &MakeXRef ($object);
5934 push (@tree, ' ' x ($level * 4) . "$xref");
5935 push (@Objects, $object);
5936 push (@ObjectLevels, $level);
5937 $ObjectRoots{$object} = $root;
5941 # LogWarning ($OBJECT_TREE_FILE, $., "unknown type $object");
5948 # my $old_tree_index = "$DB_OUTPUT_DIR/tree_index.$xml";
5949 my $old_tree_index = "$DB_OUTPUT_DIR/tree_index.sgml";
5950 my $new_tree_index = "$DB_OUTPUT_DIR/tree_index.new";
5952 open (OUTPUT, ">$new_tree_index")
5953 || die "Can't create $new_tree_index: $!";
5955 print (OUTPUT &MakeDocHeader ("screen")."\n<screen>\n".&AddTreeLineArt(\@tree)."\n</screen>\n");
5958 &UpdateFileIfChanged ($old_tree_index, $new_tree_index, 0);
5963 #############################################################################
5964 # Function : ReadInterfaces
5965 # Description : This reads in the $MODULE.interfaces file.
5968 #############################################################################
5970 sub ReadInterfaces {
5973 if (! -f $INTERFACES_FILE) {
5976 if (!open (INPUT, $INTERFACES_FILE)) {
5977 warn "Can't open $INTERFACES_FILE - skipping interfaces\n";
5983 my ($object, @ifaces) = split;
5984 if (exists($KnownSymbols{$object}) && $KnownSymbols{$object} == 1) {
5985 my @knownIfaces = ();
5987 # filter out private interfaces, but leave foreign interfaces
5988 foreach my $iface (@ifaces) {
5989 if (!exists($KnownSymbols{$iface}) || $KnownSymbols{$iface} == 1) {
5990 push (@knownIfaces, $iface);
5994 $Interfaces{$object} = join(' ', @knownIfaces);
5995 @TRACE@("Interfaces for $object: $Interfaces{$object}\n");
5997 @TRACE@("skipping interfaces for unknown symbol: $object\n");
6003 #############################################################################
6004 # Function : ReadPrerequisites
6005 # Description : This reads in the $MODULE.prerequisites file.
6008 #############################################################################
6010 sub ReadPrerequisites {
6011 %Prerequisites = ();
6013 if (! -f $PREREQUISITES_FILE) {
6016 if (!open (INPUT, $PREREQUISITES_FILE)) {
6017 warn "Can't open $PREREQUISITES_FILE - skipping prerequisites\n";
6023 my ($iface, @prereqs) = split;
6024 if (exists($KnownSymbols{$iface}) && $KnownSymbols{$iface} == 1) {
6025 my @knownPrereqs = ();
6027 # filter out private prerequisites, but leave foreign prerequisites
6028 foreach my $prereq (@prereqs) {
6029 if (!exists($KnownSymbols{$prereq}) || $KnownSymbols{$prereq} == 1) {
6030 push (@knownPrereqs, $prereq);
6034 $Prerequisites{$iface} = join(' ', @knownPrereqs);
6040 #############################################################################
6041 # Function : ReadArgsFile
6042 # Description : This reads in an existing file which contains information on
6043 # all GTK args. It creates the arrays @ArgObjects, @ArgNames,
6044 # @ArgTypes, @ArgFlags, @ArgNicks and @ArgBlurbs containing info
6046 # Arguments : $file - the file containing the arg information.
6047 #############################################################################
6062 # Reset the args info.
6075 if (!open (INPUT, $file)) {
6076 warn "Can't open $file - skipping args\n";
6093 if (m/^<NAME>(.*)<\/NAME>/) {
6095 if ($arg_name =~ m/^(.*)::(.*)$/) {
6097 ($arg_name = $2) =~ s/_/-/g;
6098 @TRACE@("Found arg: $arg_name\n");
6100 &LogWarning ($file, $., "Invalid argument name: $arg_name");
6102 } elsif (m/^<TYPE>(.*)<\/TYPE>/) {
6104 } elsif (m/^<RANGE>(.*)<\/RANGE>/) {
6106 } elsif (m/^<FLAGS>(.*)<\/FLAGS>/) {
6108 } elsif (m/^<NICK>(.*)<\/NICK>/) {
6110 } elsif (m/^<BLURB>(.*)<\/BLURB>/) {
6112 if ($arg_blurb eq "(null)") {
6114 &LogWarning ($file, $., "Property ${arg_object}:${arg_name} has no documentation.");
6116 } elsif (m/^<DEFAULT>(.*)<\/DEFAULT>/) {
6118 } elsif (m%^</ARG>%) {
6119 @TRACE@("Found end of arg: ${arg_object}::${arg_name}\n${arg_type} : ${arg_flags}\n");
6120 push (@ArgObjects, $arg_object);
6121 push (@ArgNames, $arg_name);
6122 push (@ArgTypes, $arg_type);
6123 push (@ArgRanges, $arg_range);
6124 push (@ArgFlags, $arg_flags);
6125 push (@ArgNicks, $arg_nick);
6126 push (@ArgBlurbs, $arg_blurb);
6127 push (@ArgDefaults, $arg_default);
6135 #############################################################################
6136 # Function : AddTreeLineArt
6137 # Description : Add unicode lineart to a pre-indented string array and returns
6138 # it as as multiline string.
6139 # Arguments : @tree - array of indented strings.
6140 #############################################################################
6142 sub AddTreeLineArt {
6143 my @tree = @{$_[0]};
6148 # iterate bottom up over the tree
6149 for ($i = $#tree; $i >= 0; $i--) {
6150 # count leading spaces
6151 $tree[$i] =~ /^([^<A-Za-z]*)/;
6152 $indent = length( $1 );
6153 # replace with ╰───, if place of ╰ is not space insert ├
6155 if (substr($tree[$i],$indent-4,1) eq " ") {
6156 substr($tree[$i],$indent-4,4) = "--- ";
6158 substr($tree[$i],$indent-4,4) = "+-- ";
6160 # go lines up while space and insert |
6161 for ($j = $i - 1; ($j >= 0 && substr($tree[$j],$indent-4,1) eq ' '); $j--) {
6162 substr($tree[$j],$indent-4,1) = '|';
6167 my $res = join("\n", @tree);
6168 # unicode chars for: ╰──
6169 $res =~ s%---%<phrase role=\"lineart\">╰──</phrase>%g;
6170 # unicde chars for: ├──
6171 $res =~ s%\+--%<phrase role=\"lineart\">├──</phrase>%g;
6172 # unicode char for: │
6173 $res =~ s%\|%<phrase role=\"lineart\">│</phrase>%g;
6179 #############################################################################
6180 # Function : CheckIsObject
6181 # Description : Returns 1 if the given name is a GObject or a subclass.
6182 # It uses the global @Objects array.
6183 # Note that the @Objects array only contains classes in the
6184 # current module and their ancestors - not all GObject classes.
6185 # Arguments : $name - the name to check.
6186 #############################################################################
6190 my $root = $ObjectRoots{$name};
6191 # Let GBoxed pass as an object here to get -struct appended to the id
6192 # and prevent conflicts with sections.
6193 return (defined($root) and $root ne 'GEnum' and $root ne 'GFlags');
6197 #############################################################################
6198 # Function : MakeReturnField
6199 # Description : Pads a string to $RETURN_TYPE_FIELD_WIDTH.
6200 # Arguments : $str - the string to pad.
6201 #############################################################################
6203 sub MakeReturnField {
6206 return $str . (' ' x ($RETURN_TYPE_FIELD_WIDTH - length ($str)));
6209 #############################################################################
6210 # Function : GetSymbolSourceFile
6211 # Description : Get the filename where the symbol docs where taken from.
6212 # Arguments : $symbol - the symbol name
6213 #############################################################################
6215 sub GetSymbolSourceFile {
6218 if (defined($SourceSymbolSourceFile{$symbol})) {
6219 return $SourceSymbolSourceFile{$symbol};
6220 } elsif (defined($SymbolSourceFile{$symbol})) {
6221 return $SymbolSourceFile{$symbol};
6227 #############################################################################
6228 # Function : GetSymbolSourceLine
6229 # Description : Get the file line where the symbol docs where taken from.
6230 # Arguments : $symbol - the symbol name
6231 #############################################################################
6233 sub GetSymbolSourceLine {
6236 if (defined($SourceSymbolSourceLine{$symbol})) {
6237 return $SourceSymbolSourceLine{$symbol};
6238 } elsif (defined($SymbolSourceLine{$symbol})) {
6239 return $SymbolSourceLine{$symbol};