mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 01:00:37 +00:00
9bae9d4b91
Original commit message from CVS: More Docs updates. Added plugin documentation. I fear we need a gstdoc implementation that loads plugins and does introspection on them. I think we should automatically create the docs for the pads and mime types the plugins provide. Does anyone have enough perl knowledge to add these features? I allready changed the C code to output the pad definitions but my perl knowledge is too limited, for now, to implement the rest of the needed functionality...
2273 lines
68 KiB
Perl
Executable file
2273 lines
68 KiB
Perl
Executable file
#!/usr/bin/perl -w
|
|
#
|
|
# gtk-doc - GTK DocBook documentation generator.
|
|
# Copyright (C) 1998 Damon Chaplin
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
#
|
|
|
|
#############################################################################
|
|
# Script : gtkdoc-mkdb
|
|
# Description : This creates the DocBook files from the edited templates.
|
|
#
|
|
# NOTE: When creating SGML IDS, we append -CAPS to all
|
|
# all-caps identifiers to prevent name clashes. (It basically
|
|
# never is the case that mixed-case identifiers would collide.)
|
|
# See the CreateValidSGMLID function.
|
|
#############################################################################
|
|
|
|
use strict;
|
|
use Getopt::Long;
|
|
|
|
# Options
|
|
|
|
# name of documentation module
|
|
my $MODULE;
|
|
my $TMPL_DIR;
|
|
my $SGML_OUTPUT_DIR;
|
|
my @SOURCE_DIRS;
|
|
|
|
my %optctl = (module => \$MODULE,
|
|
'source-dir' => \@SOURCE_DIRS,
|
|
'output-dir' => \$SGML_OUTPUT_DIR,
|
|
'tmpl-dir' => \$TMPL_DIR);
|
|
GetOptions(\%optctl, "module=s", "source-dir:s", "output-dir:s");
|
|
|
|
my $ROOT_DIR = ".";
|
|
|
|
# All the files are written in subdirectories beneath here.
|
|
$TMPL_DIR = $TMPL_DIR ? $TMPL_DIR : "$ROOT_DIR/tmpl";
|
|
|
|
# This is where we put all the DocBook output.
|
|
$SGML_OUTPUT_DIR = $SGML_OUTPUT_DIR ? $SGML_OUTPUT_DIR : "$ROOT_DIR/sgml";
|
|
|
|
# This file contains the object hierarchy.
|
|
my $OBJECT_TREE_FILE = "$ROOT_DIR/$MODULE.hierarchy";
|
|
|
|
# This file contains signal arguments and names.
|
|
my $SIGNALS_FILE = "$ROOT_DIR/$MODULE.signals";
|
|
|
|
# The file containing Arg information.
|
|
my $ARGS_FILE = "$ROOT_DIR/$MODULE.args";
|
|
|
|
# These global arrays store information on signals. Each signal has an entry
|
|
# in each of these arrays at the same index, like a multi-dimensional array.
|
|
my @SignalObjects; # The GtkObject which emits the signal.
|
|
my @SignalNames; # The signal name.
|
|
my @SignalReturns; # The return type.
|
|
my @SignalPrototypes; # The rest of the prototype of the signal handler.
|
|
|
|
# These global arrays store information on Args. Each Arg has an entry
|
|
# in each of these arrays at the same index, like a multi-dimensional array.
|
|
my @ArgObjects; # The GtkObject which has the Arg.
|
|
my @ArgNames; # The Arg name.
|
|
my @ArgTypes; # The Arg type - gint, GtkArrowType etc.
|
|
my @ArgFlags; # How the Arg can be used - readable/writable etc.
|
|
|
|
# These global hashes store declaration info keyed on a symbol name.
|
|
my %Declarations;
|
|
my %DeclarationTypes;
|
|
my %DeclarationConditional;
|
|
my %DeclarationOutput;
|
|
|
|
# These global hashes store the existing documentation.
|
|
my %SymbolDocs;
|
|
my %SymbolTypes;
|
|
my %SymbolParams;
|
|
|
|
# These global hashes store documentation scanned from the source files.
|
|
my %SourceSymbolDocs;
|
|
my %SourceSymbolParams;
|
|
|
|
# These global arrays store GtkObject and subclasses and the hierarchy.
|
|
my @Objects;
|
|
my @ObjectLevels;
|
|
|
|
|
|
# Create the root DocBook output directory if it doens't exist.
|
|
if (! -e $SGML_OUTPUT_DIR) {
|
|
mkdir ("$SGML_OUTPUT_DIR", 0777)
|
|
|| die "Can't create directory: $SGML_OUTPUT_DIR";
|
|
}
|
|
|
|
# Function and other declaration output settings.
|
|
my $RETURN_TYPE_FIELD_WIDTH = 12;
|
|
my $SYMBOL_FIELD_WIDTH = 32;
|
|
my $SIGNAL_FIELD_WIDTH = 12;
|
|
|
|
&ReadSignalsFile ($SIGNALS_FILE);
|
|
&ReadArgsFile ($ARGS_FILE);
|
|
&ReadObjectHierarchy;
|
|
|
|
# FIXME: this is the header file output at the top of the Synopsis.
|
|
# We should allow this to be changed in the MODULE-sections.txt file.
|
|
# gnome.h includes gtk/gtk.h which includes gdk/gdk.h which includes glib.h
|
|
# so what should we output? - alternatives?
|
|
my $HEADER_FILE = "";
|
|
if ($MODULE eq 'glib') {
|
|
$HEADER_FILE = "glib.h";
|
|
} elsif ($MODULE eq 'gdk') {
|
|
$HEADER_FILE = "gtk/gdk.h";
|
|
} elsif ($MODULE eq 'gtk') {
|
|
$HEADER_FILE = "gtk/gtk.h";
|
|
} elsif ($MODULE eq 'gnome' || $MODULE eq 'gnomeui') {
|
|
$HEADER_FILE = "gnome.h";
|
|
}
|
|
|
|
for my $dir (@SOURCE_DIRS) {
|
|
&ReadSourceDocumentation ($dir);
|
|
}
|
|
|
|
&OutputSGML ("$ROOT_DIR/$MODULE-sections.txt");
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputObjectList
|
|
# Description : This outputs the alphabetical list of objects, in a columned
|
|
# table. FIXME: Currently this also outputs ancestor objects
|
|
# which may not actually be in this module.
|
|
# Arguments : none
|
|
#############################################################################
|
|
|
|
sub OutputObjectList {
|
|
my $cols = 3;
|
|
|
|
open (OUTPUT, ">$SGML_OUTPUT_DIR/object_index.sgml")
|
|
|| die "Can't create $SGML_OUTPUT_DIR/object_index.sgml";
|
|
print (OUTPUT <<EOF);
|
|
<informaltable pgwide=1 frame="none">
|
|
<tgroup cols="$cols">
|
|
<colspec colwidth="1*">
|
|
<colspec colwidth="1*">
|
|
<colspec colwidth="1*">
|
|
<tbody>
|
|
EOF
|
|
|
|
my $count = 0;
|
|
my $object;
|
|
foreach $object (sort(@Objects)) {
|
|
my $xref = &MakeXRef ($object);
|
|
if ($count % $cols == 0) { print (OUTPUT "<row>\n"); }
|
|
print (OUTPUT "<entry>$xref</entry>\n");
|
|
if ($count % $cols == ($cols - 1)) { print (OUTPUT "</row>\n"); }
|
|
$count++;
|
|
}
|
|
|
|
print (OUTPUT <<EOF);
|
|
</tbody></tgroup></informaltable>
|
|
EOF
|
|
close (OUTPUT);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputSGML
|
|
# Description : This collects the output for each section of the docs, and
|
|
# outputs each file when the end of the section is found.
|
|
# Arguments : $file - the $MODULE-sections.txt file which contains all of
|
|
# the functions/macros/structs etc. being documented, organised
|
|
# into sections and subsections.
|
|
#############################################################################
|
|
|
|
sub OutputSGML {
|
|
my ($file) = @_;
|
|
|
|
open (INPUT, $file)
|
|
|| die "Can't open $file";
|
|
my $book_top = "";
|
|
my $book_bottom = "";
|
|
my $includes = "";
|
|
my $section_includes = "";
|
|
my $in_section = 0;
|
|
my $title = "";
|
|
my $subsection = "";
|
|
my $synopsis;
|
|
my $details;
|
|
my $num_symbols;
|
|
while (<INPUT>) {
|
|
if (m/^#/) {
|
|
next;
|
|
|
|
} elsif (m/^<SECTION>/) {
|
|
$synopsis = "";
|
|
$details = "";
|
|
$num_symbols = 0;
|
|
$in_section = 1;
|
|
|
|
} elsif (m/^<SUBSECTION\s*(.*)>/i) {
|
|
$synopsis .= "\n";
|
|
$subsection = $1;
|
|
|
|
} elsif (m/^<SUBSECTION>/) {
|
|
|
|
} elsif (m/^<TITLE>(.*)<\/TITLE>/) {
|
|
$title = $1;
|
|
# print "Section: $title\n";
|
|
|
|
# We don't want warnings if object & class structs aren't used.
|
|
$DeclarationOutput{$title} = 1;
|
|
$DeclarationOutput{"${title}Class"} = 1;
|
|
|
|
} elsif (m/^<FILE>(.*)<\/FILE>/) {
|
|
$file = $1;
|
|
%SymbolDocs = ();
|
|
%SymbolTypes = ();
|
|
%SymbolParams = ();
|
|
&ReadTemplateFile ("$TMPL_DIR/$file.sgml", 1);
|
|
&MergeSourceDocumentation;
|
|
|
|
} elsif (m/^<INCLUDE>(.*)<\/INCLUDE>/) {
|
|
if ($in_section) {
|
|
$section_includes = $1;
|
|
} else {
|
|
$includes = $1;
|
|
}
|
|
|
|
} elsif (m/^<\/SECTION>/) {
|
|
if ($title eq "") {
|
|
$title = $file;
|
|
}
|
|
# print "End of section: $title\n";
|
|
|
|
$file =~ s/\s/_/g;
|
|
$file .= ".sgml";
|
|
|
|
# GtkObjects use their class name as the ID.
|
|
my $section_id;
|
|
if (&CheckIsObject ($title)) {
|
|
$section_id = &CreateValidSGMLID ($title);
|
|
} else {
|
|
$section_id = &CreateValidSGMLID ("$MODULE-$title");
|
|
}
|
|
|
|
if ($num_symbols > 0) {
|
|
$book_top .= "<!entity $section_id SYSTEM \"sgml/$file\">\n";
|
|
$book_bottom .= " &$section_id;\n";
|
|
|
|
if ($section_includes eq "") {
|
|
$section_includes = $includes;
|
|
}
|
|
|
|
&OutputSGMLFile ($file, $title, $section_id, $section_includes,
|
|
\$synopsis, \$details);
|
|
}
|
|
$title = "";
|
|
$subsection = "";
|
|
$in_section = 0;
|
|
$section_includes = "";
|
|
|
|
} elsif (m/^(\S+)/) {
|
|
my $symbol = $1;
|
|
#print " Symbol: $symbol\n";
|
|
|
|
my $declaration = $Declarations{$1};
|
|
if (defined ($declaration)) {
|
|
# We don't want standard macros/functions of GtkObjects,
|
|
# or private declarations.
|
|
if ($subsection ne "Standard" && $subsection ne "Private") {
|
|
my ($synop, $desc) = &OutputDeclaration ($symbol,
|
|
$declaration);
|
|
$synopsis .= $synop;
|
|
$details .= $desc;
|
|
}
|
|
|
|
# Note that the declaration has been output.
|
|
$DeclarationOutput{$symbol} = 1;
|
|
} else {
|
|
print "WARNING: No declaration for: $1\n";
|
|
}
|
|
$num_symbols++;
|
|
}
|
|
}
|
|
close (INPUT);
|
|
|
|
&OutputBook ($book_top, $book_bottom);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputDeclaration
|
|
# Description : Returns the synopsis and detailed description DocBook
|
|
# describing one function/macro etc.
|
|
# Arguments : $symbol - the name of the function/macro begin described.
|
|
# $declaration - the declaration of the function/macro.
|
|
#############################################################################
|
|
|
|
sub OutputDeclaration {
|
|
my ($symbol, $declaration) = @_;
|
|
|
|
my $type = $DeclarationTypes {$symbol};
|
|
if ($type eq 'MACRO') {
|
|
return &OutputMacro ($symbol, $declaration);
|
|
} elsif ($type eq 'TYPEDEF') {
|
|
return &OutputTypedef ($symbol, $declaration);
|
|
} elsif ($type eq 'STRUCT') {
|
|
return &OutputStruct ($symbol, $declaration);
|
|
} elsif ($type eq 'ENUM') {
|
|
return &OutputEnum ($symbol, $declaration);
|
|
} elsif ($type eq 'UNION') {
|
|
return &OutputUnion ($symbol, $declaration);
|
|
} elsif ($type eq 'VARIABLE') {
|
|
return &OutputVariable ($symbol, $declaration);
|
|
|
|
} elsif ($type eq 'FUNCTION') {
|
|
return &OutputFunction ($symbol, $declaration, $type);
|
|
} elsif ($type eq 'USER_FUNCTION') {
|
|
return &OutputFunction ($symbol, $declaration, $type);
|
|
} else {
|
|
die "Unknown symbol type";
|
|
}
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputMacro
|
|
# Description : Returns the synopsis and detailed description of a macro.
|
|
# Arguments : $symbol - the macro.
|
|
# $declaration - the declaration of the macro.
|
|
#############################################################################
|
|
|
|
sub OutputMacro {
|
|
my ($symbol, $declaration) = @_;
|
|
my $id = &CreateValidSGMLID ($symbol);
|
|
my $synop = "#define <link linkend=\"$id\">$symbol</link>";
|
|
my $desc;
|
|
my $args = "";
|
|
if ($declaration =~ m/^\s*#\s*define\s+\w+(\([^\)]*\))/) {
|
|
$args = $1;
|
|
|
|
if (length ($symbol) < $SYMBOL_FIELD_WIDTH) {
|
|
$synop .= (' ' x ($SYMBOL_FIELD_WIDTH - length ($symbol)));
|
|
}
|
|
|
|
$synop .= &CreateValidSGML ($args);
|
|
}
|
|
$synop .= "\n";
|
|
|
|
if ($args ne "") {
|
|
$desc = "<refsect2>\n<title><anchor id=\"$id\">${symbol}()</title>\n";
|
|
} else {
|
|
$desc = "<refsect2>\n<title><anchor id=\"$id\">$symbol</title>\n";
|
|
}
|
|
# Don't output the macro definition if is is a conditional macro or it
|
|
# looks like a function, i.e. starts with "g_" or "_?gnome_", or it is
|
|
# longer than 2 lines, otherwise we get lots of complicated macros like
|
|
# g_assert.
|
|
if (!defined ($DeclarationConditional{$symbol}) && ($symbol !~ m/^g_/)
|
|
&& ($symbol !~ m/^_?gnome_/) && (($declaration =~ tr/\n//) < 2)) {
|
|
$declaration = &CreateValidSGML ($declaration);
|
|
$desc .= "<programlisting>$declaration</programlisting>\n";
|
|
} else {
|
|
$desc .= "<programlisting>#define $symbol";
|
|
$desc .= &CreateValidSGML ($args);
|
|
$desc .= "</programlisting>\n";
|
|
}
|
|
if (defined ($SymbolDocs{$symbol})) {
|
|
$desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
|
|
}
|
|
$desc .= &OutputParamDescriptions ("MACRO", $symbol);
|
|
$desc .= "</refsect2>\n";
|
|
return ($synop, $desc);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputTypedef
|
|
# Description : Returns the synopsis and detailed description of a typedef.
|
|
# Arguments : $symbol - the typedef.
|
|
# $declaration - the declaration of the typedef,
|
|
# e.g. 'typedef unsigned int guint;'
|
|
#############################################################################
|
|
|
|
sub OutputTypedef {
|
|
my ($symbol, $declaration) = @_;
|
|
my $id = &CreateValidSGMLID ($symbol);
|
|
my $synop = "typedef <link linkend=\"$id\">$symbol</link>;\n";
|
|
my $desc = "<refsect2>\n<title><anchor id=\"$id\">$symbol</title>\n";
|
|
if (!defined ($DeclarationConditional{$symbol})) {
|
|
$declaration = &CreateValidSGML ($declaration);
|
|
$desc .= "<programlisting>$declaration</programlisting>\n";
|
|
}
|
|
if (defined ($SymbolDocs{$symbol})) {
|
|
$desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
|
|
}
|
|
$desc .= "</refsect2>\n";
|
|
return ($synop, $desc);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputStruct
|
|
# Description : Returns the synopsis and detailed description of a struct.
|
|
# We check if it is a widget struct, and if so we only output
|
|
# parts of it that are noted as public fields.
|
|
# We also use a different SGML ID for widget structs, since the
|
|
# original ID is used for the entire RefEntry.
|
|
# Arguments : $symbol - the struct.
|
|
# $declaration - the declaration of the struct.
|
|
#############################################################################
|
|
|
|
sub OutputStruct {
|
|
my ($symbol, $declaration) = @_;
|
|
|
|
my $is_widget_struct = 0;
|
|
if (&CheckIsObject ($symbol)) {
|
|
# print "Found widget struct: $symbol\n";
|
|
$is_widget_struct = 1;
|
|
}
|
|
|
|
my $id;
|
|
if ($is_widget_struct) {
|
|
$id = &CreateValidSGMLID ($symbol . "_struct");
|
|
} else {
|
|
$id = &CreateValidSGMLID ($symbol);
|
|
}
|
|
my $synop = "struct <link linkend=\"$id\">$symbol</link>;\n";
|
|
my $desc = "<refsect2>\n<title><anchor id=\"$id\">struct $symbol</title>\n";
|
|
|
|
# Form a pretty-printed, private-data-removed form of the declaration
|
|
|
|
my $decl_out;
|
|
if ($declaration =~ m/^\s*$/) {
|
|
# print "Found opaque struct\n";
|
|
$decl_out = "struct $symbol;";
|
|
} elsif ($is_widget_struct) {
|
|
my $public = 0;
|
|
my $new_declaration = "";
|
|
my $decl_line;
|
|
foreach $decl_line (split (/\n/, $declaration)) {
|
|
# print "Struct line: $decl_line\n";
|
|
if ($decl_line =~ m%/\*\s*<\s*public\s*>\s*\*/%) {
|
|
$public = 1;
|
|
} elsif ($decl_line =~ m%/\*\s*<\s*private\s*>\s*\*/%) {
|
|
$public = 0;
|
|
} elsif ($public) {
|
|
$new_declaration .= $decl_line . "\n";
|
|
}
|
|
}
|
|
if ($new_declaration) {
|
|
$decl_out = "struct $symbol {\n" . $new_declaration;
|
|
# If we finished with public set, we already have the struct end.
|
|
if ($public == 0) {
|
|
$decl_out .= "};\n";
|
|
}
|
|
} else {
|
|
$decl_out = "struct $symbol;";
|
|
}
|
|
} else {
|
|
$decl_out = $declaration;
|
|
}
|
|
|
|
$decl_out = &CreateValidSGML ($decl_out);
|
|
$desc .= "<programlisting>$decl_out</programlisting>\n";
|
|
if (defined ($SymbolDocs{$symbol})) {
|
|
$desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
|
|
}
|
|
|
|
# Create a table of fields and descriptions
|
|
|
|
# FIXME: Inserting  's into the produced type declarations here would
|
|
# improve the output in most situations ... except for function
|
|
# members of structs!
|
|
my @fields = ParseStructDeclaration($declaration, $is_widget_struct, \&MakeXRef,
|
|
sub {
|
|
"<structfield>$_[0]</structfield>";
|
|
});
|
|
my $params = $SymbolParams{$symbol};
|
|
|
|
# If no parameters are filled in, we don't generate the description
|
|
# table, for backwards compatibility
|
|
|
|
my $found = 0;
|
|
if (defined $params) {
|
|
for (my $i = 1; $i <= $#$params; $i += 2) {
|
|
if ($params->[$i] =~ /\S/) {
|
|
$found = 1;
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($found) {
|
|
my %field_descrs = @$params;
|
|
|
|
$desc .= <<EOF;
|
|
<informaltable pgwide=1 frame="none" role="struct">
|
|
<tgroup cols="2">
|
|
<colspec colwidth="2*">
|
|
<colspec colwidth="8*">
|
|
<tbody>
|
|
EOF
|
|
while (@fields) {
|
|
my $field_name = shift @fields;
|
|
my $text = shift @fields;
|
|
my $field_descr = $field_descrs{$field_name};
|
|
|
|
$desc .= "<row>\n<entry>$text</entry>\n";
|
|
if (defined $field_descr) {
|
|
$desc .= "<entry>".&ExpandAbbreviations($field_descr)."</entry>\n";
|
|
} else {
|
|
$desc .= "<entry></entry>\n";
|
|
}
|
|
$desc .= "</row>\n";
|
|
}
|
|
|
|
$desc .= "</tbody></tgroup></informaltable>";
|
|
}
|
|
$desc .= "</refsect2>\n";
|
|
return ($synop, $desc);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputEnum
|
|
# Description : Returns the synopsis and detailed description of a enum.
|
|
# Arguments : $symbol - the enum.
|
|
# $declaration - the declaration of the enum.
|
|
#############################################################################
|
|
|
|
sub OutputEnum {
|
|
my ($symbol, $declaration) = @_;
|
|
my $id = &CreateValidSGMLID ($symbol);
|
|
my $synop = "enum <link linkend=\"$id\">$symbol</link>;\n";
|
|
my $desc = "<refsect2>\n<title><anchor id=\"$id\">enum $symbol</title>\n";
|
|
$declaration = &CreateValidSGML ($declaration);
|
|
$desc .= "<programlisting>$declaration</programlisting>\n";
|
|
if (defined ($SymbolDocs{$symbol})) {
|
|
$desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
|
|
}
|
|
|
|
# Create a table of fields and descriptions
|
|
|
|
my @members = ParseEnumDeclaration($declaration);
|
|
my $params = $SymbolParams{$symbol};
|
|
|
|
# If no parameters are filled in, we don't generate the description
|
|
# table, for backwards compatibility
|
|
|
|
my $found = 0;
|
|
if (defined $params) {
|
|
for (my $i = 1; $i <= $#$params; $i += 2) {
|
|
if ($params->[$i] =~ /\S/) {
|
|
$found = 1;
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($found) {
|
|
my %member_descrs = @$params;
|
|
|
|
$desc .= <<EOF;
|
|
<informaltable pgwide=1 frame="none" role="enum">
|
|
<tgroup cols="2">
|
|
<colspec colwidth="2*">
|
|
<colspec colwidth="8*">
|
|
<tbody>
|
|
EOF
|
|
for my $member_name (@members) {
|
|
my $member_descr = $member_descrs{$member_name};
|
|
|
|
$desc .= "<row>\n<entry><literal>$member_name</literal></entry>\n";
|
|
if (defined $member_descr) {
|
|
$desc .= "<entry>".&ExpandAbbreviations($member_descr)."</entry>\n";
|
|
} else {
|
|
$desc .= "<entry></entry>\n";
|
|
}
|
|
$desc .= "</row>\n";
|
|
}
|
|
|
|
$desc .= "</tbody></tgroup></informaltable>";
|
|
}
|
|
|
|
$desc .= "</refsect2>\n";
|
|
return ($synop, $desc);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputUnion
|
|
# Description : Returns the synopsis and detailed description of a union.
|
|
# Arguments : $symbol - the union.
|
|
# $declaration - the declaration of the union.
|
|
#############################################################################
|
|
|
|
sub OutputUnion {
|
|
my ($symbol, $declaration) = @_;
|
|
my $id = &CreateValidSGMLID ($symbol);
|
|
my $synop = "union <link linkend=\"$id\">$symbol</link>;\n";
|
|
my $desc = "<refsect2>\n<title><anchor id=\"$id\">union $symbol</title>\n";
|
|
$declaration = &CreateValidSGML ($declaration);
|
|
$desc .= "<programlisting>$declaration</programlisting>\n";
|
|
if (defined ($SymbolDocs{$symbol})) {
|
|
$desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
|
|
}
|
|
$desc .= "</refsect2>\n";
|
|
return ($synop, $desc);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputVariable
|
|
# Description : Returns the synopsis and detailed description of a variable.
|
|
# Arguments : $symbol - the extern'ed variable.
|
|
# $declaration - the declaration of the variable.
|
|
#############################################################################
|
|
|
|
sub OutputVariable {
|
|
my ($symbol, $declaration) = @_;
|
|
my $id = &CreateValidSGMLID ($symbol);
|
|
|
|
my $synop;
|
|
if ($declaration =~ m/^\s*extern\s+((const\s+|unsigned\s+)*\w+)(\s+\*+|\*+|\s)(\s*)([A-Za-z]\w*)\s*;/) {
|
|
my $mod = defined ($1) ? $1 : "";
|
|
my $ptr = defined ($3) ? $3 : "";
|
|
my $space = defined ($4) ? $4 : "";
|
|
$synop = "extern $mod$ptr$space<link linkend=\"$id\">$symbol</link>;\n";
|
|
|
|
} else {
|
|
$synop = "extern <link linkend=\"$id\">$symbol</link>;\n";
|
|
}
|
|
|
|
my $desc = "<refsect2>\n<title><anchor id=\"$id\">$symbol</title>\n";
|
|
$declaration = &CreateValidSGML ($declaration);
|
|
$desc .= "<programlisting>$declaration</programlisting>\n";
|
|
if (defined ($SymbolDocs{$symbol})) {
|
|
$desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
|
|
}
|
|
$desc .= "</refsect2>\n";
|
|
return ($synop, $desc);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputFunction
|
|
# Description : Returns the synopsis and detailed description of a function.
|
|
# Arguments : $symbol - the function.
|
|
# $declaration - the declaration of the function.
|
|
#############################################################################
|
|
|
|
sub OutputFunction {
|
|
my ($symbol, $declaration, $symbol_type) = @_;
|
|
my $id = &CreateValidSGMLID ($symbol);
|
|
|
|
# Take out the return type
|
|
$declaration =~ s/<RETURNS>\s*(const\s+|unsigned\s+)*(\w+)\s*(\**)\s*<\/RETURNS>\n//;
|
|
my $type_modifier = defined($1) ? $1 : "";
|
|
my $type = $2;
|
|
my $pointer = $3;
|
|
my $xref = &MakeXRef ($type);
|
|
my $start = "";
|
|
if ($symbol_type eq 'USER_FUNCTION') {
|
|
# $start = "typedef ";
|
|
}
|
|
|
|
my $ret_type_len = length ($start) + length ($type_modifier)
|
|
+ length ($pointer) + length ($type);
|
|
my $ret_type_output;
|
|
my $symbol_len;
|
|
if ($ret_type_len < $RETURN_TYPE_FIELD_WIDTH) {
|
|
$ret_type_output = "$start$type_modifier$xref$pointer"
|
|
. (' ' x ($RETURN_TYPE_FIELD_WIDTH - $ret_type_len));
|
|
$symbol_len = 0;
|
|
} else {
|
|
# $ret_type_output = "$start$type_modifier$xref$pointer\n"
|
|
# . (' ' x $RETURN_TYPE_FIELD_WIDTH);
|
|
|
|
$ret_type_output = "$start$type_modifier$xref$pointer ";
|
|
$symbol_len = $ret_type_len + 1 - $RETURN_TYPE_FIELD_WIDTH;
|
|
}
|
|
|
|
$symbol_len += length ($symbol);
|
|
my $char1 = my $char2 = my $char3 = "";
|
|
if ($symbol_type eq 'USER_FUNCTION') {
|
|
$symbol_len += 3;
|
|
$char1 = "(";
|
|
$char2 = "*";
|
|
$char3 = ")";
|
|
}
|
|
|
|
my ($symbol_output, $symbol_desc_output);
|
|
if ($symbol_len < $SYMBOL_FIELD_WIDTH) {
|
|
$symbol_output = "$char1<link linkend=\"$id\">$char2$symbol</link>$char3"
|
|
. (' ' x ($SYMBOL_FIELD_WIDTH - $symbol_len));
|
|
$symbol_desc_output = "$char1$char2$symbol$char3"
|
|
. (' ' x ($SYMBOL_FIELD_WIDTH - $symbol_len));
|
|
} else {
|
|
$symbol_output = "$char1<link linkend=\"$id\">$char2$symbol</link>$char3\n"
|
|
. (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH));
|
|
$symbol_desc_output = "$char1$char2$symbol$char3\n"
|
|
. (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH));
|
|
}
|
|
|
|
my $synop = $ret_type_output . $symbol_output . '(';
|
|
my $desc = "<refsect2>\n<title><anchor id=\"$id\">${symbol} ()</title>\n";
|
|
$desc .= "<programlisting>${ret_type_output}$symbol_desc_output(";
|
|
|
|
my $param_num = 0;
|
|
while ($declaration ne "") {
|
|
if ($declaration =~ s/^[\s,]+//) {
|
|
# skip whitespace and commas
|
|
next;
|
|
|
|
} elsif ($declaration =~ s/^void\s*[,\n]//) {
|
|
$synop .= "void";
|
|
$desc .= "void";
|
|
|
|
} elsif ($declaration =~ s/^...\s*[,\n]//) {
|
|
if ($param_num == 0) {
|
|
$synop .= "...";
|
|
$desc .= "...";
|
|
} else {
|
|
$synop .= ",\n"
|
|
. (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH))
|
|
. " ...";
|
|
$desc .= ",\n"
|
|
. (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH))
|
|
. " ...";
|
|
}
|
|
|
|
# allow alphanumerics, '_', '[' & ']' in param names
|
|
} elsif ($declaration =~ s/^(const\s+|unsigned\s+)*(struct\s+)?(\w+)\s*(\**)\s*(const\s+)?(\**)?\s*(\w+)?\s*(\[\d*\])?\s*[,\n]//) {
|
|
my $mod1 = defined($1) ? $1 : "";
|
|
if (defined($2)) { $mod1 .= $2; }
|
|
my $type = $3;
|
|
my $ptr1 = $4;
|
|
my $mod2 = defined($5) ? $5 : "";
|
|
my $ptr2 = $6;
|
|
my $name = defined($7) ? $7 : "";
|
|
if ($name) { $ptr1 = " " . $ptr1; }
|
|
my $array = defined($8) ? $8 : "";
|
|
my $xref = &MakeXRef ($type);
|
|
|
|
# print "Type: $mod1$type $ptr1 $mod2 $name $array\n";
|
|
if ($param_num == 0) {
|
|
$synop .= "$mod1$xref$ptr1$mod2$ptr2$name$array";
|
|
$desc .= "$mod1$xref$ptr1$mod2$ptr2$name$array";
|
|
} else {
|
|
$synop .= ",\n"
|
|
. (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH))
|
|
. " $mod1$xref$ptr1$mod2$ptr2$name$array";
|
|
$desc .= ",\n"
|
|
. (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH))
|
|
. " $mod1$xref$ptr1$mod2$ptr2$name$array";
|
|
}
|
|
|
|
# Try to match parameters which are functions.
|
|
} elsif ($declaration =~ s/^(const\s+|unsigned\s+)*(struct\s+)?(\w+)\s*(\**)\s*(const\s+)?\(\s*\*\s*(\w+)\s*\)\s*\(([^)]*)\)\s*[,\n]//) {
|
|
my $mod1 = defined($1) ? $1 : "";
|
|
if (defined($2)) { $mod1 .= $2; }
|
|
my $type = $3;
|
|
my $ptr1 = $4;
|
|
my $mod2 = defined($5) ? $5 : "";
|
|
my $name = $6;
|
|
my $func_params = $7;
|
|
my $xref = &MakeXRef ($type);
|
|
|
|
# print "Type: $mod1$type$ptr1$mod2(*$name)($func_params)\n";
|
|
if ($param_num == 0) {
|
|
$synop .= "$mod1$xref$ptr1$mod2 (*$name) ($func_params)";
|
|
$desc .= "$mod1$xref$ptr1$mod2 (*$name) ($func_params)";
|
|
} else {
|
|
$synop .= ",\n"
|
|
. (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH))
|
|
. " $mod1$xref$ptr1$mod2 (*$name) ($func_params)";
|
|
$desc .= ",\n"
|
|
. (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH))
|
|
. " $mod1$xref$ptr1$mod2 (*$name) ($func_params)";
|
|
}
|
|
|
|
} else {
|
|
print "###Can't parse args for function $symbol: $declaration\n";
|
|
last;
|
|
}
|
|
$param_num++;
|
|
}
|
|
$synop .= ");\n";
|
|
$desc .= ");</programlisting>\n";
|
|
if (defined ($SymbolDocs{$symbol})) {
|
|
$desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
|
|
}
|
|
|
|
$desc .= &OutputParamDescriptions ("FUNCTION", $symbol);
|
|
$desc .= "</refsect2>\n";
|
|
return ($synop, $desc);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputParamDescriptions
|
|
# Description : Returns the DocBook output describing the parameters of a
|
|
# function, macro or signal handler.
|
|
# Arguments : $symbol_type - 'FUNCTION', 'MACRO' or 'SIGNAL'. Signal
|
|
# handlers have an implicit user_data parameter last.
|
|
# $symbol - the name of the function/macro being described.
|
|
#############################################################################
|
|
|
|
sub OutputParamDescriptions {
|
|
my ($symbol_type, $symbol) = @_;
|
|
my $output = "";
|
|
|
|
if (defined ($SymbolParams{$symbol})) {
|
|
my $returns = "";
|
|
my $params = $SymbolParams{$symbol};
|
|
my $params_desc = "";
|
|
if ($#$params < 0) {
|
|
print "WARNING: 0 parameters\n";
|
|
}
|
|
my $j;
|
|
for ($j = 0; $j <= $#$params; $j += 2) {
|
|
my $param_name = $$params[$j];
|
|
my $param = $$params[$j + 1];
|
|
if ($param_name eq "Returns") {
|
|
$returns = &ExpandAbbreviations($param);
|
|
} else {
|
|
if ($param_name eq "Varargs") {
|
|
$param_name = "...";
|
|
}
|
|
$param = &ExpandAbbreviations($param);
|
|
$params_desc .= "<row><entry align=\"right\"><parameter>$param_name</parameter> :</entry>\n<entry>$param</entry></row>\n";
|
|
}
|
|
}
|
|
|
|
# Signals have an implicit user_data parameter which we describe.
|
|
if ($symbol_type eq "SIGNAL") {
|
|
$params_desc .= "<row><entry align=\"right\"><parameter>user_data</parameter> :</entry>\n<entry>user data set when the signal handler was connected.</entry></row>\n";
|
|
}
|
|
|
|
# Start a table if we need one.
|
|
if ($params_desc || $returns) {
|
|
$output .= <<EOF;
|
|
<informaltable pgwide=1 frame="none" role="params">
|
|
<tgroup cols="2">
|
|
<colspec colwidth="2*">
|
|
<colspec colwidth="8*">
|
|
<tbody>
|
|
EOF
|
|
|
|
if ($params_desc ne "") {
|
|
# $output .= "<row><entry>Parameters:</entry></row>\n";
|
|
$output .= $params_desc;
|
|
}
|
|
|
|
# Output the returns info last.
|
|
if ($returns) {
|
|
$output .= "<row><entry align=\"right\"><emphasis>Returns</emphasis> :</entry><entry>$returns</entry></row>\n";
|
|
}
|
|
|
|
# Finish the table.
|
|
$output .= "</tbody></tgroup></informaltable>";
|
|
}
|
|
}
|
|
return $output;
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputSGMLFile
|
|
# Description : Outputs the final DocBook file for one section.
|
|
# Arguments : $file - the name of the file.
|
|
# $title - the title from the $MODULE-sections.txt file, which
|
|
# will be overriden by the title in the template file.
|
|
# $section_id - the SGML id to use for the toplevel tag.
|
|
# $includes - comma-separates list of include files added at top
|
|
# of synopsis, with '<' '>' around them.
|
|
# $synopsis - reference to the DocBook for the Synopsis part.
|
|
# $details - reference to the DocBook for the Details part.
|
|
#############################################################################
|
|
|
|
sub OutputSGMLFile {
|
|
my ($file, $title, $section_id, $includes, $synopsis, $details) = @_;
|
|
|
|
# Find out if this is a GtkObject or descendant.
|
|
my $signals_synop = "";
|
|
my $signals_desc = "";
|
|
my $args_synop = "";
|
|
my $args_desc = "";
|
|
my $hierarchy = "";
|
|
if (&CheckIsObject ($title)) {
|
|
($signals_synop, $signals_desc) = &GetSignals ($title);
|
|
($args_synop, $args_desc) = &GetArgs ($title);
|
|
$hierarchy = &GetHierarchy ($title);
|
|
}
|
|
|
|
# The edited title overrides the one from the sections file.
|
|
my $new_title = $SymbolDocs{"$TMPL_DIR/$file:Title"};
|
|
if (defined ($new_title) && $new_title !~ m/^\s*$/) {
|
|
$title = $new_title;
|
|
# print "Found title: $title\n";
|
|
}
|
|
my $short_desc = $SymbolDocs{"$TMPL_DIR/$file:Short_Description"};
|
|
if (!defined ($short_desc) || $short_desc =~ m/^\s*$/) {
|
|
# $short_desc = "one line description goes here.";
|
|
$short_desc = "";
|
|
} else {
|
|
$short_desc = &ExpandAbbreviations($short_desc);
|
|
# print "Found short_desc: $short_desc";
|
|
}
|
|
my $long_desc = $SymbolDocs{"$TMPL_DIR/$file:Long_Description"};
|
|
if (!defined ($long_desc) || $long_desc =~ m/^\s*$/) {
|
|
$long_desc = "<para>\nA longer description goes here.\n</para>\n";
|
|
} else {
|
|
$long_desc = &ExpandAbbreviations($long_desc);
|
|
# print "Found long_desc: $long_desc";
|
|
}
|
|
my $see_also = $SymbolDocs{"$TMPL_DIR/$file:See_Also"};
|
|
if (!defined ($see_also) || $see_also =~ m%^\s*(<para>)?\s*(</para>)?\s*$%) {
|
|
$see_also = "";
|
|
} else {
|
|
$see_also = &ExpandAbbreviations($see_also);
|
|
# print "Found see_also: $see_also";
|
|
}
|
|
if ($see_also) {
|
|
$see_also = "<refsect1>\n<title>See Also</title>\n$see_also\n</refsect1>\n";
|
|
}
|
|
|
|
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
|
|
gmtime (time);
|
|
my $month = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$mon];
|
|
$year += 1900;
|
|
|
|
my $include_output = "";
|
|
my $include;
|
|
foreach $include (split (/,/, $includes)) {
|
|
$include_output .= "#include <${include}>\n";
|
|
}
|
|
|
|
open (OUTPUT, ">$SGML_OUTPUT_DIR/$file")
|
|
|| die "Can't create $SGML_OUTPUT_DIR/$file";
|
|
|
|
# Note: The refname and refpurpose are on the same line to stop
|
|
# docbook-to-man 1.08 putting them on separate lines.
|
|
print OUTPUT <<EOF;
|
|
<refentry id="$section_id" revision="$mday $month $year">
|
|
<refmeta>
|
|
<refentrytitle>$title</refentrytitle>
|
|
<manvolnum>3</manvolnum>
|
|
<refmiscinfo>\U$MODULE\E Library</refmiscinfo>
|
|
</refmeta>
|
|
|
|
<refnamediv>
|
|
<refname>$title</refname><refpurpose>$short_desc</refpurpose>
|
|
</refnamediv>
|
|
|
|
<refsynopsisdiv><title>Synopsis</title>
|
|
<synopsis>
|
|
|
|
$include_output
|
|
|
|
$${synopsis}</synopsis>
|
|
</refsynopsisdiv>
|
|
|
|
$hierarchy
|
|
$args_synop
|
|
$signals_synop
|
|
|
|
<refsect1>
|
|
<title>Description</title>
|
|
$long_desc
|
|
</refsect1>
|
|
|
|
<refsect1>
|
|
<title>Details</title>
|
|
$$details
|
|
</refsect1>
|
|
$args_desc
|
|
$signals_desc
|
|
|
|
$see_also
|
|
</refentry>
|
|
EOF
|
|
close (OUTPUT);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : OutputBook
|
|
# Description : Outputs the SGML entities that need to be included into the
|
|
# main SGML file for the module.
|
|
# Arguments : $book_top - the declarations of the entities, which are added
|
|
# at the top of the main SGML file.
|
|
# $book_bottom - the references to the entities, which are
|
|
# added in the main SGML file at the desired position.
|
|
#############################################################################
|
|
|
|
sub OutputBook {
|
|
my ($book_top, $book_bottom) = @_;
|
|
|
|
open (OUTPUT, ">$SGML_OUTPUT_DIR/$MODULE-doc.top")
|
|
|| die "Can't create $SGML_OUTPUT_DIR/$MODULE-doc.top";
|
|
print OUTPUT $book_top;
|
|
close (OUTPUT);
|
|
|
|
open (OUTPUT, ">$SGML_OUTPUT_DIR/$MODULE-doc.bottom")
|
|
|| die "Can't create $SGML_OUTPUT_DIR/$MODULE-doc.bottom";
|
|
print OUTPUT $book_bottom;
|
|
close (OUTPUT);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : CreateValidSGMLID
|
|
# Description : Creates a valid SGML 'id' from the given string.
|
|
# NOTE: SGML ids are case-insensitive, so we have a few special
|
|
# cases to avoid clashes of ids.
|
|
# Arguments : $id - the string to be converted into a valid SGML id.
|
|
#############################################################################
|
|
|
|
sub CreateValidSGMLID {
|
|
my ($id) = $_[0];
|
|
|
|
# Append -CAPS to all all-caps identifiers
|
|
|
|
# Special case, '_' would end up as '' so we use 'gettext-macro' instead.
|
|
if ($id eq "_") { return "gettext-macro"; }
|
|
|
|
if ($id !~ /[a-z]/) { $id .= "-CAPS" };
|
|
|
|
$id =~ s/[_ ]/-/g;
|
|
$id =~ s/[,\.]//g;
|
|
$id =~ s/^-*//;
|
|
$id =~ s/::/-/g;
|
|
|
|
return $id;
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : CreateValidSGML
|
|
# Description : This turns any chars which are used in SGML into entities,
|
|
# e.g. '<' into '<'
|
|
# Arguments : $text - the text to turn into proper SGML.
|
|
#############################################################################
|
|
|
|
sub CreateValidSGML {
|
|
my ($text) = @_;
|
|
$text =~ s/&/&/g; # Do this first, or the others get messed up.
|
|
$text =~ s/</</g;
|
|
$text =~ s/>/>/g;
|
|
return $text;
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : ExpandAbbreviations
|
|
# Description : This turns the abbreviations function(), macro(), @param,
|
|
# %constant, and #symbol into appropriate DocBook markup.
|
|
# Arguments : $text - the text to expand.
|
|
#############################################################################
|
|
|
|
sub ExpandAbbreviations {
|
|
my ($text) = @_;
|
|
|
|
# Convert 'function()' or 'macro()'
|
|
$text =~ s/(\w+)\s*\(\)/&MakeXRef($1) . "()";/eg;
|
|
|
|
# Convert '@param'
|
|
$text =~ s/\@(\w+)/<parameter>$1<\/parameter>/g;
|
|
|
|
# Convert '%constant'. Also allow negative numbers, e.g. %-1.
|
|
$text =~ s/\%(-?\w+)/<literal>$1<\/literal>/g;
|
|
|
|
# Convert '#symbol'
|
|
$text =~ s/#([\w-]+)/&MakeXRef($1);/eg;
|
|
|
|
return $text;
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : MakeXRef
|
|
# Description : This returns a cross-reference link to the given symbol.
|
|
# Though it doesn't try to do this for a few standard C types
|
|
# that it knows won't be in the documentation.
|
|
# Arguments : $symbol - the symbol to try to create a XRef to.
|
|
#############################################################################
|
|
|
|
sub MakeXRef {
|
|
my ($symbol) = $_[0];
|
|
# print "Getting type link for $symbol\n";
|
|
|
|
# Don't create a link for some standard C types and functions, to cut
|
|
# down on the number of warnings output by jade.
|
|
if ($symbol eq "void" || $symbol eq "va_list" || $symbol eq "int"
|
|
|| $symbol eq "char" || $symbol eq "printf" || $symbol eq "sprintf") {
|
|
return $symbol;
|
|
}
|
|
|
|
my $symbol_id = &CreateValidSGMLID ($symbol);
|
|
# Get rid of special '-struct' suffix.
|
|
$symbol =~ s/-struct$//;
|
|
return "<link linkend=\"$symbol_id\">$symbol</link>";
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : GetHierarchy
|
|
# Description : Returns the DocBook output describing the ancestors of a
|
|
# GtkObject subclass. It uses the global @Objects and
|
|
# @ObjectLevels arrays to walk up the tree.
|
|
# Arguments : $object - the GtkObject subclass.
|
|
#############################################################################
|
|
|
|
sub GetHierarchy {
|
|
my ($object) = @_;
|
|
|
|
# Find object in the objects array.
|
|
my $found = 0;
|
|
my $i;
|
|
for ($i = 0; $i < @Objects; $i++) {
|
|
if ($Objects[$i] eq $object) {
|
|
$found = 1;
|
|
last;
|
|
}
|
|
}
|
|
if (!$found) {
|
|
return "";
|
|
}
|
|
|
|
# Walk up the hierarchy, pushing ancestors onto the ancestors array.
|
|
my @ancestors = ();
|
|
push (@ancestors, $object);
|
|
my $level = $ObjectLevels[$i];
|
|
# print "Level: $level\n";
|
|
while ($level > 1) {
|
|
$i--;
|
|
if ($ObjectLevels[$i] < $level) {
|
|
push (@ancestors, $Objects[$i]);
|
|
$level = $ObjectLevels[$i];
|
|
# print "Level: $level\n";
|
|
}
|
|
}
|
|
|
|
# Output the ancestors list, indented and with links.
|
|
my $hierarchy = "<synopsis>\n\n";
|
|
$level = 0;
|
|
for ($i = $#ancestors; $i >= 0; $i--) {
|
|
my $link_text;
|
|
# Don't add a link to the current widget, i.e. when i == 0.
|
|
if ($i > 0) {
|
|
my $ancestor_id = &CreateValidSGMLID ($ancestors[$i]);
|
|
$link_text = "<link linkend=\"$ancestor_id\">$ancestors[$i]</link>";
|
|
} else {
|
|
$link_text = "$ancestors[$i]";
|
|
}
|
|
if ($level == 0) {
|
|
$hierarchy .= " $link_text\n";
|
|
} else {
|
|
# $hierarchy .= ' ' x ($level * 6 - 3) . "|\n";
|
|
$hierarchy .= ' ' x ($level * 6 - 3) . "+----$link_text\n";
|
|
}
|
|
$level++;
|
|
}
|
|
$hierarchy .= "</synopsis>\n";
|
|
|
|
return <<EOF;
|
|
<refsect1>
|
|
<title>Object Hierarchy</title>
|
|
$hierarchy
|
|
</refsect1>
|
|
EOF
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : GetSignals
|
|
# Description : Returns the synopsis and detailed description DocBook output
|
|
# for the signal handlers of a given GtkObject subclass.
|
|
# Arguments : $object - the GtkObject subclass, e.g. 'GtkButton'.
|
|
#############################################################################
|
|
|
|
sub GetSignals {
|
|
my ($object) = @_;
|
|
my $synop = "";
|
|
my $desc = "";
|
|
|
|
my $i;
|
|
for ($i = 0; $i <= $#SignalObjects; $i++) {
|
|
if ($SignalObjects[$i] eq $object) {
|
|
# print "Found signal: $SignalNames[$i]\n";
|
|
my $name = $SignalNames[$i];
|
|
my $symbol = "${object}::${name}";
|
|
my $id = &CreateValidSGMLID ("$object-$name");
|
|
|
|
my $name_len = length ($name) + 2;
|
|
if ($name_len < $SIGNAL_FIELD_WIDTH) {
|
|
$synop .= ""<link linkend=\"$id\">$name</link>""
|
|
. (' ' x ($SIGNAL_FIELD_WIDTH - $name_len));
|
|
} else {
|
|
$synop .= ""<link linkend=\"$id\">$name</link>"\n"
|
|
. (' ' x $SIGNAL_FIELD_WIDTH);
|
|
}
|
|
|
|
$desc .= "<refsect2><title><anchor id=\"$id\">The "$name" signal</title>\n";
|
|
$desc .= "<programlisting>";
|
|
|
|
$SignalReturns[$i] =~ m/\s*(const\s*)?(\w+)\s*(\**)/;
|
|
my $type_modifier = defined($1) ? $1 : "";
|
|
my $type = $2;
|
|
my $pointer = $3;
|
|
my $xref = &MakeXRef ($type);
|
|
|
|
my $ret_type_len = length ($type_modifier) + length ($pointer)
|
|
+ length ($type);
|
|
my $ret_type_output = "$type_modifier$xref$pointer"
|
|
. (' ' x ($RETURN_TYPE_FIELD_WIDTH - $ret_type_len));
|
|
|
|
$synop .= "${ret_type_output}user_function (";
|
|
$desc .= "${ret_type_output}user_function (";
|
|
|
|
my @params = split ("\n", $SignalPrototypes[$i]);
|
|
my $j;
|
|
for ($j = 0; $j <= $#params; $j++) {
|
|
# allow alphanumerics, '_', '[' & ']' in param names
|
|
if ($params[$j] =~ m/^\s*(\w+)\s*(\**)\s*([\w\[\]]+)\s*$/) {
|
|
$type = $1;
|
|
$pointer = $2;
|
|
$name = $3;
|
|
$xref = &MakeXRef ($type);
|
|
$synop .= "$xref $pointer$name,\n";
|
|
$synop .= (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH));
|
|
$desc .= "$xref $pointer$name,\n";
|
|
$desc .= (' ' x ($SYMBOL_FIELD_WIDTH + $RETURN_TYPE_FIELD_WIDTH));
|
|
} else {
|
|
print "###Can't parse arg: $params[$j]\nArgs:$SignalPrototypes[$i]\n";
|
|
}
|
|
}
|
|
$xref = &MakeXRef ("gpointer");
|
|
$synop .= "$xref user_data);\n";
|
|
$desc .= "$xref user_data);</programlisting>\n";
|
|
|
|
if (defined ($SymbolDocs{$symbol})) {
|
|
$desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
|
|
}
|
|
|
|
$desc .= &OutputParamDescriptions ("SIGNAL", $symbol);
|
|
$desc .= "</refsect2>";
|
|
}
|
|
}
|
|
if ($synop ne '') {
|
|
$synop = <<EOF;
|
|
<refsect1>
|
|
<title>Signal Prototypes</title>
|
|
<synopsis>
|
|
|
|
${synop}</synopsis>
|
|
</refsect1>
|
|
EOF
|
|
$desc = <<EOF;
|
|
<refsect1>
|
|
<title>Signals</title>
|
|
$desc
|
|
</refsect1>
|
|
EOF
|
|
}
|
|
return ($synop, $desc);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : GetArgs
|
|
# Description : Returns the synopsis and detailed description DocBook output
|
|
# for the Args of a given GtkObject subclass.
|
|
# Arguments : $object - the GtkObject subclass, e.g. 'GtkButton'.
|
|
#############################################################################
|
|
|
|
sub GetArgs {
|
|
my ($object) = @_;
|
|
my $synop = "";
|
|
my $desc = "";
|
|
|
|
my $i;
|
|
for ($i = 0; $i <= $#ArgObjects; $i++) {
|
|
if ($ArgObjects[$i] eq $object) {
|
|
# print "Found arg: $ArgNames[$i]\n";
|
|
my $name = $ArgNames[$i];
|
|
# Remember only one colon so we don't clash with signals.
|
|
my $symbol = "${object}:${name}";
|
|
# I've used two dashes here for the same reason.
|
|
my $id = &CreateValidSGMLID ("$object--$name");
|
|
|
|
my $type = $ArgTypes[$i];
|
|
my $type_output;
|
|
|
|
if ($type eq "GtkSignal") {
|
|
$type = "GtkSignalFunc, gpointer";
|
|
$type_output = &MakeXRef ("GtkSignalFunc") . ", "
|
|
. &MakeXRef ("gpointer");
|
|
} elsif ($type eq "GtkString") {
|
|
$type = "gchar*";
|
|
$type_output = &MakeXRef ("gchar") . "*";
|
|
} else {
|
|
$type_output = &MakeXRef ($type);
|
|
}
|
|
|
|
my $flags = $ArgFlags[$i];
|
|
my $flags_string = "";
|
|
|
|
if ($flags =~ m/r/) {
|
|
$flags_string = "Read";
|
|
}
|
|
if ($flags =~ m/w/) {
|
|
if ($flags_string) { $flags_string .= " / "; }
|
|
$flags_string .= "Write";
|
|
}
|
|
if ($flags =~ m/x/) {
|
|
if ($flags_string) { $flags_string .= " / "; }
|
|
$flags_string .= "Construct";
|
|
}
|
|
if ($flags =~ m/X/) {
|
|
if ($flags_string) { $flags_string .= " / "; }
|
|
$flags_string .= "Construct Only";
|
|
}
|
|
if ($flags =~ m/c/) {
|
|
if ($flags_string) { $flags_string .= " / "; }
|
|
$flags_string .= "Child";
|
|
}
|
|
|
|
my $pad1 = " " x (20 - length ($name));
|
|
my $pad2 = " " x (20 - length ($type));
|
|
$synop .= " "<link linkend=\"$id\">$name</link>"$pad1 $type_output$pad2 : $flags_string\n";
|
|
|
|
$desc .= "<varlistentry><term><anchor id=\"$id\">"<literal>$name</literal>" ($type_output : $flags_string)</term>\n<listitem>\n";
|
|
|
|
if (defined ($SymbolDocs{$symbol})) {
|
|
$desc .= &ExpandAbbreviations($SymbolDocs{$symbol});
|
|
} else {
|
|
$desc .= "<para></para>\n";
|
|
}
|
|
|
|
$desc .= "</listitem></varlistentry>\n";
|
|
}
|
|
}
|
|
if ($synop ne '') {
|
|
$synop = <<EOF;
|
|
<refsect1>
|
|
<title>Args</title>
|
|
<synopsis>
|
|
|
|
${synop}</synopsis>
|
|
</refsect1>
|
|
EOF
|
|
$desc = <<EOF;
|
|
<refsect1>
|
|
<title>Args</title>
|
|
<variablelist>
|
|
$desc
|
|
</variablelist>
|
|
</refsect1>
|
|
EOF
|
|
}
|
|
return ($synop, $desc);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : ReadSourceDocumentation
|
|
# Description : This reads in the documentation embedded in comment blocks
|
|
# in the source code (for Gnome).
|
|
#
|
|
# Parameter descriptions override any in the template files.
|
|
# Function descriptions are placed before any description from
|
|
# the template files.
|
|
#
|
|
# It recursively descends the source directory looking for .c
|
|
# files and scans them looking for specially-formatted comment
|
|
# blocks.
|
|
#
|
|
# Arguments : $source_dir - the directory to scan.
|
|
#############################################################################
|
|
|
|
sub ReadSourceDocumentation {
|
|
my ($source_dir) = @_;
|
|
# print "Scanning source directory: $source_dir\n";
|
|
|
|
# This array holds any subdirectories found.
|
|
my (@subdirs) = ();
|
|
|
|
opendir (SRCDIR, $source_dir)
|
|
|| die "Can't open source directory $source_dir: $!";
|
|
my $file;
|
|
foreach $file (readdir (SRCDIR)) {
|
|
if ($file =~ /^\./) {
|
|
next;
|
|
} elsif (-d "$source_dir/$file") {
|
|
push (@subdirs, $file);
|
|
} elsif ($file =~ m/\.c$/) {
|
|
&ScanSourceFile ("$source_dir/$file");
|
|
}
|
|
}
|
|
closedir (SRCDIR);
|
|
|
|
# Now recursively scan the subdirectories.
|
|
my $dir;
|
|
foreach $dir (@subdirs) {
|
|
&ReadSourceDocumentation ("$source_dir/$dir");
|
|
}
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : ScanSourceFile
|
|
# Description : Scans one source file looking for specially-formatted comment
|
|
# blocks. It calls &MergeSourceDocumentation to merge any
|
|
# documentation found with the documentation already read in
|
|
# from the template files.
|
|
#
|
|
# Arguments : $file - the file to scan.
|
|
#############################################################################
|
|
|
|
sub ScanSourceFile {
|
|
my ($file) = @_;
|
|
|
|
# print "Scanning source file: $file\n";
|
|
|
|
open (SRCFILE, $file)
|
|
|| die "Can't open $file: $!";
|
|
my $in_comment_block = 0;
|
|
my $symbol;
|
|
my ($in_description, $in_return);
|
|
my ($description, $return_desc, $return_start);
|
|
my $current_param;
|
|
my @params;
|
|
while (<SRCFILE>) {
|
|
# Look for the start of a comment block.
|
|
if (!$in_comment_block) {
|
|
if (m%^\s*/\*\*\s%) {
|
|
# print "Found comment block start\n";
|
|
$in_comment_block = 1;
|
|
|
|
# Reset all the symbol data.
|
|
$symbol = "";
|
|
$in_description = 0;
|
|
$in_return = 0;
|
|
$description = "";
|
|
$return_desc = "";
|
|
$current_param = -1;
|
|
@params = ();
|
|
}
|
|
next;
|
|
}
|
|
|
|
# We're in a comment block. Check if we've found the end of it.
|
|
if (m%^\s*\*+/%) {
|
|
# print "Found comment block end: $symbol\n";
|
|
if (!$symbol) {
|
|
print <<EOF;
|
|
WARNING: symbol name not found in comment block.
|
|
$file line $.
|
|
EOF
|
|
} else {
|
|
# Add the return value description onto the end of the params.
|
|
if ($return_desc) {
|
|
push (@params, "Returns");
|
|
push (@params, $return_desc);
|
|
}
|
|
$SourceSymbolDocs{$symbol} = $description;
|
|
$SourceSymbolParams{$symbol} = [ @params ];
|
|
}
|
|
|
|
$in_comment_block = 0;
|
|
next;
|
|
}
|
|
|
|
# Get rid of ' * ' at start of every line in the comment block.
|
|
s%^\s*\*\s*%%;
|
|
# But make sure we don't get rid of the newline at the end.
|
|
if (!$_) {
|
|
$_ = "\n";
|
|
}
|
|
|
|
# If we haven't found the symbol name yet, look for it.
|
|
if (!$symbol) {
|
|
if (m%^(\w+)\s*:?%) {
|
|
$symbol = $1;
|
|
}
|
|
next;
|
|
}
|
|
|
|
# If we're in the return value description, add it to the end.
|
|
if ($in_return) {
|
|
# If we find another valid returns line, we assume that the first
|
|
# one was really part of the description.
|
|
if (m%^(returns:|return\s+value:|returns\s*)%i) {
|
|
$description .= $return_start . $return_desc;
|
|
$return_start = $1;
|
|
$return_desc = $';
|
|
} else {
|
|
$return_desc .= $_;
|
|
}
|
|
next;
|
|
}
|
|
|
|
# If we're in the description part, check for the 'Return' line.
|
|
# If that isn't found, add the text to the end.
|
|
if ($in_description) {
|
|
# Get rid of 'Description:'
|
|
s%^Description:%%;
|
|
|
|
if (m%^(returns:|return\s+value:|returns\s*)%i) {
|
|
# print "RETURNS: $_";
|
|
$return_start = $1;
|
|
$return_desc = $';
|
|
$in_return = 1;
|
|
next;
|
|
}
|
|
|
|
$description .= $_;
|
|
next;
|
|
}
|
|
|
|
# We must be in the parameters. Check for the empty line at the end.
|
|
if (m%^$%) {
|
|
$in_description = 1;
|
|
next;
|
|
}
|
|
|
|
# Look for a parameter name.
|
|
if (m%^@(\S+)\s*:%) {
|
|
my $param_name = $1;
|
|
# print "Found parameter: $param_name\n";
|
|
# Allow '...' as the Varargs parameter.
|
|
if ($param_name eq "...") {
|
|
$param_name = "Varargs";
|
|
}
|
|
push (@params, $param_name);
|
|
push (@params, $');
|
|
$current_param += 2;
|
|
next;
|
|
}
|
|
|
|
# We must be in the middle of a parameter description, so add it on
|
|
# to the last element in @params.
|
|
if ($current_param == -1) {
|
|
print <<EOF
|
|
ERROR parsing comment block file : parameter expected -
|
|
$file:$.
|
|
EOF
|
|
} else {
|
|
$params[$#params] .= $_;
|
|
}
|
|
}
|
|
close (SRCFILE);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : MergeSourceDocumentation
|
|
# Description : This merges documentation read from a source file into the
|
|
# documentation read in from a template file.
|
|
#
|
|
# Parameter descriptions override any in the template files.
|
|
# Function descriptions are placed before any description from
|
|
# the template files.
|
|
#
|
|
# Arguments : none
|
|
#############################################################################
|
|
|
|
sub MergeSourceDocumentation {
|
|
my $symbol;
|
|
foreach $symbol (keys (%SymbolDocs)) {
|
|
if (exists ($SourceSymbolDocs{$symbol})) {
|
|
my $src_doc = $SourceSymbolDocs{$symbol};
|
|
my $tmpl_doc = $SymbolDocs{$symbol};
|
|
$tmpl_doc = defined ($tmpl_doc) ? $tmpl_doc : "";
|
|
$src_doc =~ s/^\s+//;
|
|
$src_doc =~ s/\s+$//;
|
|
|
|
# Convert special SGML characters. I'm not sure if we want to do
|
|
# this but currently there are a couple of '&'s in the source code
|
|
# comment blocks which mess up the HTML output badly.
|
|
$src_doc = &CreateValidSGML ($src_doc);
|
|
|
|
# If there is a blank line, finish the paragraph and start another.
|
|
if ($src_doc =~ s%\n{2,}%\n</para>\n<para>\n%g) {
|
|
# print "Converted blank lines:\n$src_doc\n";
|
|
}
|
|
$SymbolDocs{$symbol} = "<para>\n$src_doc</para>\n$tmpl_doc";
|
|
|
|
# The templates contain the definitive parameter names and order,
|
|
# so we will not change that. We only override the actual text.
|
|
my $tmpl_params = $SymbolParams{$symbol};
|
|
if (!defined ($tmpl_params)) {
|
|
next;
|
|
}
|
|
|
|
my $params = $SourceSymbolParams{$symbol};
|
|
my $j;
|
|
for ($j = 0; $j <= $#$tmpl_params; $j += 2) {
|
|
my $tmpl_param_name = $$tmpl_params[$j];
|
|
my $tmpl_param_desc = $$tmpl_params[$j + 1];
|
|
|
|
# Try to find the param in the source comment documentation.
|
|
my $found = 0;
|
|
my $k;
|
|
for ($k = 0; $k <= $#$params; $k += 2) {
|
|
my $param_name = $$params[$k];
|
|
my $param_desc = $$params[$k + 1];
|
|
|
|
# We accept changed in case, since the Gnome source docs
|
|
# contain a lot of these.
|
|
if ("\L$param_name" eq "\L$tmpl_param_name") {
|
|
$found = 1;
|
|
|
|
# Override the description.
|
|
$$tmpl_params[$j + 1] = &CreateValidSGML ($param_desc);
|
|
|
|
# Set the name to "" to mark it as used.
|
|
$$params[$k] = "";
|
|
last;
|
|
}
|
|
}
|
|
|
|
# Output a warning if the parameter is not found.
|
|
if (!$found) {
|
|
print <<EOF;
|
|
WARNING: Parameter description missing in source code comment block -
|
|
Func: $symbol Param: $tmpl_param_name.
|
|
EOF
|
|
}
|
|
}
|
|
|
|
# Now we output a warning if parameters have been described which
|
|
# do not exist.
|
|
for ($j = 0; $j <= $#$params; $j += 2) {
|
|
my $param_name = $$params[$j];
|
|
if ($param_name) {
|
|
print <<EOF;
|
|
WARNING: Parameter described in source code comment block but does not exist -
|
|
Func: $symbol Param: $param_name.
|
|
EOF
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# LIBRARY FUNCTIONS - These functions are used in both gtkdoc-mkdb and
|
|
# gtkdoc-mktmpl and should eventually be moved to a
|
|
# separate library.
|
|
#############################################################################
|
|
|
|
#############################################################################
|
|
# Function : ReadDeclarationsFile
|
|
# Description : This reads in a file containing the function/macro/enum etc.
|
|
# declarations.
|
|
#
|
|
# Note that in some cases there are several declarations with
|
|
# the same name, e.g. for conditional macros. In this case we
|
|
# set a flag in the %DeclarationConditional hash so the
|
|
# declaration is not shown in the docs.
|
|
#
|
|
# If a macro and a function have the same name, e.g. for
|
|
# gtk_object_ref, the function declaration takes precedence.
|
|
#
|
|
# Some opaque structs are just declared with 'typedef struct
|
|
# _name name;' in which case the declaration may be empty.
|
|
# The structure may have been found later in the header, so
|
|
# that overrides the empty declaration.
|
|
#
|
|
# Arguments : $file - the declarations file to read
|
|
# $override - if declarations in this file should override
|
|
# any current declaration.
|
|
#############################################################################
|
|
|
|
sub ReadDeclarationsFile {
|
|
my ($file, $override) = @_;
|
|
|
|
if ($override == 0) {
|
|
%Declarations = ();
|
|
%DeclarationTypes = ();
|
|
%DeclarationConditional = ();
|
|
%DeclarationOutput = ();
|
|
}
|
|
|
|
open (INPUT, $file)
|
|
|| die "Can't open $file";
|
|
my $declaration_type = "";
|
|
my $declaration_name;
|
|
my $declaration;
|
|
while (<INPUT>) {
|
|
if (!$declaration_type) {
|
|
if (m/^<([^>]+)>/) {
|
|
$declaration_type = $1;
|
|
$declaration_name = "";
|
|
# print "Found declaration: $declaration_type\n";
|
|
$declaration = "";
|
|
}
|
|
} else {
|
|
if (m%^<NAME>(.*)</NAME>%) {
|
|
$declaration_name = $1;
|
|
} elsif (m%^</$declaration_type>%) {
|
|
# print "Found end of declaration: $declaration_name\n";
|
|
# Check that the declaration has a name
|
|
if ($declaration_name eq "") {
|
|
print "ERROR: $declaration_type has no name $file:$.\n";
|
|
}
|
|
|
|
# Check if the symbol is already defined.
|
|
if (defined ($Declarations{$declaration_name})
|
|
&& $override == 0) {
|
|
# Function declarations take precedence.
|
|
if ($DeclarationTypes{$declaration_name} eq 'FUNCTION') {
|
|
# Ignore it.
|
|
} elsif ($declaration_type eq 'FUNCTION') {
|
|
$Declarations{$declaration_name} = $declaration;
|
|
$DeclarationTypes{$declaration_name} = $declaration_type;
|
|
} elsif ($DeclarationTypes{$declaration_name}
|
|
eq $declaration_type) {
|
|
# If the existing declaration is empty override it.
|
|
if ($declaration_type eq 'STRUCT') {
|
|
if ($Declarations{$declaration_name} =~ m/^\s*$/) {
|
|
$Declarations{$declaration_name} = $declaration;
|
|
} elsif ($declaration =~ m/^\s*$/) {
|
|
# Ignore an empty declaration.
|
|
} else {
|
|
print "WARNING: Structure has multiple definitions: $declaration_name\n";
|
|
}
|
|
|
|
} else {
|
|
# set flag in %DeclarationConditional hash for
|
|
# multiply defined macros/typedefs.
|
|
$DeclarationConditional{$declaration_name} = 1;
|
|
}
|
|
} else {
|
|
print "ERROR: $declaration_name has multiple definitions\n";
|
|
}
|
|
} else {
|
|
$Declarations{$declaration_name} = $declaration;
|
|
$DeclarationTypes{$declaration_name} = $declaration_type;
|
|
}
|
|
$declaration_type = "";
|
|
} else {
|
|
$declaration .= $_;
|
|
}
|
|
}
|
|
}
|
|
close (INPUT);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : ReadSignalsFile
|
|
# Description : This reads in an existing file which contains information on
|
|
# all GTK signals. It creates the arrays @SignalNames and
|
|
# @SignalPrototypes containing info on the signals. The first
|
|
# line of the SignalPrototype is the return type of the signal
|
|
# handler. The remaining lines are the parameters passed to it.
|
|
# The last parameter, "gpointer user_data" is always the same
|
|
# so is not included.
|
|
# Arguments : $file - the file containing the signal handler prototype
|
|
# information.
|
|
#############################################################################
|
|
|
|
sub ReadSignalsFile {
|
|
my ($file) = @_;
|
|
|
|
my $in_signal = 0;
|
|
my $signal_object;
|
|
my $signal_name;
|
|
my $signal_returns;
|
|
my $signal_prototype;
|
|
|
|
# Reset the signal info.
|
|
@SignalObjects = ();
|
|
@SignalNames = ();
|
|
@SignalReturns = ();
|
|
@SignalPrototypes = ();
|
|
|
|
if (! -f $file) {
|
|
return;
|
|
}
|
|
if (!open (INPUT, $file)) {
|
|
warn "Can't open $file - skipping signals\n";
|
|
return;
|
|
}
|
|
while (<INPUT>) {
|
|
if (!$in_signal) {
|
|
if (m/^<SIGNAL>/) {
|
|
$in_signal = 1;
|
|
$signal_object = "";
|
|
$signal_name = "";
|
|
$signal_returns = "";
|
|
$signal_prototype = "";
|
|
}
|
|
} else {
|
|
if (m/^<NAME>(.*)<\/NAME>/) {
|
|
$signal_name = $1;
|
|
if ($signal_name =~ m/^(.*)::(.*)$/) {
|
|
$signal_object = $1;
|
|
$signal_name = $2;
|
|
# print "Found signal: $signal_name\n";
|
|
} else {
|
|
print "Invalid signal name: $signal_name\n";
|
|
}
|
|
} elsif (m/^<RETURNS>(.*)<\/RETURNS>/) {
|
|
$signal_returns = $1;
|
|
} elsif (m%^</SIGNAL>%) {
|
|
# print "Found end of signal: ${signal_object}::${signal_name}\nReturns: ${signal_returns}\n${signal_prototype}";
|
|
push (@SignalObjects, $signal_object);
|
|
push (@SignalNames, $signal_name);
|
|
push (@SignalReturns, $signal_returns);
|
|
push (@SignalPrototypes, $signal_prototype);
|
|
$in_signal = 0;
|
|
} else {
|
|
$signal_prototype .= $_;
|
|
}
|
|
}
|
|
}
|
|
close (INPUT);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : ReadTemplateFile
|
|
# Description : This reads in the manually-edited documentation file
|
|
# corresponding to the file currently being created, so we can
|
|
# insert the documentation at the appropriate places.
|
|
# It outputs %SymbolTypes, %SymbolDocs and %SymbolParams, which
|
|
# is a hash of arrays.
|
|
# NOTE: This function is duplicated in gtkdoc-mkdb (but
|
|
# slightly different).
|
|
# Arguments : $docsfile - the template file to read in.
|
|
# $skip_unused_params - 1 if the unused parameters should be
|
|
# skipped.
|
|
#############################################################################
|
|
|
|
sub ReadTemplateFile {
|
|
my ($docsfile, $skip_unused_params) = @_;
|
|
|
|
# print "Reading $docsfile\n";
|
|
if (! -f $docsfile) {
|
|
print "File doesn't exist: $docsfile\n";
|
|
return;
|
|
}
|
|
|
|
my $current_type = ""; # Type of symbol being read.
|
|
my $current_symbol = ""; # Name of symbol being read.
|
|
my $symbol_doc = ""; # Description of symbol being read.
|
|
my @params; # Parameter names and descriptions of current
|
|
# function/macro/function typedef.
|
|
my $current_param = -1; # Index of parameter currently being read.
|
|
# Note that the param array contains pairs
|
|
# of param name & description.
|
|
my $in_unused_params = 0; # True if we are reading in the unused params.
|
|
|
|
open (DOCS, $docsfile)
|
|
|| die "Can't open file $docsfile: $!";
|
|
while (<DOCS>) {
|
|
if (m/^<!-- ##### ([A-Z_]+) (\S+) ##### -->/) {
|
|
my $type = $1;
|
|
my $symbol = $2;
|
|
if ($symbol eq "Title"
|
|
|| $symbol eq "Short_Description"
|
|
|| $symbol eq "Long_Description"
|
|
|| $symbol eq "See_Also") {
|
|
$symbol = $docsfile . ":" . $symbol;
|
|
# print "Found symbol: $symbol\n";
|
|
}
|
|
|
|
# Store previous symbol, but remove any trailing blank lines.
|
|
if ($current_symbol ne "") {
|
|
$symbol_doc =~ s/\s+$//;
|
|
$SymbolTypes{$current_symbol} = $current_type;
|
|
$SymbolDocs{$current_symbol} = $symbol_doc;
|
|
if ($current_param >= 0) {
|
|
$SymbolParams{$current_symbol} = [ @params ];
|
|
} else {
|
|
# Delete any existing params in case we are overriding a
|
|
# previously read template.
|
|
delete $SymbolParams{$current_symbol};
|
|
}
|
|
}
|
|
$current_type = $type;
|
|
$current_symbol = $symbol;
|
|
$current_param = -1;
|
|
$in_unused_params = 0;
|
|
$symbol_doc = "";
|
|
@params = ();
|
|
|
|
} elsif (m/^<!-- # Unused Parameters # -->/) {
|
|
# print "DEBUG: Found unused parameters\n";
|
|
$in_unused_params = 1;
|
|
next;
|
|
|
|
} elsif ($in_unused_params && $skip_unused_params) {
|
|
# When outputting the DocBook we skip unused parameters.
|
|
# print "DEBUG: Skipping unused param: $_";
|
|
next;
|
|
|
|
} else {
|
|
# Check if param found
|
|
if (s/^\@(\S+):\s*//) {
|
|
my $param_name = $1;
|
|
# Allow variations of 'Returns'
|
|
if ($param_name =~ m/^[Rr]eturns?$/) {
|
|
$param_name = "Returns";
|
|
}
|
|
# print "Found param: $param_name\n";
|
|
push (@params, $param_name);
|
|
push (@params, $_);
|
|
$current_param += 2;
|
|
next;
|
|
}
|
|
|
|
if ($current_param >= 0) {
|
|
$params[$current_param] .= $_;
|
|
} else {
|
|
$symbol_doc .= $_;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Remember to finish the current symbol doccs.
|
|
if ($current_symbol ne "") {
|
|
$symbol_doc =~ s/\s+$//;
|
|
$SymbolTypes{$current_symbol} = $current_type;
|
|
$SymbolDocs{$current_symbol} = $symbol_doc;
|
|
if ($current_param >= 0) {
|
|
$SymbolParams{$current_symbol} = [ @params ];
|
|
} else {
|
|
delete $SymbolParams{$current_symbol};
|
|
}
|
|
}
|
|
|
|
close (DOCS);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : ReadObjectHierarchy
|
|
# Description : This reads in the $MODULE-hierarchy.txt file containing all
|
|
# the GtkObject subclasses described in this module (and their
|
|
# ancestors).
|
|
# It places them in the @Objects array, and places their level
|
|
# in the widget hierarchy in the @ObjectLevels array, at the
|
|
# same index. GtkObject, the root object, has a level of 1.
|
|
#
|
|
# FIXME: the version in gtkdoc-mkdb also generates tree_index.sgml
|
|
# as it goes along, this should be split out into a separate
|
|
# function.
|
|
#
|
|
# Arguments : none
|
|
#############################################################################
|
|
|
|
sub ReadObjectHierarchy {
|
|
@Objects = ();
|
|
@ObjectLevels = ();
|
|
|
|
if (! -f $OBJECT_TREE_FILE) {
|
|
return;
|
|
}
|
|
if (!open (INPUT, $OBJECT_TREE_FILE)) {
|
|
warn "Can't open $OBJECT_TREE_FILE - skipping object tree\n";
|
|
return;
|
|
}
|
|
open (OUTPUT, ">$SGML_OUTPUT_DIR/tree_index.sgml")
|
|
|| die "Can't create $SGML_OUTPUT_DIR/tree_index.sgml";
|
|
print (OUTPUT "<literallayout>\n");
|
|
|
|
while (<INPUT>) {
|
|
if (m/\S+/) {
|
|
my $object = $&;
|
|
my $level = (length($`)) / 2 + 1;
|
|
# print ("Level: $level Object: $object\n");
|
|
|
|
my $xref = &MakeXRef ($object);
|
|
print (OUTPUT ' ' x ($level * 4), "$xref\n");
|
|
push (@Objects, $object);
|
|
push (@ObjectLevels, $level);
|
|
}
|
|
}
|
|
print (OUTPUT "</literallayout>\n");
|
|
|
|
close (INPUT);
|
|
close (OUTPUT);
|
|
|
|
&OutputObjectList;
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : ReadArgsFile
|
|
# Description : This reads in an existing file which contains information on
|
|
# all GTK args. It creates the arrays @ArgObjects, @ArgNames,
|
|
# @ArgTypes and @ArgFlags containing info on the args.
|
|
# Arguments : $file - the file containing the arg information.
|
|
#############################################################################
|
|
|
|
sub ReadArgsFile {
|
|
my ($file) = @_;
|
|
|
|
my $in_arg = 0;
|
|
my $arg_object;
|
|
my $arg_name;
|
|
my $arg_type;
|
|
my $arg_flags;
|
|
|
|
# Reset the signal info.
|
|
@ArgObjects = ();
|
|
@ArgNames = ();
|
|
@ArgTypes = ();
|
|
@ArgFlags = ();
|
|
|
|
if (! -f $file) {
|
|
return;
|
|
}
|
|
if (!open (INPUT, $file)) {
|
|
warn "Can't open $file - skipping args\n";
|
|
return;
|
|
}
|
|
while (<INPUT>) {
|
|
if (!$in_arg) {
|
|
if (m/^<ARG>/) {
|
|
$in_arg = 1;
|
|
$arg_object = "";
|
|
$arg_name = "";
|
|
$arg_type = "";
|
|
$arg_flags = "";
|
|
}
|
|
} else {
|
|
if (m/^<NAME>(.*)<\/NAME>/) {
|
|
$arg_name = $1;
|
|
if ($arg_name =~ m/^(.*)::(.*)$/) {
|
|
$arg_object = $1;
|
|
$arg_name = $2;
|
|
# print "Found arg: $arg_name\n";
|
|
} else {
|
|
print "Invalid arg name: $arg_name\n";
|
|
}
|
|
} elsif (m/^<TYPE>(.*)<\/TYPE>/) {
|
|
$arg_type = $1;
|
|
} elsif (m/^<FLAGS>(.*)<\/FLAGS>/) {
|
|
$arg_flags = $1;
|
|
} elsif (m%^</ARG>%) {
|
|
# print "Found end of arg: ${arg_object}::${arg_name}\n${arg_type} : ${arg_flags}\n";
|
|
push (@ArgObjects, $arg_object);
|
|
push (@ArgNames, $arg_name);
|
|
push (@ArgTypes, $arg_type);
|
|
push (@ArgFlags, $arg_flags);
|
|
$in_arg = 0;
|
|
}
|
|
}
|
|
}
|
|
close (INPUT);
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : CheckIsObject
|
|
# Description : Returns 1 if the given name is a GtkObject or a subclass.
|
|
# It uses the global @Objects array.
|
|
# Note that the @Objects array only contains classes in the
|
|
# current module and their ancestors - not all GTK classes.
|
|
# Arguments : $name - the name to check.
|
|
#############################################################################
|
|
|
|
sub CheckIsObject {
|
|
my ($name) = @_;
|
|
|
|
my $object;
|
|
foreach $object (@Objects) {
|
|
if ($object eq $name) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : ParseStructDeclaration
|
|
# Description : This function takes a structure declaration and
|
|
# breaks it into individual type declarations.
|
|
# Arguments : $declaration - the declaration to parse
|
|
# $is_object - true if this is an object structure
|
|
# $typefunc - function reference to apply to type
|
|
# $namefunc - function reference to apply to name
|
|
#############################################################################
|
|
|
|
sub ParseStructDeclaration {
|
|
my ($declaration, $is_object, $typefunc, $namefunc) = @_;
|
|
|
|
# Remove all private parts of the declaration
|
|
|
|
# For objects, assume private
|
|
if ($is_object) {
|
|
$declaration =~ s!(struct\s+\w*\s*\{)
|
|
.*?
|
|
(?:/\*\s*<\s*public\s*>\s*\*/|(?=\}))!$1!msgx;
|
|
}
|
|
|
|
$declaration =~ s!\n?[ \t]*/\*\s*<\s*private\s*>\s*\*/
|
|
.*?
|
|
(?:/\*\s*<\s*public\s*>\s*\*/|(?=\}))!!msgx;
|
|
|
|
# Remove all other comments;
|
|
$declaration =~ s@/\*([^*]+|\*(?!/))*\*/@ @g;
|
|
|
|
my @result = ();
|
|
|
|
if ($declaration =~ /^\s*$/) {
|
|
return @result;
|
|
}
|
|
|
|
# Prime match after "struct {" declaration
|
|
if (!scalar($declaration =~ m/struct\s+\w*\s*\{/msg)) {
|
|
die "Structure declaration '$declaration' does not begin with struct [NAME] {\n";
|
|
}
|
|
|
|
# Treat lines in sequence, allowing singly nested anonymous structs
|
|
# and unions.
|
|
while ($declaration =~ m/\s*([^{;]+(\{[^\}]*\}[^{;]+)?);/msg) {
|
|
my $line = $1;
|
|
|
|
last if $line =~ /^\s*\}\s*\w*\s*$/;
|
|
|
|
# FIXME: Just ignore nested structs and unions for now
|
|
next if $line =~ /{/;
|
|
|
|
# FIXME: The regexes here are the same as in OutputFunction;
|
|
# this functionality should be separated out.
|
|
|
|
if ($line =~ m/^
|
|
(const\s+|unsigned\s+)*(struct\s+)? # mod1
|
|
(\w+)\s* # type
|
|
(\**)\s* # ptr1
|
|
(const\s+)? # mod2
|
|
(\**)?\s* # ptr2
|
|
(\w+(?:\s*,\s*\w+)*)\s* # name
|
|
(?:((?:\[[^\]]*\]\s*)+) | # array
|
|
(:\s*\d+))?\s* # bits
|
|
$/x) {
|
|
my $mod1 = defined($1) ? $1 : "";
|
|
if (defined($2)) { $mod1 .= $2; }
|
|
my $type = $3;
|
|
my $ptr1 = $4;
|
|
my $mod2 = defined($5) ? $5 : "";
|
|
my $ptr2 = $6;
|
|
my $name = $7;
|
|
$ptr1 = " " . $ptr1;
|
|
my $array = defined($8) ? $8 : "";
|
|
my $bits = defined($9) ? " $9" : "";
|
|
my $ptype = defined $typefunc ? $typefunc->($type) : $type;
|
|
|
|
# FIXME:
|
|
# As a hack, we allow the "name" to be of the form
|
|
# "a, b, c". This isn't the correct C syntax, but
|
|
# at least we get "gint16 x, y" right. Such constructs
|
|
# should really be completely removed from the source.
|
|
# Or we should really try to understand the C syntax
|
|
# here...
|
|
|
|
my @names = split /\s*,\s*/, $name;
|
|
for my $n (@names) {
|
|
push @result, $n;
|
|
if (defined $namefunc) {
|
|
$n = $namefunc->($n);
|
|
}
|
|
push @result, "$mod1$ptype$ptr1$mod2$ptr2$n$array$bits";
|
|
}
|
|
|
|
# Try to match structure members which are functions
|
|
} elsif ($line =~ m/^
|
|
(const\s+|unsigned\s+)*(struct\s+)? # mod1
|
|
(\w+)\s* # type
|
|
(\**)\s* # ptr1
|
|
(const\s+)? # mod2
|
|
\(\s*\*\s*(\w+)\s*\)\s* # name
|
|
\(([^)]*)\)\s* # func_params
|
|
$/x) {
|
|
|
|
my $mod1 = defined($1) ? $1 : "";
|
|
if (defined($2)) { $mod1 .= $2; }
|
|
my $type = $3;
|
|
my $ptr1 = $4;
|
|
my $mod2 = defined($5) ? $5 : "";
|
|
my $name = $6;
|
|
my $func_params = $7;
|
|
my $ptype = defined $typefunc ? $typefunc->($type) : $type;
|
|
my $pname = defined $namefunc ? $namefunc->($name) : $name;
|
|
|
|
push @result, $name;
|
|
push @result, "$mod1$ptype$ptr1$mod2 (*$pname) ($func_params)";
|
|
|
|
} else {
|
|
warn "Cannot parse structure field $line";
|
|
}
|
|
}
|
|
|
|
return @result;
|
|
}
|
|
|
|
|
|
#############################################################################
|
|
# Function : ParseEnumDeclaration
|
|
# Description : This function takes a enumeration declaration and
|
|
# breaks it into individual enum member declarations.
|
|
# Arguments : $declaration - the declaration to parse
|
|
#############################################################################
|
|
|
|
sub ParseEnumDeclaration {
|
|
my ($declaration, $is_object) = @_;
|
|
|
|
# Remove comments;
|
|
$declaration =~ s@/\*([^*]+|\*(?!/))*\*/@ @g;
|
|
|
|
my @result = ();
|
|
|
|
if ($declaration =~ /^\s*$/) {
|
|
return @result;
|
|
}
|
|
|
|
# Remove parenthesized expressions (in macros like GTK_BLAH = BLAH(1,3))
|
|
# to avoid getting confused by commas they might contain. This
|
|
# doesn't handle nested parentheses correctly.
|
|
|
|
$declaration =~ s/\([^)]+\)//g;
|
|
|
|
# Prime match after "typedef enum {" declaration
|
|
if (!scalar($declaration =~ m/typedef\s+enum\s*\{/msg)) {
|
|
die "Enum declaration '$declaration' does not begin with typedef enum {\n";
|
|
}
|
|
|
|
# Treat lines in sequence.
|
|
while ($declaration =~ m/\s*([^,\}]+)([,\}])/msg) {
|
|
my $line = $1;
|
|
my $terminator = $2;
|
|
|
|
if ($line =~ m/^(\w+)\s*(=.*)?$/msg) {
|
|
push @result, $1;
|
|
|
|
# Special case for GIOCondition, where the values are specified by
|
|
# macros which expand to include the equal sign like '=1'.
|
|
} elsif ($line =~ m/^(\w+)\s*GLIB_SYSDEF_POLL/msg) {
|
|
push @result, $1;
|
|
|
|
# Special case include of <gdk/gdkcursors.h>, just ignore it
|
|
} elsif ($line =~ m/^#include/) {
|
|
last;
|
|
|
|
} else {
|
|
warn "Cannot parse enumeration member $line";
|
|
}
|
|
|
|
last if $terminator eq '}';
|
|
}
|
|
|
|
return @result;
|
|
}
|