[gtk-doc] Revert "mkdb: convert gtkdoc-mkdb to python"



commit 7f04a05514f9fb3501b272811ee91a8344edd3a4
Author: Stefan Sauer <ensonic users sf net>
Date:   Fri Apr 28 14:26:01 2017 +0200

    Revert "mkdb: convert gtkdoc-mkdb to python"
    
    This reverts commit fad013949dfbbac3eb94cb93dd36c7d6cca22fde.

 gtkdoc-mkdb.in      | 9420 +++++++++++++++++++++++++++------------------------
 tests/Makefile.am   |    2 +-
 tests/gtkdoc-mkdb.t |   30 +
 tests/tools.sh.in   |    2 +-
 4 files changed, 4963 insertions(+), 4491 deletions(-)
---
diff --git a/gtkdoc-mkdb.in b/gtkdoc-mkdb.in
index fd070e9..f065344 100755
--- a/gtkdoc-mkdb.in
+++ b/gtkdoc-mkdb.in
@@ -1,5 +1,5 @@
-#!@PYTHON@
-# -*- python; coding: utf-8 -*-
+#!@PERL@ -w
+# -*- cperl -*-
 #
 # gtk-doc - GTK DocBook documentation generator.
 # Copyright (C) 1998  Damon Chaplin
@@ -25,188 +25,186 @@
 # Description : This creates the DocBook files from the edited templates.
 #############################################################################
 
-from __future__ import print_function
+use warnings;
+use strict;
+use Getopt::Long;
 
-import argparse
-import logging
-import os
-import re
-import sys
-
-from gtkdoc import common
+push @INC, '@PACKAGE_DATA_DIR@';
+require "gtkdoc-common.pl";
 
 # Options
 
 # name of documentation module
-MODULE = None
-TMPL_DIR = None
-DB_OUTPUT_DIR = None
-SOURCE_DIRS = None
-SOURCE_SUFFIXES = ''
-IGNORE_FILES = ''
-MAIN_SGML_FILE = None
-EXPAND_CONTENT_FILES = ''
-INLINE_MARKUP_MODE = None
-DEFAULT_STABILITY = None
-DEFAULT_INCLUDES = None
-OUTPUT_FORMAT = None
-NAME_SPACE = ''
-OUTPUT_ALL_SYMBOLS = None
-OUTPUT_SYMBOLS_WITHOUT_SINCE = None
-ROOT_DIR = "."
-OBJECT_TREE_FILE = None
-INTERFACES_FILE = None
-PREREQUISITES_FILE = None
-SIGNALS_FILE = None
-ARGS_FILE = None
+my $MODULE;
+my $TMPL_DIR;
+my $DB_OUTPUT_DIR;
+my @SOURCE_DIRS;
+my $SOURCE_SUFFIXES = "";
+my $IGNORE_FILES = "";
+my $PRINT_VERSION;
+my $PRINT_HELP;
+my $MAIN_SGML_FILE;
+my $EXPAND_CONTENT_FILES = "";
+my $INLINE_MARKUP_MODE;
+my $DEFAULT_STABILITY;
+my $DEFAULT_INCLUDES;
+my $OUTPUT_FORMAT;
+my $NAME_SPACE = "";
+my $OUTPUT_ALL_SYMBOLS;
+my $OUTPUT_SYMBOLS_WITHOUT_SINCE;
+my $ROOT_DIR = ".";
+my $OBJECT_TREE_FILE;
+my $INTERFACES_FILE;
+my $PREREQUISITES_FILE;
+my $SIGNALS_FILE;
+my $ARGS_FILE;
 
 # 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.
-SignalObjects = []        # The GtkObject which emits the signal.
-SignalNames = []        # The signal name.
-SignalReturns = []        # The return type.
-SignalFlags = []        # Flags for the signal
-SignalPrototypes = []        # The rest of the prototype of the signal handler.
+my @SignalObjects;        # The GtkObject which emits the signal.
+my @SignalNames;        # The signal name.
+my @SignalReturns;        # The return type.
+my @SignalFlags;        # Flags for the signal
+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.
-ArgObjects = []                # The GtkObject which has the Arg.
-ArgNames = []                # The Arg name.
-ArgTypes = []                # The Arg type - gint, GtkArrowType etc.
-ArgFlags = []                # How the Arg can be used - readable/writable etc.
-ArgNicks = []                # The nickname of the Arg.
-ArgBlurbs = []          # Docstring of the Arg.
-ArgDefaults = []        # Default value of the Arg.
-ArgRanges = []                # The range of the Arg type
-
+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.
+my @ArgNicks;                # The nickname of the Arg.
+my @ArgBlurbs;          # Docstring of the Arg.
+my @ArgDefaults;        # Default value of the Arg.
+my @ArgRanges;                # The range of the Arg type
 # These global hashes store declaration info keyed on a symbol name.
-Declarations = {}
-DeclarationTypes = {}
-DeclarationConditional = {}
-DeclarationOutput = {}
-Deprecated = {}
-Since = {}
-StabilityLevel = {}
-StructHasTypedef = {}
+my %Declarations;
+my %DeclarationTypes;
+my %DeclarationConditional;
+my %DeclarationOutput;
+my %Deprecated;
+my %Since;
+my %StabilityLevel;
+my %StructHasTypedef;
 
 # These global hashes store the existing documentation.
-SymbolDocs = {}
-SymbolTypes = {}
-SymbolParams = {}
-SymbolSourceFile = {}
-SymbolSourceLine = {}
-SymbolAnnotations = {}
+my %SymbolDocs;
+my %SymbolTypes;
+my %SymbolParams;
+my %SymbolSourceFile;
+my %SymbolSourceLine;
+my %SymbolAnnotations;
 
 # These global hashes store documentation scanned from the source files.
-SourceSymbolDocs = {}
-SourceSymbolParams = {}
-SourceSymbolSourceFile = {}
-SourceSymbolSourceLine = {}
+my %SourceSymbolDocs;
+my %SourceSymbolParams;
+my %SourceSymbolSourceFile;
+my %SourceSymbolSourceLine;
 
 # all documentation goes in here, so we can do coverage analysis
-AllSymbols = {}
-AllIncompleteSymbols = {}
-AllUnusedSymbols = {}
-AllDocumentedSymbols = {}
+my %AllSymbols;
+my %AllIncompleteSymbols;
+my %AllUnusedSymbols;
+my %AllDocumentedSymbols;
 
 # Undeclared yet documented symbols
-UndeclaredSymbols = {}
+my %UndeclaredSymbols;
 
 # These global arrays store GObject, subclasses and the hierarchy (also of
 # non-object derived types).
-Objects = []
-ObjectLevels = []
-ObjectRoots = {}
+my @Objects;
+my @ObjectLevels;
+my %ObjectRoots;
 
-Interfaces = {}
-Prerequisites = {}
+my %Interfaces;
+my %Prerequisites;
 
 # holds the symbols which are mentioned in $MODULE-sections.txt and in which
 # section they are defined
-KnownSymbols = {}
-SymbolSection = {}
-SymbolSectionId = {}
+my %KnownSymbols;
+my %SymbolSection;
+my %SymbolSectionId;
 
 # collects index entries
-IndexEntriesFull = {}
-IndexEntriesSince = {}
-IndexEntriesDeprecated = {}
+my %IndexEntriesFull;
+my %IndexEntriesSince;
+my %IndexEntriesDeprecated;
 
 # Standard C preprocessor directives, which we ignore for '#' abbreviations.
-PreProcessorDirectives = {
-    'assert': 1,
-    'define': 1,
-    'elif': 1,
-    'else': 1,
-    'endif': 1,
-    'error': 1,
-    'if': 1,
-    'ifdef': 1,
-    'ifndef': 1,
-    'include': 1,
-    'line': 1,
-    'pragma': 1,
-    'unassert': 1,
-    'undef': 1,
-    'warning': 1
-}
+my %PreProcessorDirectives = (
+    'assert' => 1,
+    'define' => 1,
+    'elif' => 1,
+    'else' => 1,
+    'endif' => 1,
+    'error' => 1,
+    'if' => 1,
+    'ifdef' => 1,
+    'ifndef' => 1,
+    'include' => 1,
+    'line' => 1,
+    'pragma' => 1,
+    'unassert' => 1,
+    'undef' => 1,
+    'warning' => 1
+);
 
 # remember used annotation (to write minimal glossary)
-AnnotationsUsed = {}
+my %AnnotationsUsed;
 
 # the regexp that parses the annotation is in ScanSourceFile()
-AnnotationDefinition = {
+my %AnnotationDefinition = (
     # the GObjectIntrospection annotations are defined at:
     # https://live.gnome.org/GObjectIntrospection/Annotations
-    'allow-none': "NULL is OK, both for passing and for returning.",
-    'nullable': "NULL may be passed as the value in, out, in-out; or as a return value.",
-    'not nullable': "NULL must not be passed as the value in, out, in-out; or as a return value.",
-    'optional': "NULL may be passed instead of a pointer to a location.",
-    'array': "Parameter points to an array of items.",
-    'attribute': "Deprecated free-form custom annotation, replaced by (attributes) annotation.",
-    'attributes': "Free-form key-value pairs.",
-    'closure': "This parameter is a 'user_data', for callbacks; many bindings can pass NULL here.",
-    'constructor': "This symbol is a constructor, not a static method.",
-    'destroy': "This parameter is a 'destroy_data', for callbacks.",
-    'default': "Default parameter value (for in case the <acronym>shadows</acronym>-to function has less 
parameters).",
-    'element-type': "Generics and defining elements of containers and arrays.",
-    'error-domains': "Typed errors. Similar to throws in Java.",
-    'foreign': "This is a foreign struct.",
-    'get-value-func': "The specified function is used to convert a struct from a GValue, must be a 
GTypeInstance.",
-    'in': "Parameter for input. Default is <acronym>transfer none</acronym>.",
-    'inout': "Parameter for input and for returning results. Default is <acronym>transfer full</acronym>.",
-    'in-out': "Parameter for input and for returning results. Default is <acronym>transfer full</acronym>.",
-    'method': "This is a method",
-    'not-error': "A GError parameter is not to be handled like a normal GError.",
-    'out': "Parameter for returning results. Default is <acronym>transfer full</acronym>.",
-    'out caller-allocates': "Out parameter, where caller must allocate storage.",
-    'out callee-allocates': "Out parameter, where caller must allocate storage.",
-    'ref-func': "The specified function is used to ref a struct, must be a GTypeInstance.",
-    'rename-to': "Rename the original symbol's name to SYMBOL.",
-    'scope call': "The callback is valid only during the call to the method.",
-    'scope async': "The callback is valid until first called.",
-    'scope notified': "The callback is valid until the GDestroyNotify argument is called.",
-    'set-value-func': "The specified function is used to convert from a struct to a GValue, must be a 
GTypeInstance.",
-    'skip': "Exposed in C code, not necessarily available in other languages.",
-    'transfer container': "Free data container after the code is done.",
-    'transfer floating': "Alias for <acronym>transfer none</acronym>, used for objects with floating refs.",
-    'transfer full': "Free data after the code is done.",
-    'transfer none': "Don't free data after the code is done.",
-    'type': "Override the parsed C type with given type.",
-    'unref-func': "The specified function is used to unref a struct, must be a GTypeInstance.",
-    'virtual': "This is the invoker for a virtual method.",
-    'value': "The specified value overrides the evaluated value of the constant.",
+    'allow-none' => "NULL is OK, both for passing and for returning.",
+    'nullable' => "NULL may be passed as the value in, out, in-out; or as a return value.",
+    'not nullable' => "NULL must not be passed as the value in, out, in-out; or as a return value.",
+    'optional' => "NULL may be passed instead of a pointer to a location.",
+    'array' => "Parameter points to an array of items.",
+    'attribute' => "Deprecated free-form custom annotation, replaced by (attributes) annotation.",
+    'attributes' => "Free-form key-value pairs.",
+    'closure' => "This parameter is a 'user_data', for callbacks; many bindings can pass NULL here.",
+    'constructor' => "This symbol is a constructor, not a static method.",
+    'destroy' => "This parameter is a 'destroy_data', for callbacks.",
+    'default' => "Default parameter value (for in case the <acronym>shadows</acronym>-to function has less 
parameters).",
+    'element-type' => "Generics and defining elements of containers and arrays.",
+    'error-domains' => "Typed errors. Similar to throws in Java.",
+    'foreign' => "This is a foreign struct.",
+    'get-value-func' => "The specified function is used to convert a struct from a GValue, must be a 
GTypeInstance.",
+    'in' => "Parameter for input. Default is <acronym>transfer none</acronym>.",
+    'inout' => "Parameter for input and for returning results. Default is <acronym>transfer full</acronym>.",
+    'in-out' => "Parameter for input and for returning results. Default is <acronym>transfer 
full</acronym>.",
+    'method' => "This is a method",
+    'not-error' => "A GError parameter is not to be handled like a normal GError.",
+    'out' => "Parameter for returning results. Default is <acronym>transfer full</acronym>.",
+    'out caller-allocates' => "Out parameter, where caller must allocate storage.",
+    'out callee-allocates' => "Out parameter, where caller must allocate storage.",
+    'ref-func' => "The specified function is used to ref a struct, must be a GTypeInstance.",
+    'rename-to' => "Rename the original symbol's name to SYMBOL.",
+    'scope call' => "The callback is valid only during the call to the method.",
+    'scope async' => "The callback is valid until first called.",
+    'scope notified' => "The callback is valid until the GDestroyNotify argument is called.",
+    'set-value-func' => "The specified function is used to convert from a struct to a GValue, must be a 
GTypeInstance.",
+    'skip' => "Exposed in C code, not necessarily available in other languages.",
+    'transfer container' => "Free data container after the code is done.",
+    'transfer floating' => "Alias for <acronym>transfer none</acronym>, used for objects with floating 
refs.",
+    'transfer full' => "Free data after the code is done.",
+    'transfer none' => "Don't free data after the code is done.",
+    'type' => "Override the parsed C type with given type.",
+    'unref-func' => "The specified function is used to unref a struct, must be a GTypeInstance.",
+    'virtual' => "This is the invoker for a virtual method.",
+    'value' => "The specified value overrides the evaluated value of the constant.",
     # Stability Level definition
     # https://bugzilla.gnome.org/show_bug.cgi?id=170860
-    'Stable': '''
+    'Stable' => <<EOF,
 The intention of a Stable interface is to enable arbitrary third parties to
 develop applications to these interfaces, release them, and have confidence that
 they will run on all minor releases of the product (after the one in which the
 interface was introduced, and within the same major release). Even at a major
 release, incompatible changes are expected to be rare, and to have strong
 justifications.
-    ''',
-    'Unstable': '''
+EOF
+    'Unstable' => <<EOF,
 Unstable interfaces are experimental or transitional. They are typically used to
 give outside developers early access to new or rapidly changing technology, or
 to provide an interim solution to a problem where a more general solution is
@@ -220,143 +218,171 @@ Given such caveats, customer impact need not be a factor when considering
 incompatible changes to an Unstable interface in a major or minor release.
 Nonetheless, when such changes are introduced, the changes should still be
 mentioned in the release notes for the affected release.
-    ''',
-    'Private': '''
+EOF
+    'Private' => <<EOF
 An interface that can be used within the GNOME stack itself, but that is not
 documented for end-users.  Such functions should only be used in specified and
 documented ways.
-    ''',
-}
+EOF
+);
 
 # Elements to consider non-block items in MarkDown parsing
-MD_TEXT_LEVEL_ELEMENTS = {"literal": 1,
-                          "emphasis": 1,
-                          "envar": 1,
-                          "filename": 1,
-                          "firstterm": 1,
-                          "footnote": 1,
-                          "function": 1,
-                          "manvolnum": 1,
-                          "option": 1,
-                          "replaceable": 1,
-                          "structfield": 1,
-                          "structname": 1,
-                          "title": 1,
-                          "varname": 1,
-                         }
-MD_ESCAPABLE_CHARS = {"\\": 1,
-                      "`": 1,
-                      "*": 1,
-                      "_": 1,
-                      "{": 1,
-                      "}": 1,
-                      "[": 1,
-                      "]": 1,
-                      "(": 1,
-                      ")": 1,
-                      ">": 1,
-                      "#": 1,
-                      "+": 1,
-                      "-": 1,
-                      ".": 1,
-                      "!": 1,
-                     }
-MD_GTK_ESCAPABLE_CHARS = {"@": 1,
-                          "%": 1,
-                         }
+my %MD_TEXT_LEVEL_ELEMENTS = ( "literal" => 1,
+                               "emphasis" => 1,
+                               "envar" => 1,
+                               "filename" => 1,
+                               "firstterm" => 1,
+                               "footnote" => 1,
+                               "function" => 1,
+                               "manvolnum" => 1,
+                               "option" => 1,
+                               "replaceable" => 1,
+                               "structfield" => 1,
+                               "structname" => 1,
+                               "title" => 1,
+                               "varname" => 1 );
+my %MD_ESCAPABLE_CHARS = ( "\\" => 1,
+                           "`" => 1,
+                           "*" => 1,
+                           "_" => 1,
+                           "{" => 1,
+                           "}" => 1,
+                           "[" => 1,
+                           "]" => 1,
+                           "(" => 1,
+                           ")" => 1,
+                           ">" => 1,
+                           "#" => 1,
+                           "+" => 1,
+                           "-" => 1,
+                           "." => 1,
+                           "!" => 1 );
+my %MD_GTK_ESCAPABLE_CHARS = ( "@" => 1,
+                               "%" => 1 );
 
 # Function and other declaration output settings.
-RETURN_TYPE_FIELD_WIDTH = 20
-SYMBOL_FIELD_WIDTH = 36
-MAX_SYMBOL_FIELD_WIDTH = 40
-SIGNAL_FIELD_WIDTH = 16
-PARAM_FIELD_COUNT = 2
+my $RETURN_TYPE_FIELD_WIDTH = 20;
+my $SYMBOL_FIELD_WIDTH = 36;
+my $MAX_SYMBOL_FIELD_WIDTH = 40;
+my $SIGNAL_FIELD_WIDTH = 16;
+my $PARAM_FIELD_COUNT = 2;
 
 # XML, SGML formatting helper
-doctype_header = None
-
-
-parser = argparse.ArgumentParser()
-parser.add_argument('--module', default='')
-parser.add_argument('--source-dir', dest='source_dir', default='')
-parser.add_argument('--source-suffixes', dest='source_suffixes', default='')
-parser.add_argument('--ignore-files', dest='ignore_files', default='')
-parser.add_argument('--output-dir', dest='output_dir', default='')
-parser.add_argument('--tmpl-dir', dest='tmpl_dir', default='')
-parser.add_argument('--main-sgml-file', dest='main_sgml_file', default='')
-parser.add_argument('--expand-content-files', dest='expand_content_files', default='')
-group = parser.add_mutually_exclusive_group()
-group.add_argument('--sgml-mode', action='store_true', default=False, dest='sgml_mode')
-group.add_argument('--xml-mode', action='store_true', default=False, dest='xml_mode')
-parser.add_argument('--default-stability', dest='default_stability', choices=['Stable', 'Private', 
'Unstable'], default='Stable')
-parser.add_argument('--default-includes', dest='default_includes', default='')
-parser.add_argument('--output-format', dest='default_format', default='')
-parser.add_argument('--name-space', dest='name_space', default='')
-parser.add_argument('--outputallsymbols', default=False, action='store_true')
-parser.add_argument('--outputsymbolswithoutsince', default=False, action='store_true')
-
-
-def Run():
-    global MODULE, TMPL_DIR, SOURCE_DIRS, SOURCE_SUFFIXES, IGNORE_FILES, MAIN_SGML_FILE, 
EXPAND_CONTENT_FILES, \
-        INLINE_MARKUP_MODE, DEFAULT_STABILITY, DEFAULT_INCLUDES, OUTPUT_FORMAT, NAME_SPACE, 
OUTPUT_ALL_SYMBOLS, \
-        OUTPUT_SYMBOLS_WITHOUT_SINCE, DB_OUTPUT_DIR, OBJECT_TREE_FILE, INTERFACES_FILE, PREREQUISITES_FILE, \
-        SIGNALS_FILE, ARGS_FILE, doctype_header
-
-    options = parser.parse_args()
-
-    # We should pass the options variable around instead of this global variable horror
-    # but too much of the code expects these to be around. Fix this once the transition is done.
-    MODULE = options.module
-    TMPL_DIR = options.tmpl_dir
-    SOURCE_DIRS = options.source_dir
-    SOURCE_SUFFIXES = options.source_suffixes
-    IGNORE_FILES = options.ignore_files
-    MAIN_SGML_FILE = options.main_sgml_file
-    EXPAND_CONTENT_FILES = options.expand_content_files
-    INLINE_MARKUP_MODE = options.xml_mode or options.sgml_mode
-    DEFAULT_STABILITY = options.default_stability
-    DEFAULT_INCLUDES = options.default_includes
-    OUTPUT_FORMAT = options.default_format
-    NAME_SPACE = options.name_space
-    OUTPUT_ALL_SYMBOLS = options.outputallsymbols
-    OUTPUT_SYMBOLS_WITHOUT_SINCE = options.outputsymbolswithoutsince
-
-    logging.info(" ignore files: " + IGNORE_FILES)
+my $doctype_header;
+
+
+Run() unless caller; # Run program unless loaded as a module
+
+
+sub Run {
+    my %optctl = ('module' => \$MODULE,
+                  'source-dir' => \@SOURCE_DIRS,
+                  'source-suffixes' => \$SOURCE_SUFFIXES,
+                  'ignore-files' => \$IGNORE_FILES,
+                  'output-dir' => \$DB_OUTPUT_DIR,
+                  'tmpl-dir' => \$TMPL_DIR,
+                  'version' => \$PRINT_VERSION,
+                  'help' => \$PRINT_HELP,
+                  'main-sgml-file' => \$MAIN_SGML_FILE,
+                  'expand-content-files' => \$EXPAND_CONTENT_FILES,
+                  'sgml-mode' => \$INLINE_MARKUP_MODE,
+                  'xml-mode' => \$INLINE_MARKUP_MODE,
+                  'default-stability' => \$DEFAULT_STABILITY,
+                  'default-includes' => \$DEFAULT_INCLUDES,
+                  'output-format' => \$OUTPUT_FORMAT,
+                  'name-space' => \$NAME_SPACE,
+                  'outputallsymbols' => \$OUTPUT_ALL_SYMBOLS,
+                  'outputsymbolswithoutsince' => \$OUTPUT_SYMBOLS_WITHOUT_SINCE
+                  );
+    GetOptions(\%optctl, "module=s", "source-dir:s", "source-suffixes:s",
+        "ignore-files:s", "output-dir:s", "tmpl-dir:s", "version",
+        "outputallsymbols", "outputsymbolswithoutsince",
+        "expand-content-files:s", "main-sgml-file:s", "extra-db-files:s", "help",
+        "sgml-mode", "xml-mode", "default-stability:s", "default-includes:s",
+        "output-format:s", "name-space:s");
+
+    if ($PRINT_VERSION) {
+        print "@VERSION@\n";
+        exit 0;
+    }
+
+    if (!$MODULE) {
+        $PRINT_HELP = 1;
+    }
+
+    if ($DEFAULT_STABILITY && $DEFAULT_STABILITY ne "Stable"
+        && $DEFAULT_STABILITY ne "Private" && $DEFAULT_STABILITY ne "Unstable") {
+        $PRINT_HELP = 1;
+    }
+
+    if ($PRINT_HELP) {
+        print <<EOF;
+gtkdoc-mkdb version @VERSION@ - generate docbook files
+
+--module=MODULE_NAME       Name of the doc module being parsed
+--source-dir=DIRNAME       Directories which contain inline reference material
+--source-suffixes=SUFFIXES Suffixes of source files to scan, comma-separated
+--ignore-files=FILES       A space-separated list of header files/dirs not to
+                           scan
+--output-dir=DIRNAME       Directory to put the generated DocBook files in
+--tmpl-dir=DIRNAME         Directory in which template files may be found
+--main-sgml-file=FILE      File containing the toplevel DocBook file.
+--expand-content-files=FILES Extra DocBook files to expand abbreviations in.
+--output-format=FORMAT     Format to use for the generated docbook, XML or SGML.
+--{xml,sgml}-mode          Allow DocBook markup in inline documentation.
+--default-stability=LEVEL  Specify default stability Level. Valid values are
+                           Stable, Unstable, or Private.
+--default-includes=FILENAMES Specify default includes for section Synopsis
+--name-space=NS            Omit namespace in index.
+--version                  Print the version of this program
+--help                     Print this help
+EOF
+        exit 0;
+    }
+
+    @TRACE@(" ignore files: [$IGNORE_FILES]\n");
 
     # check output format
-    if OUTPUT_FORMAT is None or OUTPUT_FORMAT == '':
-        OUTPUT_FORMAT = "xml"
-    else:
-        OUTPUT_FORMAT = OUTPUT_FORMAT.lower()
-    if OUTPUT_FORMAT != "xml":
-        sys.exit("Invalid format '%s' passed to --output.format" % OUTPUT_FORMAT)
-
-    if not MAIN_SGML_FILE:
+    if (! defined($OUTPUT_FORMAT) || ($OUTPUT_FORMAT eq "")) {
+        $OUTPUT_FORMAT = "xml";
+    } else {
+        $OUTPUT_FORMAT = lc($OUTPUT_FORMAT);
+    }
+    if ($OUTPUT_FORMAT ne "xml") {
+        die "Invalid format '$OUTPUT_FORMAT' passed to --output.format"
+    }
+
+    if (!$MAIN_SGML_FILE) {
         # backwards compatibility
-        if os.path.exists(MODULE + "-docs.sgml"):
-            MAIN_SGML_FILE = MODULE + "-docs.sgml"
-        else:
-            MAIN_SGML_FILE = MODULE + "-docs.xml"
+        if (-e "${MODULE}-docs.sgml") {
+            $MAIN_SGML_FILE = "${MODULE}-docs.sgml";
+        } else {
+            $MAIN_SGML_FILE = "${MODULE}-docs.xml";
+        }
+    }
 
     # extract docbook header or define default
-    if os.path.exists(MAIN_SGML_FILE):
-        INPUT = open(MAIN_SGML_FILE)
-        doctype_header = ''
-        for line in INPUT:
-            if re.search(r'^\s*<(book|chapter|article)', line):
+    if (-e $MAIN_SGML_FILE) {
+        open(INPUT, "<$MAIN_SGML_FILE") || die "Can't open $MAIN_SGML_FILE";
+        $doctype_header = "";
+        while (<INPUT>) {
+            if (/^\s*<(book|chapter|article)/) {
                 # check that the top-level tagSYSTEM or the doctype decl contain the xinclude namespace decl
-                if not re.search(r'http:\/\/www.w3.org\/200[13]\/XInclude', line) and not 
re.search(r'http:\/\/www.w3.org\/200[13]\/XInclude', doctype_header, flags=re.MULTILINE):
-                    doctype_header = ''
-                break
-
+                if (($_ !~ m/http:\/\/www.w3.org\/200[13]\/XInclude/) && ($doctype_header !~ 
m/http:\/\/www.w3.org\/200[13]\/XInclude/m)) {
+                    $doctype_header = "";
+                }
+                last;
+            }
             # if there are SYSTEM ENTITIES here, we should prepend "../" to the path
             # FIXME: not sure if we can do this now, as people already work-around the problem
             # s#<!ENTITY % ([a-zA-Z-]+) SYSTEM \"([^/][a-zA-Z./]+)\">#<!ENTITY % $1 SYSTEM \"../$2\">#;
-            #<!ENTITY % gtkdocentities SYSTEM \"([^"]*)\">#<!ENTITY % gtkdocentities SYSTEM \"../$1\">#;
-            doctype_header += line
-        INPUT.close()
-    else:
-        doctype_header = '''<?xml version="1.0"?>
+            s#<!ENTITY % gtkdocentities SYSTEM \"([^"]*)\">#<!ENTITY % gtkdocentities SYSTEM \"../$1\">#;
+            $doctype_header .= $_;
+        }
+        close(INPUT);
+    } else {
+        $doctype_header = <<EOF;
+<?xml version="1.0"?>
 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
                "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd";
 [
@@ -364,112 +390,122 @@ def Run():
   <!ENTITY % gtkdocentities SYSTEM "../xml/gtkdocentities.ent">
   %gtkdocentities;
 ]>
-'''
-
-    doctype_header = doctype_header.strip()
+EOF
+    }
+    chomp($doctype_header);
 
     # All the files are written in subdirectories beneath here.
-    TMPL_DIR = TMPL_DIR if TMPL_DIR else os.path.join(ROOT_DIR, "tmpl")
+    $TMPL_DIR = $TMPL_DIR ? $TMPL_DIR : "$ROOT_DIR/tmpl";
 
     # This is where we put all the DocBook output.
-    DB_OUTPUT_DIR = DB_OUTPUT_DIR if DB_OUTPUT_DIR else os.path.join(ROOT_DIR, "xml")
+    $DB_OUTPUT_DIR = $DB_OUTPUT_DIR ? $DB_OUTPUT_DIR : "$ROOT_DIR/xml";
 
     # This file contains the object hierarchy.
-    OBJECT_TREE_FILE = os.path.join(ROOT_DIR, MODULE + ".hierarchy")
+    $OBJECT_TREE_FILE = "$ROOT_DIR/$MODULE.hierarchy";
 
     # This file contains the interfaces.
-    INTERFACES_FILE = os.path.join(ROOT_DIR, MODULE + ".interfaces")
+    $INTERFACES_FILE = "$ROOT_DIR/$MODULE.interfaces";
 
     # This file contains the prerequisites.
-    PREREQUISITES_FILE = os.path.join(ROOT_DIR, MODULE + ".prerequisites")
+    $PREREQUISITES_FILE = "$ROOT_DIR/$MODULE.prerequisites";
 
     # This file contains signal arguments and names.
-    SIGNALS_FILE = os.path.join(ROOT_DIR, MODULE + ".signals")
+    $SIGNALS_FILE = "$ROOT_DIR/$MODULE.signals";
 
     # The file containing Arg information.
-    ARGS_FILE = os.path.join(ROOT_DIR, MODULE + ".args")
+    $ARGS_FILE = "$ROOT_DIR/$MODULE.args";
 
     # Create the root DocBook output directory if it doens't exist.
-    if not os.path.isdir(DB_OUTPUT_DIR):
-        os.mkdir(DB_OUTPUT_DIR)
+    if (! -e $DB_OUTPUT_DIR) {
+        mkdir ("$DB_OUTPUT_DIR", 0777)
+            || die "Can't create directory: $DB_OUTPUT_DIR";
+    }
 
-    ReadKnownSymbols(os.path.join(ROOT_DIR, MODULE + "-sections.txt"))
-    ReadSignalsFile(SIGNALS_FILE)
-    ReadArgsFile(ARGS_FILE)
-    ReadObjectHierarchy()
-    ReadInterfaces()
-    ReadPrerequisites()
+    &ReadKnownSymbols ("$ROOT_DIR/$MODULE-sections.txt");
+    &ReadSignalsFile ($SIGNALS_FILE);
+    &ReadArgsFile ($ARGS_FILE);
+    &ReadObjectHierarchy;
+    &ReadInterfaces;
+    &ReadPrerequisites;
 
-    ReadDeclarationsFile(os.path.join(ROOT_DIR, MODULE + "-decl.txt"), 0)
-    if os.path.isfile(os.path.join(ROOT_DIR, MODULE + "-overrides.txt")):
-        ReadDeclarationsFile(os.path.join(ROOT_DIR, MODULE + "-overrides.txt"), 1)
+    &ReadDeclarationsFile ("$ROOT_DIR/$MODULE-decl.txt", 0);
+    if (-f "$ROOT_DIR/$MODULE-overrides.txt") {
+        &ReadDeclarationsFile ("$ROOT_DIR/$MODULE-overrides.txt", 1);
+    }
 
-    for sdir in SOURCE_DIRS:
-        ReadSourceDocumentation(sdir)
+    for my $dir (@SOURCE_DIRS) {
+        &ReadSourceDocumentation ($dir);
+    }
 
-    changed = OutputDB(os.path.join(ROOT_DIR, MODULE + "-sections.txt"))
+    my $changed = &OutputDB ("$ROOT_DIR/$MODULE-sections.txt");
 
     # If any of the DocBook files have changed, update the timestamp file (so
     # it can be used for Makefile dependencies).
-    if changed or not os.path.exists(os.path.join(ROOT_DIR, "sgml.stamp")):
+    if ($changed || ! -e "$ROOT_DIR/sgml.stamp") {
 
         # try to detect the common prefix
         # GtkWidget, GTK_WIDGET, gtk_widget -> gtk
-        if NAME_SPACE == '':
-            NAME_SPACE = ''
-            pos = 0
-            ratio = 0.0
-            while True:
-                prefix = {}
-                letter = ''
-                for symbol in IndexEntriesFull.keys():
-                    if NAME_SPACE == '' or NAME_SPACE.lower() in symbol.lower():
-                        if len(symbol) > pos:
-                            letter = symbol[pos:pos+1]
+        if ($NAME_SPACE eq "") {
+            $NAME_SPACE="";
+            my $pos=0;
+            my $ratio=0.0;
+            do {
+                my %prefix;
+                my $letter="";
+                foreach my $symbol (keys(%IndexEntriesFull)) {
+                    if(($NAME_SPACE eq "") || $symbol =~ /^$NAME_SPACE/i) {
+                        if (length($symbol)>$pos) {
+                            $letter=substr($symbol,$pos,1);
                             # stop prefix scanning
-                            if letter == "_":
+                            if ($letter eq "_") {
                                 # stop on "_"
-                                break
+                                last;
+                            }
                             # Should we also stop on a uppercase char, if last was lowercase
                             #   GtkWidget, if we have the 'W' and had the 't' before
                             # or should we count upper and lowercase, and stop one 2nd uppercase, if we 
already had a lowercase
                             #   GtkWidget, the 'W' would be the 2nd uppercase and with 't','k' we had 
lowercase chars before
                             # need to recound each time as this is per symbol
-                            ul = letter.upper()
-                            if ul in prefix:
-                                prefix[ul] += 1
-                            else:
-                                prefix[ul] = 1
-
-                if letter != '' and letter != "_":
-                    maxletter = ''
-                    maxsymbols = 0
-                    for letter in prefix.keys():
+                            $prefix{uc($letter)}++;
+                        }
+                    }
+                }
+                if ($letter ne "" && $letter ne "_") {
+                    my $maxletter="";
+                    my $maxsymbols=0;
+                    foreach $letter (keys(%prefix)) {
                         #print "$letter: $prefix{$letter}.\n";
-                        if prefix[letter] > maxsymbols:
-                            maxletter = letter
-                            maxsymbols = prefix[letter]
-
-                    ratio = float(len(IndexEntriesFull)) / prefix[maxletter]
+                        if ($prefix{$letter}>$maxsymbols) {
+                            $maxletter=$letter;
+                            $maxsymbols=$prefix{$letter};
+                        }
+                    }
+                    $ratio = scalar(keys(%IndexEntriesFull)) / $prefix{$maxletter};
                     #print "most symbols start with $maxletter, that is ". (100 * $ratio) ." %\n";
-                    if ratio > 0.9:
+                    if ($ratio > 0.9) {
                         # do another round
-                        NAME_SPACE += maxletter
-
-                    pos += 1
-
-                else:
-                    ratio = 0.0
-
-                if ratio > 0.9:
-                    break
-
-        OutputIndexFull()
-        OutputDeprecatedIndex()
-        OutputSinceIndexes()
-        OutputAnnotationGlossary()
-
-        open(os.path.join(ROOT_DIR, 'sgml.stamp'), 'w').write('timestamp')
+                        $NAME_SPACE .= $maxletter;
+                    }
+                    $pos++;
+                }
+                else {
+                    $ratio=0.0;
+                }
+            } while ($ratio > 0.9);
+            #print "most symbols start with $NAME_SPACE\n";
+        }
+
+        &OutputIndexFull;
+        &OutputDeprecatedIndex;
+        &OutputSinceIndexes;
+        &OutputAnnotationGlossary;
+
+        open (TIMESTAMP, ">$ROOT_DIR/sgml.stamp")
+            || die "Can't create $ROOT_DIR/sgml.stamp: $!";
+        print (TIMESTAMP "timestamp");
+        close (TIMESTAMP);
+    }
+}
 
 #############################################################################
 # Function    : OutputObjectList
@@ -480,50 +516,53 @@ def Run():
 # Arguments   : none
 #############################################################################
 
-def OutputObjectList():
-    cols = 3
+sub OutputObjectList {
+    my $cols = 3;
 
     # FIXME: use .xml
     # my $old_object_index = "$DB_OUTPUT_DIR/object_index.xml";
-    old_object_index = os.path.join(DB_OUTPUT_DIR, "object_index.sgml")
-    new_object_index = os.path.join(DB_OUTPUT_DIR, "object_index.new")
+    my $old_object_index = "$DB_OUTPUT_DIR/object_index.sgml";
+    my $new_object_index = "$DB_OUTPUT_DIR/object_index.new";
 
-    OUTPUT = open(new_object_index, 'w')
+    open (OUTPUT, ">$new_object_index")
+        || die "Can't create $new_object_index: $!";
 
-    OUTPUT.write('''
-%s
+    print (OUTPUT <<EOF);
+${\( MakeDocHeader ("informaltable") )}
 <informaltable pgwide="1" frame="none">
 <tgroup cols="$cols">
 <colspec colwidth="1*"/>
 <colspec colwidth="1*"/>
 <colspec colwidth="1*"/>
 <tbody>
-''' % MakeDocHeader("informaltable"))
-
-    count = 0
-    object = None
-    for object in sorted(Objects):
-        xref = MakeXRef(object)
-        if count % cols == 0:
-            OUTPUT.write("<row>\n")
-        OUTPUT.write("<entry>%s</entry>\n" % xref)
-        if count % cols == cols - 1:
-            OUTPUT.write("</row>\n")
-        count += 1
-
-    if count == 0:
+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++;
+    }
+    if ($count == 0) {
         # emit an empty row, since empty tables are invalid
-        OUTPUT.write("<row><entry> </entry></row>\n")
-
-    else:
-        if count % cols > 0:
-            OUTPUT.write("</row>\n")
-
-    OUTPUT.write('''</tbody></tgroup></informaltable>\n''')
-    OUTPUT.close()
-
-    common.UpdateFileIfChanged(old_object_index, new_object_index, 0)
-
+        print (OUTPUT "<row><entry> </entry></row>\n");
+    }
+    else {
+        if ($count % $cols > 0) {
+            print (OUTPUT "</row>\n");
+        }
+    }
+
+    print (OUTPUT <<EOF);
+</tbody></tgroup></informaltable>
+EOF
+    close (OUTPUT);
+
+    &UpdateFileIfChanged ($old_object_index, $new_object_index, 0);
+}
 
 #############################################################################
 # Function    : TrimTextBlock
@@ -532,13 +571,16 @@ def OutputObjectList():
 # Arguments   : $desc - the text block to trim. May contain newlines.
 #############################################################################
 
-def TrimTextBlock(desc):
-    # strip leading spaces on the block
-    desc = re.sub(r'^\s+', '', desc)
-    # strip trailing spaces on every line
-    desc = re.sub(r'\s+$', '\n', desc, flags=re.MULTILINE)
+sub TrimTextBlock {
+  my ($desc) = @_;
 
-    return desc
+  # strip leading spaces on the block
+  $desc =~ s/^\s+//s;
+  # strip trailing spaces on every line
+  $desc =~ s/\s+$/\n/mg;
+
+  return $desc;
+}
 
 
 #############################################################################
@@ -550,125 +592,125 @@ def TrimTextBlock(desc):
 #                into sections and subsections.
 #############################################################################
 
-def OutputDB(file):
-
-    logging.info("Reading: %s", file)
-    INPUT = open(file)
-    filename = ''
-    book_top = ''
-    book_bottom = ''
-    includes = DEFAULT_INCLUDES if DEFAULT_INCLUDES else ''
-    section_includes = ''
-    in_section = 0
-    title = ''
-    section_id = ''
-    subsection = ''
-    num_symbols = 0
-    changed = 0
-    functions_synop = ''
-    other_synop = ''
-    functions_details = ''
-    other_details = ''
-    signals_synop = ''
-    signals_desc = ''
-    args_synop = ''
-    child_args_synop = ''
-    style_args_synop = ''
-    args_desc = ''
-    child_args_desc = ''
-    style_args_desc = ''
-    hierarchy_str = ''
-    hierarchy = []
-    interfaces = ''
-    implementations = ''
-    prerequisites = ''
-    derived = ''
-    file_objects = []
-    templates = {}
-    symbol_def_line = {}
+sub OutputDB {
+    my ($file) = @_;
+
+    @TRACE@("Reading: $file\n");
+    open (INPUT, $file)
+        || die "Can't open $file: $!";
+    my $filename = "";
+    my $book_top = "";
+    my $book_bottom = "";
+    my $includes = (defined $DEFAULT_INCLUDES) ? $DEFAULT_INCLUDES : "";
+    my $section_includes = "";
+    my $in_section = 0;
+    my $title = "";
+    my $section_id = "";
+    my $subsection = "";
+    my $num_symbols;
+    my $changed = 0;
+    my $functions_synop = "";
+    my $other_synop = "";
+    my $functions_details = "";
+    my $other_details = "";
+    my $signals_synop = "";
+    my $signals_desc = "";
+    my $args_synop = "";
+    my $child_args_synop = "";
+    my $style_args_synop = "";
+    my $args_desc = "";
+    my $child_args_desc = "";
+    my $style_args_desc = "";
+    my $hierarchy_str = "";
+    my @hierarchy = ();
+    my $interfaces = "";
+    my $implementations = "";
+    my $prerequisites = "";
+    my $derived = "";
+    my @file_objects = ();
+    my %templates = ();
+    my %symbol_def_line = ();
 
     # merge the source docs, in case there are no templates
-    MergeSourceDocumentation()
-
-    line_number = 0
-    for line in INPUT:
-        line_number += 1
-
-        if line.strip() == '':
-            continue
-
-        m1 = re.search(r'^<SUBSECTION\s*(.*)', line)
-        m2 = re.search(r'^<TITLE>(.*)<\/TITLE', line)
-        m3 = re.search(r'^<FILE>(.*)<\/FILE>', line)
-        m4 = re.search(r'^<INCLUDE>(.*)<\/INCLUDE>', line)
-        m5 = re.search(r'^(\S+)', line)
-
-        if line.startswith('<SECTION>'):
-            num_symbols = 0
-            in_section = False
-            file_objects = []
-            symbol_def_line = {}
-
-        elif m1:
-            other_synop += "\n"
-            functions_synop += "\n"
-            subsection = m1.group(1)
-
-        elif re.search(r'^<SUBSECTION>', line):
-            pass
-        elif m2:
-            title = m2.group(1)
-            logging.info("Section: %s", title)
+    &MergeSourceDocumentation;
 
-            # We don't want warnings if object & class structs aren't used.
-            DeclarationOutput[title] = 1
-            DeclarationOutput["%sClass" % title] = 1
-            DeclarationOutput["%sIface" % title] = 1
-            DeclarationOutput["%sInterface" % title] = 1
-
-        elif m3:
-            filename = m3.group(1)
-            if filename in templates:
-                if ReadTemplateFile(os.path.join(TMPL_DIR, filename), 1):
-                    MergeSourceDocumentation()
-                    templates[filename] = line_number
-            else:
-                common.LogWarning(file, line_number, ("Double <FILE>%s</FILE> entry. " % file) + "Previous 
occurrence on line " + templates[filename] + ".")
-            if title == ''  and ("%s/%s:Title" % (TMPL_DIR, filename)) & SourceSymbolDocs:
-                title = SourceSymbolDocs["%s/%s:Title" % (TMPL_DIR, filename)]
-                 # Remove trailing blanks
-                title = title.rstrip()
-
-        elif m4:
-            if in_section:
-                section_includes = m4.group(1)
-            else:
-                if DEFAULT_INCLUDES:
-                    common.LogWarning(file, line_number, "Default <INCLUDE> being overridden by command line 
option.")
-                else:
-                    includes = m4.group(1)
-
-        elif re.search(r'^<\/SECTION>', line):
-            logging.info("End of section: $title\n")
-            if num_symbols > 0:
-                # collect documents
-                book_bottom += "    <xi:include href=\"xml/%s.xml\"/>\n" % filename
+    while (<INPUT>) {
+        if (m/^#/) {
+            next;
 
-                i = os.path.join(TMPL_DIR, filename + ":Include")
+        } elsif (m/^<SECTION>/) {
+            $num_symbols = 0;
+            $in_section = 1;
+            @file_objects = ();
+            %symbol_def_line = ();
 
-                if i in SourceSymbolDocs:
-                    if section_includes:
-                        common.LogWarning(file, line_number, "Section <INCLUDE> being overridden by inline 
comments.")
-                    section_includes = SourceSymbolDocs[i]
+        } elsif (m/^<SUBSECTION\s*(.*)>/i) {
+            $other_synop .= "\n";
+            $functions_synop .= "\n";
+            $subsection = $1;
 
-                if section_includes == '':
-                    section_includes = includes
+        } elsif (m/^<SUBSECTION>/) {
 
-                signals_synop = re.sub(r'^\n*', '', signals_synop)
-                signals_synop = re.sub(r'\n+$', '\n', signals_synop)
+        } elsif (m/^<TITLE>(.*)<\/TITLE>/) {
+            $title = $1;
+            @TRACE@("Section: $title\n");
 
-                if signals_synop != '':
-                    signals_synop = '''<refsect1 id="%s.signals" role="signal_proto">
+            # We don't want warnings if object & class structs aren't used.
+            $DeclarationOutput{$title} = 1;
+            $DeclarationOutput{"${title}Class"} = 1;
+            $DeclarationOutput{"${title}Iface"} = 1;
+            $DeclarationOutput{"${title}Interface"} = 1;
+
+        } elsif (m/^<FILE>(.*)<\/FILE>/) {
+            $filename = $1;
+            if (! defined $templates{$filename}) {
+               if (&ReadTemplateFile ("$TMPL_DIR/$filename", 1)) {
+                   &MergeSourceDocumentation;
+                   $templates{$filename}=$.;
+               }
+            } else {
+                &LogWarning ($file, $., "Double <FILE>$filename</FILE> entry. ".
+                    "Previous occurrence on line ".$templates{$filename}.".");
+            }
+            if (($title eq "") and (defined $SourceSymbolDocs{"$TMPL_DIR/$filename:Title"})) {
+                $title = $SourceSymbolDocs{"$TMPL_DIR/$filename:Title"};
+                 # Remove trailing blanks
+                $title =~ s/\s+$//;
+           }
+
+        } elsif (m/^<INCLUDE>(.*)<\/INCLUDE>/) {
+            if ($in_section) {
+                $section_includes = $1;
+            } else {
+                if (defined $DEFAULT_INCLUDES) {
+                    &LogWarning ($file, $., "Default <INCLUDE> being overridden by command line option.");
+                }
+                else {
+                    $includes = $1;
+                }
+            }
+
+        } elsif (m/^<\/SECTION>/) {
+            @TRACE@("End of section: $title\n");
+            if ($num_symbols > 0) {
+                # collect documents
+                $book_bottom .= "    <xi:include href=\"xml/$filename.xml\"/>\n";
+
+                if (defined ($SourceSymbolDocs{"$TMPL_DIR/$filename:Include"})) {
+                    if ($section_includes) {
+                        &LogWarning ($file, $., "Section <INCLUDE> being overridden by inline comments.");
+                    }
+                    $section_includes = $SourceSymbolDocs{"$TMPL_DIR/$filename:Include"};
+                }
+                if ($section_includes eq "") {
+                    $section_includes = $includes;
+                }
+
+                 $signals_synop =~ s/^\n*//g;
+                 $signals_synop =~ s/\n+$/\n/g;
+                if ($signals_synop ne '') {
+                    $signals_synop = <<EOF;
+<refsect1 id="$section_id.signals" role="signal_proto">
 <title role="signal_proto.title">Signals</title>
 <informaltable frame="none">
 <tgroup cols="3">
@@ -676,23 +718,26 @@ def OutputDB(file):
 <colspec colname="signals_name" colwidth="300px"/>
 <colspec colname="signals_flags" colwidth="200px"/>
 <tbody>
-%s
+${signals_synop}
 </tbody>
 </tgroup>
 </informaltable>
 </refsect1>
-''' % (section_id, signals_synop)
-                    signals_desc = TrimTextBlock(signals_desc)
-                    signals_desc = '''<refsect1 id="%s.signal-details" role="signals">
+EOF
+                     $signals_desc = TrimTextBlock($signals_desc);
+                    $signals_desc  = <<EOF;
+<refsect1 id="$section_id.signal-details" role="signals">
 <title role="signals.title">Signal Details</title>
-%s
+$signals_desc
 </refsect1>
-''' % (section_id, signals_desc)
-
-                args_synop = re.sub(r'^\n*', '', args_synop)
-                args_synop = re.sub(r'\n+$', '\n', args_synop)
-                if args_synop != '':
-                    args_synop = '''<refsect1 id="%s.properties" role="properties">
+EOF
+                }
+
+                $args_synop =~ s/^\n*//g;
+                $args_synop =~ s/\n+$/\n/g;
+                if ($args_synop ne '') {
+                    $args_synop = <<EOF;
+<refsect1 id="$section_id.properties" role="properties">
 <title role="properties.title">Properties</title>
 <informaltable frame="none">
 <tgroup cols="3">
@@ -700,23 +745,26 @@ def OutputDB(file):
 <colspec colname="properties_name" colwidth="300px"/>
 <colspec colname="properties_flags" colwidth="200px"/>
 <tbody>
-%s
+${args_synop}
 </tbody>
 </tgroup>
 </informaltable>
 </refsect1>
-''' %(section_id, args_synop)
-                    args_desc = TrimTextBlock(args_desc)
-                    args_desc = '''<refsect1 id="%s.property-details" role="property_details">
+EOF
+                     $args_desc = TrimTextBlock($args_desc);
+                    $args_desc  = <<EOF;
+<refsect1 id="$section_id.property-details" role="property_details">
 <title role="property_details.title">Property Details</title>
-%s
+$args_desc
 </refsect1>
-''' % (section_id, args_desc)
-
-                child_args_synop = re.sub(r'^\n*', '', child_args_synop)
-                child_args_synop = re.sub(r'\n+$', '\n', child_args_synop)
-                if child_args_synop != '':
-                    args_synop += '''<refsect1 id="%s.child-properties" role="child_properties">
+EOF
+                }
+
+                $child_args_synop =~ s/^\n*//g;
+                $child_args_synop =~ s/\n+$/\n/g;
+                if ($child_args_synop ne '') {
+                    $args_synop .= <<EOF;
+<refsect1 id="$section_id.child-properties" role="child_properties">
 <title role="child_properties.title">Child Properties</title>
 <informaltable frame="none">
 <tgroup cols="3">
@@ -724,24 +772,26 @@ def OutputDB(file):
 <colspec colname="child_properties_name" colwidth="300px"/>
 <colspec colname="child_properties_flags" colwidth="200px"/>
 <tbody>
-%s
+${child_args_synop}
 </tbody>
 </tgroup>
 </informaltable>
 </refsect1>
-''' % (section_id, child_args_synop)
-                    child_args_desc = TrimTextBlock(child_args_desc)
-                    args_desc += '''<refsect1 id="%s.child-property-details" role="child_property_details">
+EOF
+                     $child_args_desc = TrimTextBlock($child_args_desc);
+                     $args_desc .= <<EOF;
+<refsect1 id="$section_id.child-property-details" role="child_property_details">
 <title role="child_property_details.title">Child Property Details</title>
-%s
+$child_args_desc
 </refsect1>
-''' % (section_id, child_args_desc)
-
-
-                style_args_synop = re.sub(r'^\n*', '', style_args_synop)
-                style_args_synop = re.sub(r'\n+$', '\n', style_args_synop)
-                if style_args_synop != '':
-                    args_synop += '''<refsect1 id="%s.style-properties" role="style_properties">
+EOF
+                }
+
+                $style_args_synop =~ s/^\n*//g;
+                $style_args_synop =~ s/\n+$/\n/g;
+                if ($style_args_synop ne '') {
+                    $args_synop .= <<EOF;
+<refsect1 id="$section_id.style-properties" role="style_properties">
 <title role="style_properties.title">Style Properties</title>
 <informaltable frame="none">
 <tgroup cols="3">
@@ -749,239 +799,265 @@ def OutputDB(file):
 <colspec colname="style_properties_name" colwidth="300px"/>
 <colspec colname="style_properties_flags" colwidth="200px"/>
 <tbody>
-%s
+${style_args_synop}
 </tbody>
 </tgroup>
 </informaltable>
 </refsect1>
-''' % (section_id, style_args_synop)
-                    style_args_desc = TrimTextBlock(style_args_desc)
-                    args_desc += '''<refsect1 id="%s.style-property-details" role="style_properties_details">
+EOF
+                     $style_args_desc = TrimTextBlock($style_args_desc);
+                    $args_desc .= <<EOF;
+<refsect1 id="$section_id.style-property-details" role="style_properties_details">
 <title role="style_properties_details.title">Style Property Details</title>
-%s
+$style_args_desc
 </refsect1>
-''' % (section_id, style_args_desc)
+EOF
+                }
 
-                hierarchy_str = AddTreeLineArt(hierarchy)
-                if hierarchy_str != '':
-                    hierarchy_str = '''<refsect1 id="%s.object-hierarchy" role="object_hierarchy">
+                $hierarchy_str = &AddTreeLineArt(\@hierarchy);
+                if ($hierarchy_str ne "") {
+                    $hierarchy_str = <<EOF;
+<refsect1 id="$section_id.object-hierarchy" role="object_hierarchy">
 <title role="object_hierarchy.title">Object Hierarchy</title>
-<screen>%s
+<screen>$hierarchy_str
 </screen>
 </refsect1>
-''' % (section_id, hierarchy_str)
+EOF
+                }
 
-                interfaces = TrimTextBlock(interfaces)
-                if interfaces != '':
-                    interfaces = '''<refsect1 id="%s.implemented-interfaces" role="impl_interfaces">
+                 $interfaces =~ TrimTextBlock($interfaces);
+                if ($interfaces ne "") {
+                    $interfaces = <<EOF;
+<refsect1 id="$section_id.implemented-interfaces" role="impl_interfaces">
 <title role="impl_interfaces.title">Implemented Interfaces</title>
-%s
+$interfaces
 </refsect1>
-''' % (section_id, interfaces)
+EOF
+                }
 
-                implementations = TrimTextBlock(implementations)
-                if implementations != '':
-                    implementations = '''<refsect1 id="%s.implementations" role="implementations">
+                 $implementations = TrimTextBlock($implementations);
+                if ($implementations ne "") {
+                    $implementations = <<EOF;
+<refsect1 id="$section_id.implementations" role="implementations">
 <title role="implementations.title">Known Implementations</title>
-%s
+$implementations
 </refsect1>
-''' % (section_id, implementations)
+EOF
+                }
 
-                prerequisites = TrimTextBlock(prerequisites)
-                if prerequisites != '':
-                    prerequisites = '''<refsect1 id="%s.prerequisites" role="prerequisites">
+                 $prerequisites = TrimTextBlock($prerequisites);
+                if ($prerequisites ne "") {
+                    $prerequisites = <<EOF;
+<refsect1 id="$section_id.prerequisites" role="prerequisites">
 <title role="prerequisites.title">Prerequisites</title>
-%s
+$prerequisites
 </refsect1>
-''' % (section_id, prerequisites)
+EOF
+                }
 
-
-                derived = TrimTextBlock(derived)
-                if derived != '':
-                    derived = '''<refsect1 id="%s.derived-interfaces" role="derived_interfaces">
+                 $derived = TrimTextBlock($derived);
+                if ($derived ne "") {
+                    $derived = <<EOF;
+<refsect1 id="$section_id.derived-interfaces" role="derived_interfaces">
 <title role="derived_interfaces.title">Known Derived Interfaces</title>
-%s
+$derived
 </refsect1>
-''' % (section_id, derived)
-
-                functions_synop = re.sub(r'^\n*', '', functions_synop)
-                functions_synop = re.sub(r'\n+$', '\n', functions_synop)
-                if functions_synop != '':
-                    functions_synop = '''<refsect1 id="%s.functions" role="functions_proto">
+EOF
+                }
+
+                $functions_synop =~ s/^\n*//g;
+                $functions_synop =~ s/\n+$/\n/g;
+                if ($functions_synop ne '') {
+                  $functions_synop = <<EOF;
+<refsect1 id="$section_id.functions" role="functions_proto">
 <title role="functions_proto.title">Functions</title>
 <informaltable pgwide="1" frame="none">
 <tgroup cols="2">
 <colspec colname="functions_return" colwidth="150px"/>
 <colspec colname="functions_name"/>
 <tbody>
-%s
+${functions_synop}
 </tbody>
 </tgroup>
 </informaltable>
 </refsect1>
-''' % (section_id, functions_synop)
-
-                other_synop = re.sub(r'^\n*', '', other_synop)
-                other_synop = re.sub(r'\n+$', '\n', other_synop)
-                if other_synop != '':
-                    other_synop = '''<refsect1 id="%s.other" role="other_proto">
+EOF
+                }
+
+                $other_synop =~ s/^\n*//g;
+                $other_synop =~ s/\n+$/\n/g;
+                if ($other_synop ne '') {
+                  $other_synop = <<EOF;
+<refsect1 id="$section_id.other" role="other_proto">
 <title role="other_proto.title">Types and Values</title>
 <informaltable role="enum_members_table" pgwide="1" frame="none">
 <tgroup cols="2">
 <colspec colname="name" colwidth="150px"/>
 <colspec colname="description"/>
 <tbody>
-%s
+${other_synop}
 </tbody>
 </tgroup>
 </informaltable>
 </refsect1>
-''' % (section_id, other_synop)
-
-                file_changed = OutputDBFile(filename, title, section_id,
-                                            section_includes,
-                                            functions_synop, other_synop,
-                                            functions_details, other_details,
-                                            signals_synop, signals_desc,
-                                            args_synop, args_desc,
-                                            hierarchy_str, interfaces,
-                                            implementations,
-                                            prerequisites, derived,
-                                            file_objects)
-                if file_changed:
-                    changed = True
-
-            title = ''
-            section_id = ''
-            subsection = ''
-            in_section = 0
-            section_includes = ''
-            functions_synop = ''
-            other_synop = ''
-            functions_details = ''
-            other_details = ''
-            signals_synop = ''
-            signals_desc = ''
-            args_synop = ''
-            child_args_synop = ''
-            style_args_synop = ''
-            args_desc = ''
-            child_args_desc = ''
-            style_args_desc = ''
-            hierarchy_str = ''
-            hierarchy = []
-            interfaces = ''
-            implementations = ''
-            prerequisites = ''
-            derived = ''
-
-        elif m5:
-            symbol = m5.group(1)
-            logging.info("  Symbol: %s in subsection: %s", symbol, subsection)
+EOF
+                }
+
+                my $file_changed = &OutputDBFile ($filename, $title, $section_id,
+                                                    $section_includes,
+                                                    \$functions_synop, \$other_synop,
+                                                    \$functions_details, \$other_details,
+                                                    \$signals_synop, \$signals_desc,
+                                                    \$args_synop, \$args_desc,
+                                                    \$hierarchy_str, \$interfaces,
+                                                    \$implementations,
+                                                    \$prerequisites, \$derived,
+                                                    \@file_objects);
+                if ($file_changed) {
+                    $changed = 1;
+                }
+            }
+            $title = "";
+            $section_id = "";
+            $subsection = "";
+            $in_section = 0;
+            $section_includes = "";
+            $functions_synop = "";
+            $other_synop = "";
+            $functions_details = "";
+            $other_details = "";
+            $signals_synop = "";
+            $signals_desc = "";
+            $args_synop = "";
+            $child_args_synop = "";
+            $style_args_synop = "";
+            $args_desc = "";
+            $child_args_desc = "";
+            $style_args_desc = "";
+            $hierarchy_str = "";
+            @hierarchy = ();
+            $interfaces = "";
+            $implementations = "";
+            $prerequisites = "";
+            $derived = "";
+
+        } elsif (m/^(\S+)/) {
+            my $symbol = $1;
+            @TRACE@("  Symbol: $symbol in subsection: $subsection\n");
 
             # check for duplicate entries
-            if symbol in symbol_def_line:
-                declaration = Declarations.get(symbol, None)
-                if declaration:
-                    if CheckIsObject(symbol):
-                        file_objects.append(symbol)
-
+            if (! defined $symbol_def_line{$symbol}) {
+                my $declaration = $Declarations{$symbol};
+                if (defined ($declaration)) {
+                    if (&CheckIsObject ($symbol)) {
+                        push @file_objects, $symbol;
+                    }
                     # We don't want standard macros/functions of GObjects,
                     # or private declarations.
-                    if subsection != "Standard" and subsection != "Private":
-                        synop, desc = OutputDeclaration(symbol, declaration)
-                        type = DeclarationTypes[symbol]
-
-                        if type == 'FUNCTION' or type == 'USER_FUNCTION':
-                            functions_synop += synop
-                            functions_details += desc
-                        elif type == 'MACRO' and re.search(symbol + r'\(', declaration):
-                            functions_synop += synop
-                            functions_details += desc
-                        else:
-                            other_synop += synop
-                            other_details += +desc
-
-                    sig_synop, sig_desc = GetSignals(symbol)
-                    arg_synop, child_arg_synop, style_arg_synop, arg_desc, child_arg_desc, style_arg_desc = 
GetArgs(symbol)
-                    ifaces = GetInterfaces(symbol)
-                    impls = GetImplementations(symbol)
-                    prereqs = GetPrerequisites(symbol)
-                    der = GetDerived(symbol)
-                    hierarchy = GetHierarchy(symbol, hierarchy)
-
-                    signals_synop += sig_synop
-                    signals_desc += sig_desc
-                    args_synop += arg_synop
-                    child_args_synop += child_arg_synop
-                    style_args_synop += style_arg_synop
-                    args_desc += arg_desc
-                    child_args_desc += child_arg_desc
-                    style_args_desc += style_arg_desc
-                    interfaces += ifaces
-                    implementations += impls
-                    prerequisites += prereqs
-                    derived += der
+                    if ($subsection ne "Standard" && $subsection ne "Private") {
+                        my ($synop, $desc) = &OutputDeclaration ($symbol,
+                                                                 $declaration);
+                        my $type = $DeclarationTypes {$symbol};
+
+                        if ($type eq 'FUNCTION' || $type eq 'USER_FUNCTION') {
+                          $functions_synop .= $synop;
+                          $functions_details .= $desc;
+                        } elsif ($type eq 'MACRO' && $declaration =~ /$symbol\(/) {
+                          $functions_synop .= $synop;
+                          $functions_details .= $desc;
+                        } else {
+                          $other_synop .= $synop;
+                          $other_details .= $desc;
+                        }
+                    }
+                    my ($sig_synop, $sig_desc) = &GetSignals ($symbol);
+                    my ($arg_synop, $child_arg_synop, $style_arg_synop,
+                        $arg_desc, $child_arg_desc, $style_arg_desc) = &GetArgs ($symbol);
+                    my $ifaces = &GetInterfaces ($symbol);
+                    my $impls = &GetImplementations ($symbol);
+                    my $prereqs = &GetPrerequisites ($symbol);
+                    my $der = &GetDerived ($symbol);
+                    @hierarchy = &GetHierarchy ($symbol, \@hierarchy);
+
+                    $signals_synop .= $sig_synop;
+                    $signals_desc .= $sig_desc;
+                    $args_synop .= $arg_synop;
+                    $child_args_synop .= $child_arg_synop;
+                    $style_args_synop .= $style_arg_synop;
+                    $args_desc .= $arg_desc;
+                    $child_args_desc .= $child_arg_desc;
+                    $style_args_desc .= $style_arg_desc;
+                    $interfaces .= $ifaces;
+                    $implementations .= $impls;
+                    $prerequisites .= $prereqs;
+                    $derived .= $der;
 
                     # Note that the declaration has been output.
-                    DeclarationOutput[symbol] = True
-                elif subsection != "Standard" and subsection != "Private":
-                    UndeclaredSymbols[symbol] = True
-                    common.LogWarning(file, line_number, "No declaration found for %s." % symbol)
-
-                num_symbols += 1
-                symbol_def_line[symbol] = line_number
-
-                if section_id == '':
-                    if title == '' and filename == '':
-                        common.LogWarning(file, line_number, "Section has no title and no file.")
-
+                    $DeclarationOutput{$symbol} = 1;
+                } elsif ($subsection ne "Standard" && $subsection ne "Private") {
+                    $UndeclaredSymbols{$symbol} = 1;
+                    &LogWarning ($file, $., "No declaration found for $symbol.");
+                }
+                $num_symbols++;
+                $symbol_def_line{$symbol}=$.;
+
+                if ($section_id eq "") {
+                    if($title eq "" && $filename eq "") {
+                        &LogWarning ($file, $., "Section has no title and no file.");
+                    }
                     # FIXME: one of those would be enough
                     # filename should be an internal detail for gtk-doc
-                    if title == '':
-                        title = filename
-                    elif filename == '':
-                        filename = title
-
-                    filename = filename.replace(' ', '_')
+                    if ($title eq "") {
+                        $title = $filename;
+                    } elsif ($filename eq "") {
+                        $filename = $title;
+                    }
+                    $filename =~ s/\s/_/g;
 
-                    section_id = SourceSymbolDocs[os.path.join(TMPL_DIR, filename + ":Section_Id")]
-                    if section_id and section_id.strip() != '':
+                    $section_id = $SourceSymbolDocs{"$TMPL_DIR/$filename:Section_Id"};
+                    if (defined ($section_id) && $section_id !~ m/^\s*$/) {
                         # Remove trailing blanks and use as is
-                        section_id = section_id.rstrip()
-                    elif CheckIsObject(title):
+                        $section_id =~ s/\s+$//;
+                    } elsif (&CheckIsObject ($title)) {
                         # GObjects use their class name as the ID.
-                        section_id = common.CreateValidSGMLID(title)
-                    else:
-                        section_id = common.CreateValidSGMLID(MODULE + '-' + title)
-
-                SymbolSection[symbol] = title
-                SymbolSectionId[symbol] = section_id
-
-            else:
-                common.LogWarning(file, line_number, "Double symbol entry for %s. "
-                                  "Previous occurrence on line %d." % (symbol, symbol_def_line[symbol]))
-    INPUT.close()
-
-    OutputMissingDocumentation()
-    OutputUndeclaredSymbols()
-    OutputUnusedSymbols()
-
-    if OUTPUT_ALL_SYMBOLS:
-        OutputAllSymbols()
-
-    if OUTPUT_SYMBOLS_WITHOUT_SINCE:
-        OutputSymbolsWithoutSince()
-
-
-    for filename in EXPAND_CONTENT_FILES.split():
-        file_changed = OutputExtraFile(filename)
-        if file_changed:
-            changed = True
-
-    OutputBook(book_top, book_bottom)
-
-    return changed
+                        $section_id = &CreateValidSGMLID ($title);
+                    } else {
+                        $section_id = &CreateValidSGMLID ("$MODULE-$title");
+                    }
+                }
+                $SymbolSection{$symbol}=$title;
+                $SymbolSectionId{$symbol}=$section_id;
+            }
+            else {
+                &LogWarning ($file, $., "Double symbol entry for $symbol. ".
+                    "Previous occurrence on line ".$symbol_def_line{$symbol}.".");
+            }
+        }
+    }
+    close (INPUT);
+
+    &OutputMissingDocumentation;
+    &OutputUndeclaredSymbols;
+    &OutputUnusedSymbols;
+
+    if ($OUTPUT_ALL_SYMBOLS) {
+        &OutputAllSymbols;
+    }
+    if ($OUTPUT_SYMBOLS_WITHOUT_SINCE) {
+        &OutputSymbolsWithoutSince;
+    }
+
+    for $filename (split (' ', $EXPAND_CONTENT_FILES)) {
+        my $file_changed = &OutputExtraFile ($filename);
+        if ($file_changed) {
+            $changed = 1;
+        }
+    }
+
+    &OutputBook ($book_top, $book_bottom);
+
+    return $changed;
+}
 
 #############################################################################
 # Function    : OutputIndex
@@ -989,110 +1065,120 @@ def OutputDB(file):
 #               document into an <index> tag.
 #############################################################################
 
-def OutputIndex(basename, apiindexref):
-    apiindex = apiindexref # FIXME should we copy here?
-    old_index = os.path.join(DB_OUTPUT_DIR, basename + '.xml')
-    new_index = os.path.join(DB_OUTPUT_DIR, basename + '.new')
-    lastletter = " "
-    divopen = 0
-    symbol = None
-    short_symbol = None
+sub OutputIndex {
+    my ($basename, $apiindexref ) = @_;
+    my %apiindex = %{$apiindexref};
+    my $old_index = "$DB_OUTPUT_DIR/$basename.xml";
+    my $new_index = "$DB_OUTPUT_DIR/$basename.new";
+    my $lastletter = " ";
+    my $divopen = 0;
+    my $symbol;
+    my $short_symbol;
 
-    OUTPUT = open(new_index, 'w')
+    open (OUTPUT, ">$new_index")
+        || die "Can't create $new_index";
 
-    OUTPUT.write(MakeDocHeader("indexdiv") + "\n<indexdiv id=\"%s\">\n" % basename)
+    print (OUTPUT &MakeDocHeader ("indexdiv")."\n<indexdiv id=\"$basename\">\n");
 
-    logging.info("generate %s index (%d entries)\n", basename, len(apiindex))
+    @TRACE@("generate $basename index (".%apiindex." entries)\n");
 
     # do a case insensitive sort while chopping off the prefix
-    def cpmfunc(intxt):
-        uc = intxt.upper()
-        criteria = re.sub(r'^' + NAME_SPACE + r'\_?(.*)', r'\1', uc, flags=re.I)
-        return (criteria, intxt)
-
-    sorted_keys = sorted(apiindex.keys(), key=cpmfunc)
-
-    for original in sorted_keys:
-        symbol = apiindex[original]
-        match = re.search(r'^' + NAME_SPACE + r'\_?(.*)', original, flags=re.I)
-        short = match.group(1)
-        if short and short != '':
-            short_symbol = short
-        else:
-            short_symbol = symbol
+    foreach my $hash (
+        sort { $$a{criteria} cmp $$b{criteria} or $$a{original} cmp $$b{original} }
+        map { my $x = uc($_); $x =~ s/^$NAME_SPACE\_?(.*)/$1/i; { criteria => $x, original => $_, short => 
$1 } }
+        keys %apiindex) {
+
+        $symbol = $$hash{original};
+        if (defined($$hash{short}) && $$hash{short} ne "") {
+            $short_symbol = $$hash{short};
+        } else {
+            $short_symbol = $symbol;
+        }
 
         # generate a short symbol description
-        symbol_desc = ''
-        symbol_section = ''
-        symbol_section_id = ''
-        symbol_type = ''
-        if symbol in DeclarationTypes:
-            symbol_type = DeclarationTypes[symbol].lower()
-
-        if symbol_type == '':
-            logging.info("trying symbol %s\n", symbol)
-            m = re.search(r'(.*)::(.*)', symbol)
-            m2 = re.search(r'(.*):(.*)/', symbol)
-            if m:
-                oname = m.group(1)
-                osym = m.group(2)
-                i = None
-                logging.info("  trying object signal %s:%s in %d signals\n", oname, osym, len(SignalNames))
-                for i in range(len(SignalNames)):
-                    if SignalNames[i] == osym:
-                        symbol_type = "object signal"
-                        if oname in SymbolSection:
-                            symbol_section = SymbolSection[oname]
-                            symbol_section_id = SymbolSectionId[oname]
-                        break
-            elif m2:
-                oname = m2.group(1)
-                osym = m2.group(2)
-                i = None
-                logging.info("  trying object property %s::%s in %d properties\n", oname, osym, 
len(ArgNames))
-                for i in range(len(ArgNames)):
-                    logging.info("    " + ArgNames[i] + "\n")
-                    if ArgNames[i] == osym:
-                        symbol_type = "object property"
-                        if oname in SymbolSection:
-                            symbol_section = SymbolSection[oname]
-                            symbol_section_id = SymbolSectionId[oname]
-                        break
-        else:
-            if symbol in SymbolSection:
-                symbol_section = SymbolSection[symbol]
-                symbol_section_id = SymbolSectionId[symbol]
-
-        if symbol_type != '':
-            symbol_desc = ", " + symbol_type
-            if symbol_section != '':
-                symbol_desc += " in <link linkend=\"%s\">%s</link>" % (symbol_section_id, symbol_section)
-                #$symbol_desc.=" in ". &ExpandAbbreviations($symbol, "#$symbol_section")
-
-        curletter = short_symbol[0].upper()
-        id = apiindex[symbol]
-
-        logging.info("  add symbol %s with %d to index in section '%s' (derived from %s)\n", symbol, id, 
curletter, short_symbol)
-
-        if curletter != lastletter:
-            lastletter = curletter
-
-            if divopen:
-                OUTPUT.write("</indexdiv>\n")
-
-            OUTPUT.write("<indexdiv><title>$curletter</title>\n")
-            divopen = True
-
-        OUTPUT.write('<indexentry><primaryie linkends="$id"><link 
linkend="$id">$symbol</link>$symbol_desc</primaryie></indexentry>\n')
-
-    if divopen:
-        OUTPUT.write("</indexdiv>\n")
-
-    OUTPUT.write("</indexdiv>\n")
-    OUTPUT.close()
-
-    common.UpdateFileIfChanged(old_index, new_index, 0)
-
+        my $symbol_desc = "";
+        my $symbol_section = "";
+        my $symbol_section_id = "";
+        my $symbol_type = "";
+        if (defined($DeclarationTypes{$symbol})) {
+          $symbol_type = lc($DeclarationTypes{$symbol});
+        }
+        if ($symbol_type eq "") {
+            @TRACE@("trying symbol $symbol\n");
+            if ($symbol =~ m/(.*)::(.*)/) {
+                my $oname = $1;
+                my $osym = $2;
+                my $i;
+                @TRACE@("  trying object signal ${oname}:$osym in ".$#SignalNames." signals\n");
+                for ($i = 0; $i <= $#SignalNames; $i++) {
+                    if ($SignalNames[$i] eq $osym) {
+                        $symbol_type = "object signal";
+                        if (defined($SymbolSection{$oname})) {
+                           $symbol_section = $SymbolSection{$oname};
+                           $symbol_section_id = $SymbolSectionId{$oname};
+                        }
+                        last;
+                    }
+                }
+            } elsif ($symbol =~ m/(.*):(.*)/) {
+                my $oname = $1;
+                my $osym = $2;
+                my $i;
+                @TRACE@("  trying object property ${oname}::$osym in ".$#ArgNames." properties\n");
+                for ($i = 0; $i <= $#ArgNames; $i++) {
+                    @TRACE@("    ".$ArgNames[$i]."\n");
+                    if ($ArgNames[$i] eq $osym) {
+                        $symbol_type = "object property";
+                        if (defined($SymbolSection{$oname})) {
+                           $symbol_section = $SymbolSection{$oname};
+                           $symbol_section_id = $SymbolSectionId{$oname};
+                        }
+                        last;
+                    }
+                }
+            }
+        } else {
+           if (defined($SymbolSection{$symbol})) {
+               $symbol_section = $SymbolSection{$symbol};
+               $symbol_section_id = $SymbolSectionId{$symbol};
+           }
+        }
+        if ($symbol_type ne "") {
+           $symbol_desc=", $symbol_type";
+           if ($symbol_section ne "") {
+               $symbol_desc.=" in <link linkend=\"$symbol_section_id\">$symbol_section</link>";
+               #$symbol_desc.=" in ". &ExpandAbbreviations($symbol, "#$symbol_section");
+           }
+        }
+
+        my $curletter = uc(substr($short_symbol,0,1));
+        my $id = $apiindex{$symbol};
+
+        @TRACE@("  add symbol $symbol with $id to index in section '$curletter' (derived from 
$short_symbol)\n");
+
+        if ($curletter ne $lastletter) {
+            $lastletter = $curletter;
+
+            if ($divopen == 1) {
+                print (OUTPUT "</indexdiv>\n");
+            }
+            print (OUTPUT "<indexdiv><title>$curletter</title>\n");
+            $divopen = 1;
+        }
+
+        print (OUTPUT <<EOF);
+<indexentry><primaryie linkends="$id"><link linkend="$id">$symbol</link>$symbol_desc</primaryie></indexentry>
+EOF
+    }
+
+    if ($divopen == 1) {
+        print (OUTPUT "</indexdiv>\n");
+    }
+    print (OUTPUT "</indexdiv>\n");
+    close (OUTPUT);
+
+    &UpdateFileIfChanged ($old_index, $new_index, 0);
+}
 
 
 #############################################################################
@@ -1101,8 +1187,9 @@ def OutputIndex(basename, apiindexref):
 #               main document into an <index> tag.
 #############################################################################
 
-def OutputIndexFull():
-    OutputIndex("api-index-full", IndexEntriesFull)
+sub OutputIndexFull {
+    &OutputIndex ("api-index-full", \%IndexEntriesFull);
+}
 
 
 #############################################################################
@@ -1111,8 +1198,9 @@ def OutputIndexFull():
 #               into the main document into an <index> tag.
 #############################################################################
 
-def OutputDeprecatedIndex():
-    OutputIndex("api-index-deprecated", IndexEntriesDeprecated)
+sub OutputDeprecatedIndex {
+    &OutputIndex ("api-index-deprecated", \%IndexEntriesDeprecated);
+}
 
 
 #############################################################################
@@ -1121,19 +1209,18 @@ def OutputDeprecatedIndex():
 #               the main document into an <index> tag.
 #############################################################################
 
-def OutputSinceIndexes():
-    raise RuntimeError('I have no idea what this does.')
-#    my @sinces = keys %{{ map { $_ => 1 } values %Since }
-#
-#    foreach my $version (@sinces)
-#        logging.info("Since : [$version]\n")
-#        # TODO make filtered hash
-#        #my %index = grep { $Since{$_} == $version } %IndexEntriesSince
-#        my %index = map { $_ => $IndexEntriesSince{$_} } grep { $Since{$_} == $version } keys 
%IndexEntriesSince
-#
-#        &OutputIndex ("api-index-$version", \%index)
+sub OutputSinceIndexes {
+    my @sinces = keys %{{ map { $_ => 1 } values %Since }};
 
+    foreach my $version (@sinces) {
+        @TRACE@("Since : [$version]\n");
+        # TODO make filtered hash
+        #my %index = grep { $Since{$_} eq $version } %IndexEntriesSince;
+        my %index = map { $_ => $IndexEntriesSince{$_} } grep { $Since{$_} eq $version } keys 
%IndexEntriesSince;
 
+        &OutputIndex ("api-index-$version", \%index);
+    }
+}
 
 #############################################################################
 # Function    : OutputAnnotationGlossary
@@ -1142,64 +1229,70 @@ def OutputSinceIndexes():
 #               document.
 #############################################################################
 
-def OutputAnnotationGlossary():
-    old_glossary = os.path.join(DB_OUTPUT_DIR, "annotation-glossary.xml")
-    new_glossary = os.path.join(DB_OUTPUT_DIR, "annotation-glossary.new")
-    lastletter = " "
-    divopen = False
+sub OutputAnnotationGlossary {
+    my $old_glossary = "$DB_OUTPUT_DIR/annotation-glossary.xml";
+    my $new_glossary = "$DB_OUTPUT_DIR/annotation-glossary.new";
+    my $lastletter = " ";
+    my $divopen = 0;
 
     # if there are no annotations used return
-    if len(AnnotationsUsed) == 0:
-        return
+    return if (! keys(%AnnotationsUsed));
 
     # add acronyms that are referenced from acronym text
-#rerun:
-    for annotation in AnnotationsUsed:
-        if annotation in AnnotationDefinition:
-            m = re.search(r'<acronym>([\w ]+)<\/acronym>', AnnotationDefinition[annotation])
-            if m:
-                if m.group(1) in AnnotationsUsed:
-                    AnnotationsUsed[m.group(1)] = 1
-                    return OutputAnnotationGlossary()
-
-    OUTPUT = open(new_glossary, 'w')
-
-    OUTPUT.write('''%s
+rerun:
+    foreach my $annotation (keys(%AnnotationsUsed)) {
+        if(defined($AnnotationDefinition{$annotation})) {
+            if($AnnotationDefinition{$annotation} =~ m/<acronym>([\w ]+)<\/acronym>/) {
+                if (!exists($AnnotationsUsed{$1})) {
+                    $AnnotationsUsed{$1} = 1;
+                    goto rerun;
+                }
+            }
+        }
+    }
+
+    open (OUTPUT, ">$new_glossary")
+        || die "Can't create $new_glossary";
+
+    print (OUTPUT  <<EOF);
+${\( MakeDocHeader ("glossary") )}
 <glossary id="annotation-glossary">
   <title>Annotation Glossary</title>
-''' % MakeDocHeader("glossary"))
-
-    for annotation in sorted(AnnotationsUsed.keys(), keys=str.lower()):
-        if annotation in AnnotationDefinition:
-            defi = AnnotationDefinition[annotation]
-            curletter = annotation[0].upper()
-
-            if curletter != lastletter:
-                lastletter = curletter
-
-                if divopen:
-                    OUTPUT.write("</glossdiv>\n")
-
-                OUTPUT.write("<glossdiv><title>%s</title>\n" % curletter)
-                divopen = True
-
-            OUTPUT.write('''
+EOF
+
+    foreach my $annotation (sort({lc $a cmp lc $b} keys(%AnnotationsUsed))) {
+        if(defined($AnnotationDefinition{$annotation})) {
+            my $def = $AnnotationDefinition{$annotation};
+            my $curletter = uc(substr($annotation,0,1));
+
+            if ($curletter ne $lastletter) {
+                $lastletter = $curletter;
+
+                if ($divopen == 1) {
+                    print (OUTPUT "</glossdiv>\n");
+                }
+                print (OUTPUT "<glossdiv><title>$curletter</title>\n");
+                $divopen = 1;
+            }
+            print (OUTPUT <<EOF);
     <glossentry>
-      <glossterm><anchor id="annotation-glossterm-%s"/>%s</glossterm>
+      <glossterm><anchor id="annotation-glossterm-$annotation"/>$annotation</glossterm>
       <glossdef>
-        <para>%s</para>
+        <para>$def</para>
       </glossdef>
     </glossentry>
-''' % (annotation, annotation, defi))
-
-    if divopen:
-        OUTPUT.write("</glossdiv>\n")
+EOF
+        }
+    }
 
-    OUTPUT.write("</glossary>\n")
-    OUTPUT.close()
-
-    common.UpdateFileIfChanged(old_glossary, new_glossary, 0)
+    if ($divopen == 1) {
+        print (OUTPUT "</glossdiv>\n");
+    }
+    print (OUTPUT "</glossary>\n");
+    close (OUTPUT);
 
+    &UpdateFileIfChanged ($old_glossary, $new_glossary, 0);
+}
 
 #############################################################################
 # Function    : ReadKnownSymbols
@@ -1210,56 +1303,56 @@ def OutputAnnotationGlossary():
 #                into sections and subsections.
 #############################################################################
 
-def ReadKnownSymbols(file):
+sub ReadKnownSymbols {
+    my ($file) = @_;
 
-    subsection = ''
+    my $subsection = "";
 
-    logging.info("Reading: %s", file)
-    INPUT = open(file)
+    @TRACE@("Reading: $file\n");
+    open (INPUT, $file)
+        || die "Can't open $file: $!";
 
-    for line in INPUT:
-        if line.strip() == '':
-            continue
+    while (<INPUT>) {
+        if (m/^#/) {
+            next;
 
-        m = re.search(r'^<SECTION>', line)
-        if m:
-            subsection = ''
-            continue
+        } elsif (m/^<SECTION>/) {
+            $subsection = "";
 
-        m = re.search(r'^<SUBSECTION\s*(.*)', line, flags=re.I)
-        if m:
-            subsection = m.group(1)
-            continue
+        } elsif (m/^<SUBSECTION\s*(.*)>/i) {
+            $subsection = $1;
 
-        if re.search(r'^<SUBSECTION>', line):
-            continue
+        } elsif (m/^<SUBSECTION>/) {
+            next;
 
-        if re.search(r'^<TITLE>(.*)<\/TITLE>', line):
-            continue
+        } elsif (m/^<TITLE>(.*)<\/TITLE>/) {
+            next;
 
-        m = re.search(r'^<FILE>(.*)<\/FILE>', line)
-        if m:
-            KnownSymbols[os.path.join(TMPL_DIR, m.group(1) + ":Long_Description")] = 1
-            KnownSymbols[os.path.join(TMPL_DIR, m.group(1) + ":Short_Description")] = 1
-            continue
+        } elsif (m/^<FILE>(.*)<\/FILE>/) {
+            $KnownSymbols{"$TMPL_DIR/$1:Long_Description"} = 1;
+            $KnownSymbols{"$TMPL_DIR/$1:Short_Description"} = 1;
+            next;
 
-        m = re.search(r'^<INCLUDE>(.*)<\/INCLUDE>', line)
-        if m:
-            continue
+        } elsif (m/^<INCLUDE>(.*)<\/INCLUDE>/) {
+            next;
 
-        m = re.search(r'^<\/SECTION>', line)
-        if m:
-            continue
+        } elsif (m/^<\/SECTION>/) {
+            next;
 
-        m = re.search(r'^(\S+)', line)
-        if m:
-            symbol = m.group(1)
+        } elsif (m/^(\S+)/) {
+            my $symbol = $1;
+
+            if ($subsection ne "Standard" && $subsection ne "Private") {
+                $KnownSymbols{$symbol} = 1;
+            }
+            else {
+                $KnownSymbols{$symbol} = 0;
+            }
+        }
+    }
+    close (INPUT);
+}
 
-            if subsection != "Standard" and subsection != "Private":
-                KnownSymbols[symbol] = 1
-            else:
-                KnownSymbols[symbol] = 0
-    INPUT.close()
 
 #############################################################################
 # Function    : OutputDeclaration
@@ -1269,26 +1362,30 @@ def ReadKnownSymbols(file):
 #                $declaration - the declaration of the function/macro.
 #############################################################################
 
-def OutputDeclaration(symbol, declaration):
-    dtype = DeclarationTypes[symbol]
-    if dtype == 'MACRO':
-        return OutputMacro(symbol, declaration)
-    elif dtype == 'TYPEDEF':
-        return OutputTypedef(symbol, declaration)
-    elif dtype == 'STRUCT':
-        return OutputStruct(symbol, declaration)
-    elif dtype == 'ENUM':
-        return OutputEnum(symbol, declaration)
-    elif dtype == 'UNION':
-        return OutputUnion(symbol, declaration)
-    elif dtype == 'VARIABLE':
-        return OutputVariable(symbol, declaration)
-    elif dtype == 'FUNCTION':
-        return OutputFunction(symbol, declaration, dtype)
-    elif dtype == 'USER_FUNCTION':
-        return OutputFunction(symbol, declaration, dtype)
-    else:
-        sys.exit("Unknown symbol type " + dtype)
+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";
+    }
+}
 
 
 #############################################################################
@@ -1297,19 +1394,21 @@ def OutputDeclaration(symbol, declaration):
 # Arguments   : $symbol - the name of the function/macro begin described.
 #############################################################################
 
-def OutputSymbolTraits(symbol):
-    desc = ''
-
-    if symbol in Since:
-        link_id = "api-index-" + Since[symbol]
-        desc += "<para role=\"since\">Since: <link linkend=\"%s\">%s</link></para>" % (link_id, 
Since[symbol])
-
-    if symbol in StabilityLevel:
-        stability = StabilityLevel[symbol]
-        AnnotationsUsed[stability] = True
-        desc += "<para role=\"stability\">Stability Level: <acronym>%s</acronym></para>" % stability
-    return desc
-
+sub OutputSymbolTraits {
+    my ($symbol) = @_;
+    my $desc = "";
+
+    if (exists $Since{$symbol}) {
+        my $link_id = "api-index-".$Since{$symbol};
+        $desc .= "<para role=\"since\">Since: <link linkend=\"$link_id\">$Since{$symbol}</link></para>";
+    }
+    if (exists $StabilityLevel{$symbol}) {
+        my $stability = $StabilityLevel{$symbol};
+        $AnnotationsUsed{$stability} = 1;
+        $desc .= "<para role=\"stability\">Stability Level: <acronym>$stability</acronym></para>";
+    }
+    return $desc;
+}
 
 #############################################################################
 # Function    : Output{Symbol,Section}ExtraLinks
@@ -1317,46 +1416,52 @@ def OutputSymbolTraits(symbol):
 # Arguments   : $symbol - the name of the function/macro begin described.
 #############################################################################
 
-def uri_escape(text):
-    if text is None:
-        return None
+sub uri_escape {
+    my $text = $_[0];
+    return undef unless defined $text;
 
     # Build a char to hex map
-    escapes = {}
-    for i in range(256):
-        escapes[chr(i)] = "%%%02X" % i
+    my %escapes = ();
+    for (0..255) {
+            $escapes{chr($_)} = sprintf("%%%02X", $_);
+    }
 
     # Default unsafe characters.  RFC 2732 ^(uric - reserved)
-    def do_escape(char):
-        return escapes[char]
-    text = re.sub(r"([^A-Za-z0-9\-_.!~*'()]", do_escape, text)
-
-    return text
-
-def OutputSymbolExtraLinks(symbol):
-    desc = ''
-
-    if False: # NEW FEATURE: needs configurability
-        sstr = uri_escape(symbol)
-        mstr = uri_escape(MODULE)
-        desc += '''<ulink role="extralinks" url="http://www.google.com/codesearch?q=%s";>code search</ulink>
-<ulink role="extralinks" url="http://library.gnome.org/edit?module=%s&amp;symbol=%s";>edit 
documentation</ulink>
-''' % (sstr, mstr, sstr)
-
-    return desc
+    $text =~ s/([^A-Za-z0-9\-_.!~*'()])/$escapes{$1}/g;
 
+    return $text;
+}
 
-def OutputSectionExtraLinks(symbol, docsymbol):
-    desc = ''
+sub OutputSymbolExtraLinks {
+    my ($symbol) = @_;
+    my $desc = "";
+
+    if (0) { # NEW FEATURE: needs configurability
+    my $sstr = &uri_escape($symbol);
+    my $mstr = &uri_escape($MODULE);
+    $desc .= <<EOF;
+<ulink role="extralinks" url="http://www.google.com/codesearch?q=$sstr";>code search</ulink>
+<ulink role="extralinks" url="http://library.gnome.org/edit?module=$mstr&amp;symbol=$sstr";>edit 
documentation</ulink>
+EOF
+    }
+    return $desc;
+}
 
-    if False: # NEW FEATURE: needs configurability
-        sstr = uri_escape(symbol)
-        mstr = uri_escape(MODULE)
-        dsstr = uri_escape(docsymbol)
-        desc += '''<ulink role="extralinks" url="http://www.google.com/codesearch?q=%s";>code search</ulink>
-<ulink role="extralinks" url="http://library.gnome.org/edit?module=%s&amp;symbol=%s";>edit 
documentation</ulink>
-''' % (sstr, mstr, dsstr)
-    return desc
+sub OutputSectionExtraLinks {
+    my ($symbol,$docsymbol) = @_;
+    my $desc = "";
+
+    if (0) { # NEW FEATURE: needs configurability
+    my $sstr = &uri_escape($symbol);
+    my $mstr = &uri_escape($MODULE);
+    my $dsstr = &uri_escape($docsymbol);
+    $desc .= <<EOF;
+<ulink role="extralinks" url="http://www.google.com/codesearch?q=$sstr";>code search</ulink>
+<ulink role="extralinks" url="http://library.gnome.org/edit?module=$mstr&amp;symbol=$dsstr";>edit 
documentation</ulink>
+EOF
+    }
+    return $desc;
+}
 
 
 #############################################################################
@@ -1366,59 +1471,60 @@ def OutputSectionExtraLinks(symbol, docsymbol):
 #                $declaration - the declaration of the macro.
 #############################################################################
 
-def OutputMacro(symbol, declaration):
-    sid = common.CreateValidSGMLID(symbol)
-    condition = MakeConditionDescription(symbol)
-    synop = "<row><entry role=\"define_keyword\">#define</entry><entry role=\"function_name\"><link 
linkend=\"%s\">%s</link>" % (sid, symbol)
-    desc = None
+sub OutputMacro {
+    my ($symbol, $declaration) = @_;
+    my $id = &CreateValidSGMLID ($symbol);
+    my $condition = &MakeConditionDescription ($symbol);
+    my $synop = "<row><entry role=\"define_keyword\">#define</entry><entry role=\"function_name\"><link 
linkend=\"$id\">$symbol</link>";
+    my $desc;
 
-    fields = common.ParseMacroDeclaration(declaration, CreateValidSGML)
-    title = symbol  +'()' if len(fields) > 0 else ''
+    my @fields = ParseMacroDeclaration($declaration, \&CreateValidSGML);
+    my $title = $symbol . (@fields ? "()" : "");
 
-    desc = "<refsect2 id=\"%s\" role=\"macro\"condition>\n<title>title</title>\n" % (sid, condition, title)
-    desc += MakeIndexterms(symbol, sid)
-    desc += "\n"
-    desc += OutputSymbolExtraLinks(symbol)
+    $desc = "<refsect2 id=\"$id\" role=\"macro\"$condition>\n<title>$title</title>\n";
+    $desc .= MakeIndexterms($symbol, $id);
+    $desc .= "\n";
+    $desc .= OutputSymbolExtraLinks($symbol);
 
-    if len(fields) > 0:
-        synop += "<phrase role=\"c_punctuation\">()</phrase>"
-
-    synop += "</entry></row>\n"
+    if (@fields) {
+        $synop .= "<phrase role=\"c_punctuation\">()</phrase>";
+    }
+    $synop .= "</entry></row>\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 symbol in DeclarationConditional and not symbol.startswith('g_') \
-        and not re.search(r'^_?gnome_', symbol) and declaration.count('\n/') < 2:
-        decl_out = CreateValidSGML(declaration)
-        desc += "<programlisting language=\"C\">%s</programlisting>\n" % decl_out
-    else:
-        desc += "<programlisting language=\"C\">" + MakeReturnField("#define") + symbol
-        m = re.search(r'^\s*#\s*define\s+\w+(\([^\)]*\))', declaration)
-        if m:
-            args = m.group(1)
-            pad = ' ' * RETURN_TYPE_FIELD_WIDTH - len("#define ")
+    if (!defined ($DeclarationConditional{$symbol}) && ($symbol !~ m/^g_/)
+        && ($symbol !~ m/^_?gnome_/) && (($declaration =~ tr/\n//) < 2)) {
+        my $decl_out = &CreateValidSGML ($declaration);
+        $desc .= "<programlisting language=\"C\">$decl_out</programlisting>\n";
+    } else {
+        $desc .= "<programlisting language=\"C\">" . &MakeReturnField("#define") . "$symbol";
+        if ($declaration =~ m/^\s*#\s*define\s+\w+(\([^\)]*\))/) {
+            my $args = $1;
+            my $pad = ' ' x ($RETURN_TYPE_FIELD_WIDTH - length ("#define "));
             # Align each line so that if should all line up OK.
-            args = args.replace('\n', '\n' + pad)
-            desc += CreateValidSGML(args)
-
-        desc += "</programlisting>\n"
+            $args =~ s/\n/\n$pad/gm;
+            $desc .= &CreateValidSGML ($args);
+        }
+        $desc .= "</programlisting>\n";
+    }
 
+    $desc .= &MakeDeprecationNote($symbol);
 
-    desc += MakeDeprecationNote(symbol)
+    my $parameters = &OutputParamDescriptions ("MACRO", $symbol, @fields);
 
-    parameters = OutputParamDescriptions("MACRO", symbol, fields)
+    if (defined ($SymbolDocs{$symbol})) {
+        my $symbol_docs = &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
+        $desc .= $symbol_docs;
+    }
 
-    if symbol in SymbolDocs:
-        symbol_docs = ConvertMarkDown(symbol, SymbolDocs[symbol])
-        desc += symbol_docs
-
-
-    desc += parameters
-    desc += OutputSymbolTraits(symbol)
-    desc += "</refsect2>\n"
-    return (synop, desc)
+    $desc .= $parameters;
+    $desc .= OutputSymbolTraits ($symbol);
+    $desc .= "</refsect2>\n";
+    return ($synop, $desc);
+}
 
 
 #############################################################################
@@ -1429,30 +1535,31 @@ def OutputMacro(symbol, declaration):
 #                  e.g. 'typedef unsigned int guint;'
 #############################################################################
 
-def OutputTypedef(symbol, declaration):
-    sid = common.CreateValidSGMLID(symbol)
-    condition = MakeConditionDescription(symbol)
-    desc = "<refsect2 id=\"%s\" role=\"typedef\"%s>\n<title>%s</title>\n" % (sid, condition, symbol)
-    synop = "<row><entry role=\"typedef_keyword\">typedef</entry><entry role=\"function_name\"><link 
linkend=\"%s\">%s</link></entry></row>\n" % (sid, symbol)
-
-    desc += MakeIndexterms(symbol, sid)
-    desc += "\n"
-    desc += OutputSymbolExtraLinks(symbol)
-
-    if  symbol in DeclarationConditional:
-        decl_out = CreateValidSGML(declaration)
-        desc += "<programlisting language=\"C\">%s</programlisting>\n" % decl_out
+sub OutputTypedef {
+    my ($symbol, $declaration) = @_;
+    my $id = &CreateValidSGMLID ($symbol);
+    my $condition = &MakeConditionDescription ($symbol);
+    my $desc = "<refsect2 id=\"$id\" role=\"typedef\"$condition>\n<title>$symbol</title>\n";
+    my $synop = "<row><entry role=\"typedef_keyword\">typedef</entry><entry role=\"function_name\"><link 
linkend=\"$id\">$symbol</link></entry></row>\n";
 
+    $desc .= MakeIndexterms($symbol, $id);
+    $desc .= "\n";
+    $desc .= OutputSymbolExtraLinks($symbol);
 
-    desc += MakeDeprecationNote(symbol)
+    if (!defined ($DeclarationConditional{$symbol})) {
+        my $decl_out = &CreateValidSGML ($declaration);
+        $desc .= "<programlisting language=\"C\">$decl_out</programlisting>\n";
+    }
 
-    if symbol in SymbolDocs:
-        desc += ConvertMarkDown(symbol, SymbolDocs[symbol])
-
-    desc += OutputSymbolTraits(symbol)
-    desc += "</refsect2>\n"
-    return (synop, desc)
+    $desc .= &MakeDeprecationNote($symbol);
 
+    if (defined ($SymbolDocs{$symbol})) {
+        $desc .= &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
+    }
+    $desc .= OutputSymbolTraits ($symbol);
+    $desc .= "</refsect2>\n";
+    return ($synop, $desc);
+}
 
 
 #############################################################################
@@ -1466,204 +1573,223 @@ def OutputTypedef(symbol, declaration):
 #                $declaration - the declaration of the struct.
 #############################################################################
 
-def OutputStruct(symbol, declaration):
-
-    is_gtype = False
-    default_to_public = True
-    if CheckIsObject(symbol):
-        logging.info("Found struct gtype: %s", symbol)
-        is_gtype = True
-        default_to_public = ObjectRoots[symbol] == 'GBoxed'
+sub OutputStruct {
+    my ($symbol, $declaration) = @_;
 
+    my $is_gtype = 0;
+    my $default_to_public = 1;
+    if (&CheckIsObject ($symbol)) {
+        @TRACE@("Found struct gtype: $symbol\n");
+        $is_gtype = 1;
+        $default_to_public = $ObjectRoots{$symbol} eq 'GBoxed';
+    }
 
-    sid = None
-    condition = None
-    if is_gtype:
-        sid = common.CreateValidSGMLID(symbol + "_struct")
-        condition = MakeConditionDescription(symbol + "_struct")
-    else:
-        sid = common.CreateValidSGMLID(symbol)
-        condition = MakeConditionDescription(symbol)
-
+    my $id;
+    my $condition;
+    if ($is_gtype) {
+        $id = &CreateValidSGMLID ($symbol . "_struct");
+        $condition = &MakeConditionDescription ($symbol . "_struct");
+    } else {
+        $id = &CreateValidSGMLID ($symbol);
+        $condition = &MakeConditionDescription ($symbol);
+    }
 
     # Determine if it is a simple struct or it also has a typedef.
-    has_typedef = False
-    if StructHasTypedef[symbol] or re.search(r'^\s*typedef\s+', declaration):
-        has_typedef = True
-
-    type_output = None
-    desc = None
-    if has_typedef:
+    my $has_typedef = 0;
+    if ($StructHasTypedef{$symbol} || $declaration =~ m/^\s*typedef\s+/) {
+      $has_typedef = 1;
+    }
+
+    my $type_output;
+    my $desc;
+    if ($has_typedef) {
         # For structs with typedefs we just output the struct name.
-        type_output = ''
-        desc = "<refsect2 id=\"%s\" role=\"struct\"%s>\n<title>%s</title>\n" % (sid, condition, symbol)
-    else:
-        type_output = "struct"
-        desc = "<refsect2 id=\"%s\" role=\"struct\"%s>\n<title>struct %s</title>\n" % (sid, condition, 
symbol)
-
-    synop = "<row><entry role=\"datatype_keyword\">%s</entry><entry role=\"function_name\"><link 
linkend=\"%s\">%s</link></entry></row>\n" % (type_output, sid, symbol)
-
-    desc += MakeIndexterms(symbol, sid)
-    desc += "\n"
-    desc += OutputSymbolExtraLinks(symbol)
+        $type_output = "";
+        $desc = "<refsect2 id=\"$id\" role=\"struct\"$condition>\n<title>$symbol</title>\n";
+    } else {
+        $type_output = "struct";
+        $desc = "<refsect2 id=\"$id\" role=\"struct\"$condition>\n<title>struct $symbol</title>\n";
+    }
+    my $synop = "<row><entry role=\"datatype_keyword\">${type_output}</entry><entry 
role=\"function_name\"><link linkend=\"$id\">$symbol</link></entry></row>\n";
+
+    $desc .= MakeIndexterms($symbol, $id);
+    $desc .= "\n";
+    $desc .= OutputSymbolExtraLinks($symbol);
 
     # Form a pretty-printed, private-data-removed form of the declaration
 
-    decl_out = ''
-    if re.search(r'^\s*$', declaration):
-        logging.info("Found opaque struct: %s", symbol)
-        decl_out = "typedef struct _%s %s;" % (symbol, symbol)
-    elif re.search(r'^\s*struct\s+\w+\s*;\s*', declaration):
-        logging.info("Found opaque struct: %s", symbol)
-        decl_out = "struct %s;" % symbol
-    else:
-        public = default_to_public
-        new_declaration = ''
-        decl_line = None
-        decl = declaration
-
-        m = re.search(r'^\s*(typedef\s+)?struct\s*\w*\s*(?:\/\*.*\*\/)?\s*{(.*)}\s*\w*\s*;\s*$', decl, 
flags=re.S)
-        if m:
-            struct_contents = m.group(2)
-
-            for decl_line  in struct_contents.split('\n'):
-                logging.info("Struct line: %s", decl_line)
-                m2 = re.search(r'/\*\s*<\s*public\s*>\s*\*/', decl_line)
-                m3 = re.search(r'/\*\s*<\s*(private|protected)\s*>\s*\*/', decl_line)
-                if m2:
-                    public = True
-                elif m3:
-                    public = False
-                elif public:
-                    new_declaration += decl_line + "\n"
-
-            if new_declaration:
+    my $decl_out = "";
+    if ($declaration =~ m/^\s*$/) {
+        @TRACE@("Found opaque struct: $symbol\n");
+        $decl_out = "typedef struct _$symbol $symbol;";
+    } elsif ($declaration =~ m/^\s*struct\s+\w+\s*;\s*$/) {
+        @TRACE@("Found opaque struct: $symbol\n");
+        $decl_out = "struct $symbol;";
+    } else {
+        my $public = $default_to_public;
+        my $new_declaration = "";
+        my $decl_line;
+        my $decl = $declaration;
+
+        if ($decl =~ m/^\s*(typedef\s+)?struct\s*\w*\s*(?:\/\*.*\*\/)?\s*{(.*)}\s*\w*\s*;\s*$/s) {
+            my $struct_contents = $2;
+
+            foreach $decl_line (split (/\n/, $struct_contents)) {
+                @TRACE@("Struct line: $decl_line\n");
+                if ($decl_line =~ m%/\*\s*<\s*public\s*>\s*\*/%) {
+                    $public = 1;
+                } elsif ($decl_line =~ m%/\*\s*<\s*(private|protected)\s*>\s*\*/%) {
+                    $public = 0;
+                } elsif ($public) {
+                    $new_declaration .= $decl_line . "\n";
+                }
+            }
+
+            if ($new_declaration) {
                 # Strip any blank lines off the ends.
-                new_declaration = '\n'.join([x.strip() for x in new_declaration.split('\n')])
-
-                if has_typedef:
-                    decl_out = "typedef struct {\n" + new_declaration + "} $symbol;\n"
-                else:
-                    decl_out = "struct %s {\n%s };\n" % (symbol, new_declaration)
-
-        else:
-            common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                              "Couldn't parse struct:\n%s" % declaration)
+                $new_declaration =~ s/^\s*\n//;
+                $new_declaration =~ s/\n\s*$/\n/;
+
+                if ($has_typedef) {
+                    $decl_out = "typedef struct {\n" . $new_declaration
+                      . "} $symbol;\n";
+                } else {
+                    $decl_out = "struct $symbol {\n" . $new_declaration
+                      . "};\n";
+                }
+            }
+        } else {
+            &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                "Couldn't parse struct:\n$declaration");
+        }
 
         # If we couldn't parse the struct or it was all private, output an
         # empty struct declaration.
-        if decl_out == '':
-            if has_typedef:
-                decl_out = "typedef struct _%s %s;" % (symbol, symbol)
-            else:
-                decl_out = "struct %s;" % symbol
-
-    decl_out = CreateValidSGML(decl_out)
-    desc += "<programlisting language=\"C\">%s</programlisting>\n" % decl_out
+        if ($decl_out eq "") {
+            if ($has_typedef) {
+                $decl_out = "typedef struct _$symbol $symbol;";
+            } else {
+                $decl_out = "struct $symbol;";
+            }
+        }
+    }
 
-    desc += MakeDeprecationNote(symbol)
+    $decl_out = &CreateValidSGML ($decl_out);
+    $desc .= "<programlisting language=\"C\">$decl_out</programlisting>\n";
 
-    if symbol in SymbolDocs:
-        desc += ConvertMarkDown(symbol, SymbolDocs[symbol])
+    $desc .= &MakeDeprecationNote($symbol);
 
+    if (defined ($SymbolDocs{$symbol})) {
+        $desc .= &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
+    }
 
     # Create a table of fields and descriptions
 
     # FIXME: Inserting &#160's into the produced type declarations here would
     #        improve the output in most situations ... except for function
     #        members of structs!
-    def depfunc(*args):
-        return '<structfield id="%s">%s</structfield>' % (common.CreateValidSGMLID(sid + '.' + args[0]), 
args[0])
-
-    fields = common.ParseStructDeclaration(declaration, not default_to_public,
-                                           0, MakeXRef, depfunc)
-    params = SymbolParams[symbol]
+    my @fields = ParseStructDeclaration($declaration, !$default_to_public,
+                                        0, \&MakeXRef,
+                                        sub {
+                                            "<structfield 
id=\"".&CreateValidSGMLID("$id.$_[0]")."\">$_[0]</structfield>";
+                                        });
+    my $params = $SymbolParams{$symbol};
 
     # If no parameters are filled in, we don't generate the description
     # table, for backwards compatibility.
 
-    found = False
-    if params:
-        for i in range(1, len(params)+1, PARAM_FIELD_COUNT):
-            if re.search(r'\S', params[i]):
-                found = True
-                break
-
-    if found:
-        field_descrs = {} # FIXME, don't know what this does, original was: @$params
-        missing_parameters = ''
-        unused_parameters = ''
-        sid = common.CreateValidSGMLID(symbol + ".members")
-
-        desc += '''<refsect3 id="%s" role="struct_members">\n<title>Members</title>
+    my $found = 0;
+    if (defined $params) {
+        for (my $i = 1; $i <= $#$params; $i += $PARAM_FIELD_COUNT) {
+            if ($params->[$i] =~ /\S/) {
+                $found = 1;
+                last;
+            }
+        }
+    }
+
+    if ($found) {
+        my %field_descrs = @$params;
+        my $missing_parameters = "";
+        my $unused_parameters = "";
+        my $id = &CreateValidSGMLID ("$symbol".".members");
+
+        $desc .= <<EOF;
+<refsect3 id="$id" role="struct_members">\n<title>Members</title>
 <informaltable role="struct_members_table" pgwide="1" frame="none">
 <tgroup cols="3">
 <colspec colname="struct_members_name" colwidth="300px"/>
 <colspec colname="struct_members_description"/>
 <colspec colname="struct_members_annotations" colwidth="200px"/>
 <tbody>
-''' % sid
-
-        while len(fields) > 0:
-            field_name = fields.pop(0)
-            text = fields.pop(0)
-            field_descr = field_descrs[field_name]
-            param_annotations = ''
-
-            desc += "<row role=\"member\"><entry role=\"struct_member_name\"><para>%s</para></entry>\n" % 
text
-            if field_descr:
-                (field_descr, param_annotations) = ExpandAnnotation(symbol, field_descr)
-                field_descr = ConvertMarkDown(symbol, field_descr)
+EOF
+
+        while (@fields) {
+            my $field_name = shift @fields;
+            my $text = shift @fields;
+            my $field_descr = $field_descrs{$field_name};
+            my $param_annotations = "";
+
+            $desc .= "<row role=\"member\"><entry role=\"struct_member_name\"><para>$text</para></entry>\n";
+            if (defined $field_descr) {
+                ($field_descr,$param_annotations) = &ExpandAnnotation($symbol, $field_descr);
+                $field_descr = &ConvertMarkDown($symbol, $field_descr);
                 # trim
-                field_descr = re.sub(r'^(\s|\n)+', '', field_descr, flags=re.M|re.S)
-                field_descr = re.sub(r'(\s|\n)+$', '', field_descr, flags=re.M|re.S)
-                desc += "<entry role=\"struct_member_description\">%s</entry>\n<entry 
role=\"struct_member_annotations\">%s</entry>\n" % (field_descr, param_annotations)
-                del field_descrs[field_name]
-            else:
-                common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                  "Field description for %s::%s is missing in source code comment block." % 
(symbol, field_name))
-                if missing_parameters != '':
-                    missing_parameters += ", " + field_name
-                else:
-                    missing_parameters = field_name
-
-                desc += "<entry /><entry />\n"
-
-            desc += "</row>\n"
-
-        desc += "</tbody></tgroup></informaltable>\n</refsect3>\n"
-        for field_name in field_descrs:
+                $field_descr =~ s/^(\s|\n)+//msg;
+                $field_descr =~ s/(\s|\n)+$//msg;
+                $desc .= "<entry role=\"struct_member_description\">$field_descr</entry>\n<entry 
role=\"struct_member_annotations\">$param_annotations</entry>\n";
+                delete $field_descrs{$field_name};
+            } else {
+                &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                    "Field description for $symbol"."::"."$field_name is missing in source code comment 
block.");
+                if ($missing_parameters ne "") {
+                  $missing_parameters .= ", ".$field_name;
+                } else {
+                    $missing_parameters = $field_name;
+                }
+                $desc .= "<entry /><entry />\n";
+            }
+            $desc .= "</row>\n";
+        }
+        $desc .= "</tbody></tgroup></informaltable>\n</refsect3>\n";
+        foreach my $field_name (keys %field_descrs) {
             # Documenting those standard fields is not required anymore, but
             # we don't want to warn if they are documented anyway.
-            m = re.search(r'(g_iface|parent_instance|parent_class)', field_name)
-            if m:
-                continue
-
-            common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                              "Field description for %s::%s is not used from source code comment block." % 
(symbol, field_name))
-            if unused_parameters != '':
-                unused_parameters += ", " + field_name
-            else:
-                unused_parameters = field_name
+            if ($field_name =~ /(g_iface|parent_instance|parent_class)/) {
+                next;
+            }
+            &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                "Field description for $symbol"."::"."$field_name is not used from source code comment 
block.");
+            if ($unused_parameters ne "") {
+              $unused_parameters .= ", ".$field_name;
+            } else {
+               $unused_parameters = $field_name;
+            }
+        }
 
         # remember missing/unused parameters (needed in tmpl-free build)
-        if missing_parameters != '' and (symbol not in AllIncompleteSymbols):
-            AllIncompleteSymbols[symbol] = missing_parameters
-
-        if unused_parameters != '' and (symbol not in AllUnusedSymbols):
-            AllUnusedSymbols[symbol] = unused_parameters
-    else:
-        if len(fields) > 0:
-            if symbol not in AllIncompleteSymbols:
-                AllIncompleteSymbols[symbol] = "<items>"
-                common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                  "Field descriptions for struct %s are missing in source code comment 
block." % symbol)
-                logging.info("Remaining structs fields: " + ':'.join(fields) + "\n")
-
-    desc += OutputSymbolTraits(symbol)
-    desc += "</refsect2>\n"
-    return (synop, desc)
-
+        if (($missing_parameters ne "") and (! exists ($AllIncompleteSymbols{$symbol}))) {
+            $AllIncompleteSymbols{$symbol}=$missing_parameters;
+        }
+        if (($unused_parameters ne "") and (! exists ($AllUnusedSymbols{$symbol}))) {
+            $AllUnusedSymbols{$symbol}=$unused_parameters;
+        }
+    }
+    else {
+        if (scalar(@fields) > 0) {
+            if (! exists ($AllIncompleteSymbols{$symbol})) {
+                $AllIncompleteSymbols{$symbol}="<items>";
+                &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                    "Field descriptions for struct $symbol are missing in source code comment block.");
+                @TRACE@("Remaining structs fields: ".@fields.":".join(',',@fields)."\n");
+            }
+        }
+    }
+
+    $desc .= OutputSymbolTraits ($symbol);
+    $desc .= "</refsect2>\n";
+    return ($synop, $desc);
+}
 
 
 #############################################################################
@@ -1673,140 +1799,156 @@ def OutputStruct(symbol, declaration):
 #                $declaration - the declaration of the union.
 #############################################################################
 
-def OutputUnion(symbol, declaration):
-
-    is_gtype = False
-    if CheckIsObject(symbol):
-        logging.info("Found union gtype: %s\n", symbol)
-        is_gtype = True
-
+sub OutputUnion {
+    my ($symbol, $declaration) = @_;
 
-    sid = None
-    condition = None
-    if is_gtype:
-        sid = common.CreateValidSGMLID(symbol + "_union")
-        condition = MakeConditionDescription(symbol + "_union")
-    else:
-        sid = common.CreateValidSGMLID(symbol)
-        condition = MakeConditionDescription(symbol)
+    my $is_gtype = 0;
+    if (&CheckIsObject ($symbol)) {
+        @TRACE@("Found union gtype: $symbol\n");
+        $is_gtype = 1;
+    }
 
+    my $id;
+    my $condition;
+    if ($is_gtype) {
+        $id = &CreateValidSGMLID ($symbol . "_union");
+        $condition = &MakeConditionDescription ($symbol . "_union");
+    } else {
+        $id = &CreateValidSGMLID ($symbol);
+        $condition = &MakeConditionDescription ($symbol);
+    }
 
     # Determine if it is a simple struct or it also has a typedef.
-    has_typedef = False
-    if StructHasTypedef[symbol] or re.search(r'^\s*typedef\s+', declaration):
-        has_typedef = True
-
-
-    type_output = None
-    desc = None
-    if has_typedef:
+    my $has_typedef = 0;
+    if ($StructHasTypedef{$symbol} || $declaration =~ m/^\s*typedef\s+/) {
+      $has_typedef = 1;
+    }
+
+    my $type_output;
+    my $desc;
+    if ($has_typedef) {
         # For unions with typedefs we just output the union name.
-        type_output = ''
-        desc = "<refsect2 id=\"%s\" role=\"union\"%s>\n<title>%s</title>\n" % (sid, condition, symbol)
-    else:
-        type_output = "union"
-        desc = "<refsect2 id=\"%s\" role=\"union\"%s>\n<title>union %s</title>\n" % (sid, condition, symbol)
-
-    synop = "<row><entry role=\"datatype_keyword\">%s</entry><entry role=\"function_name\"><link 
linkend=\"%s$id\">%s</link></entry></row>\n" % (type_output, sid, symbol)
-
-    desc += MakeIndexterms(symbol, sid)
-    desc += "\n"
-    desc += OutputSymbolExtraLinks(symbol)
-    desc += MakeDeprecationNote(symbol)
-
-    if symbol in SymbolDocs:
-        desc += ConvertMarkDown(symbol, SymbolDocs[symbol])
-
+        $type_output = "";
+        $desc = "<refsect2 id=\"$id\" role=\"union\"$condition>\n<title>$symbol</title>\n";
+    } else {
+        $type_output = "union";
+        $desc = "<refsect2 id=\"$id\" role=\"union\"$condition>\n<title>union $symbol</title>\n";
+    }
+    my $synop = "<row><entry role=\"datatype_keyword\">${type_output}</entry><entry 
role=\"function_name\"><link linkend=\"$id\">$symbol</link></entry></row>\n";
+
+    $desc .= MakeIndexterms($symbol, $id);
+    $desc .= "\n";
+    $desc .= OutputSymbolExtraLinks($symbol);
+    $desc .= &MakeDeprecationNote($symbol);
+
+    if (defined ($SymbolDocs{$symbol})) {
+        $desc .= &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
+    }
 
     # Create a table of fields and descriptions
 
     # FIXME: Inserting &#160's into the produced type declarations here would
     #        improve the output in most situations ... except for function
     #        members of structs!
-    def pfunc(*args):
-        return '<structfield id="%s">%s</structfield>' % (common.CreateValidSGMLID(sid + '.' + args[0]), 
args[0])
-    fields = common.ParseStructDeclaration(declaration, 0, 0, MakeXRef, pfunc)
-    params = SymbolParams[symbol]
+    my @fields = ParseStructDeclaration($declaration, 0,
+                                        0, \&MakeXRef,
+                                        sub {
+                                            "<structfield 
id=\"".&CreateValidSGMLID("$id.$_[0]")."\">$_[0]</structfield>";
+                                        });
+    my $params = $SymbolParams{$symbol};
 
     # If no parameters are filled in, we don't generate the description
     # table, for backwards compatibility
 
-    found = False
-    if params:
-        for i in range(1, len(params)+1, PARAM_FIELD_COUNT):
-            if re.search(r'\S', params[i]):
-                found = True
-                break
-
-    if found:
-        field_descrs = {} # FIXME same as above: @$params
-        missing_parameters = ''
-        unused_parameters = ''
-        sid = common.CreateValidSGMLID('%s.members' % symbol)
-
-        desc += '''<refsect3 id="%s" role="union_members">\n<title>Members</title>
+    my $found = 0;
+    if (defined $params) {
+        for (my $i = 1; $i <= $#$params; $i += $PARAM_FIELD_COUNT) {
+            if ($params->[$i] =~ /\S/) {
+                $found = 1;
+                last;
+            }
+        }
+    }
+
+    if ($found) {
+        my %field_descrs = @$params;
+        my $missing_parameters = "";
+        my $unused_parameters = "";
+        my $id = &CreateValidSGMLID ("$symbol".".members");
+
+        $desc .= <<EOF;
+<refsect3 id="$id" role="union_members">\n<title>Members</title>
 <informaltable role="union_members_table" pgwide="1" frame="none">
 <tgroup cols="3">
 <colspec colname="union_members_name" colwidth="300px"/>
 <colspec colname="union_members_description"/>
 <colspec colname="union_members_annotations" colwidth="200px"/>
 <tbody>
-''' % sid
+EOF
 
-        while len(fields) > 0:
-            field_name = fields.pop(0)
-            text = fields.pop(0)
-            field_descr = field_descrs[field_name]
-            param_annotations = ''
+        while (@fields) {
+            my $field_name = shift @fields;
+            my $text = shift @fields;
+            my $field_descr = $field_descrs{$field_name};
+            my $param_annotations = "";
 
-            desc += "<row><entry role=\"union_member_name\"><para>%s</para></entry>\n" % text
-            if field_descr:
-                (field_descr, param_annotations) = ExpandAnnotation(symbol, field_descr)
-                field_descr = ConvertMarkDown(symbol, field_descr)
+            $desc .= "<row><entry role=\"union_member_name\"><para>$text</para></entry>\n";
+            if (defined $field_descr) {
+                ($field_descr,$param_annotations) = &ExpandAnnotation($symbol, $field_descr);
+                $field_descr = &ConvertMarkDown($symbol, $field_descr);
 
                 # trim
-                field_descr = re.sub(r'^(\s|\n)+', '', field_descr, flags=re.M|re.S)
-                field_descr = re.sub(r'(\s|\n)+$', '', field_descr, flags=re.M|re.S)
-                desc += "<entry role=\"union_member_description\">%s</entry>\n<entry 
role=\"union_member_annotations\">%s</entry>\n" % (field_descr, param_annotations)
-                del field_descrs[field_name]
-            else:
-                common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                  "Field description for %s::%s is missing in source code comment block." % 
(symbol, field_name))
-                if missing_parameters != '':
-                    missing_parameters += ", " + field_name
-                else:
-                    missing_parameters = field_name
-
-                desc += "<entry /><entry />\n"
-
-            desc += "</row>\n"
-
-        desc += "</tbody></tgroup></informaltable>\n</refsect3>"
-        for field_name in field_descrs:
-            common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                              "Field description for %s::%s is not used from source code comment block." % 
(symbol, field_name))
-            if unused_parameters != '':
-                unused_parameters += ", " + field_name
-            else:
-                unused_parameters = field_name
+                $field_descr =~ s/^(\s|\n)+//msg;
+                $field_descr =~ s/(\s|\n)+$//msg;
+                $desc .= "<entry role=\"union_member_description\">$field_descr</entry>\n<entry 
role=\"union_member_annotations\">$param_annotations</entry>\n";
+                delete $field_descrs{$field_name};
+            } else {
+                &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                    "Field description for $symbol"."::"."$field_name is missing in source code comment 
block.");
+                if ($missing_parameters ne "") {
+                    $missing_parameters .= ", ".$field_name;
+                } else {
+                    $missing_parameters = $field_name;
+                }
+                $desc .= "<entry /><entry />\n";
+            }
+            $desc .= "</row>\n";
+        }
+        $desc .= "</tbody></tgroup></informaltable>\n</refsect3>";
+        foreach my $field_name (keys %field_descrs) {
+            &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                "Field description for $symbol"."::"."$field_name is not used from source code comment 
block.");
+            if ($unused_parameters ne "") {
+              $unused_parameters .= ", ".$field_name;
+            } else {
+               $unused_parameters = $field_name;
+            }
+        }
 
         # remember missing/unused parameters (needed in tmpl-free build)
-        if missing_parameters != '' and (symbol not in AllIncompleteSymbols):
-            AllIncompleteSymbols[symbol] = missing_parameters
-
-        if unused_parameters != '' and (symbol not in AllUnusedSymbols):
-            AllUnusedSymbols[symbol] = unused_parameters
-    else:
-        if len(fields) > 0:
-            if symbol not in AllIncompleteSymbols:
-                AllIncompleteSymbols[symbol] = "<items>"
-                common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                  "Field descriptions for union %s are missing in source code comment 
block." % symbol)
-                logging.info("Remaining union fields: " + ':'.join(fields) + "\n")
+        if (($missing_parameters ne "") and (! exists ($AllIncompleteSymbols{$symbol}))) {
+            $AllIncompleteSymbols{$symbol}=$missing_parameters;
+        }
+        if (($unused_parameters ne "") and (! exists ($AllUnusedSymbols{$symbol}))) {
+            $AllUnusedSymbols{$symbol}=$unused_parameters;
+        }
+    }
+    else {
+        if (scalar(@fields) > 0) {
+            if (! exists ($AllIncompleteSymbols{$symbol})) {
+                $AllIncompleteSymbols{$symbol}="<items>";
+                &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                    "Field descriptions for union $symbol are missing in source code comment block.");
+                @TRACE@("Remaining union fields: ".@fields.":".join(',',@fields)."\n");
+            }
+        }
+    }
+
+    $desc .= OutputSymbolTraits ($symbol);
+    $desc .= "</refsect2>\n";
+    return ($synop, $desc);
+}
 
-    desc += OutputSymbolTraits(symbol)
-    desc += "</refsect2>\n"
-    return (synop, desc)
 
 #############################################################################
 # Function    : OutputEnum
@@ -1815,112 +1957,129 @@ def OutputUnion(symbol, declaration):
 #                $declaration - the declaration of the enum.
 #############################################################################
 
-def OutputEnum(symbol, declaration):
-    is_gtype = False
-    if CheckIsObject(symbol):
-        logging.info("Found enum gtype: %s", symbol)
-        is_gtype = True
+sub OutputEnum {
+    my ($symbol, $declaration) = @_;
 
-    sid = None
-    condition = None
-    if is_gtype:
-        sid = common.CreateValidSGMLID(symbol + "_enum")
-        condition = MakeConditionDescription(symbol + "_enum")
-    else:
-        sid = common.CreateValidSGMLID(symbol)
-        condition = MakeConditionDescription(symbol)
+    my $is_gtype = 0;
+    if (&CheckIsObject ($symbol)) {
+        @TRACE@("Found enum gtype: $symbol\n");
+        $is_gtype = 1;
+    }
 
+    my $id;
+    my $condition;
+    if ($is_gtype) {
+        $id = &CreateValidSGMLID ($symbol . "_enum");
+        $condition = &MakeConditionDescription ($symbol . "_enum");
+    } else {
+        $id = &CreateValidSGMLID ($symbol);
+        $condition = &MakeConditionDescription ($symbol);
+    }
 
-    synop = "<row><entry role=\"datatype_keyword\">enum</entry><entry role=\"function_name\"><link 
linkend=\"\">$symbol</link></entry></row>\n" % sid
-    desc = "<refsect2 id=\"%s\" role=\"enum\"%s>\n<title>enum %s</title>\n" % (sid, condition, symbol)
+    my $synop = "<row><entry role=\"datatype_keyword\">enum</entry><entry role=\"function_name\"><link 
linkend=\"$id\">$symbol</link></entry></row>\n";
+    my $desc = "<refsect2 id=\"$id\" role=\"enum\"$condition>\n<title>enum $symbol</title>\n";
 
-    desc += MakeIndexterms(symbol, sid)
-    desc += "\n"
-    desc += OutputSymbolExtraLinks(symbol)
-    desc += MakeDeprecationNote(symbol)
+    $desc .= MakeIndexterms($symbol, $id);
+    $desc .= "\n";
+    $desc .= OutputSymbolExtraLinks($symbol);
+    $desc .= &MakeDeprecationNote($symbol);
 
-    if symbol in SymbolDocs:
-        desc += ConvertMarkDown(symbol, SymbolDocs[symbol])
+    if (defined ($SymbolDocs{$symbol})) {
+        $desc .= &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
+    }
 
     # Create a table of fields and descriptions
 
-    fields = common.ParseEnumDeclaration(declaration)
-    params = SymbolParams[symbol]
+    my @fields = ParseEnumDeclaration($declaration);
+    my $params = $SymbolParams{$symbol};
 
     # If nothing at all is documented log a single summary warning at the end.
     # Otherwise, warn about each undocumented item.
 
-    found = False
-    if params:
-        for i in range(1, len(params), PARAM_FIELD_COUNT):
-            if re.search(r'\S', params[i]):
-                found = True
-                break
-
-    field_descrs = params if params else {}
-    missing_parameters = ''
-    unused_parameters = ''
-
-    sid = common.CreateValidSGMLID("%s.members" % symbol)
-    desc += '''<refsect3 id="%s" role="enum_members">\n<title>Members</title>
+    my $found = 0;
+    if (defined $params) {
+        for (my $i = 1; $i <= $#$params; $i += $PARAM_FIELD_COUNT) {
+            if ($params->[$i] =~ /\S/) {
+                $found = 1;
+                last;
+            }
+        }
+    }
+
+    my %field_descrs = (defined $params ? @$params : ());
+    my $missing_parameters = "";
+    my $unused_parameters = "";
+
+    $id = &CreateValidSGMLID ("$symbol".".members");
+    $desc .= <<EOF;
+<refsect3 id="$id" role="enum_members">\n<title>Members</title>
 <informaltable role="enum_members_table" pgwide="1" frame="none">
 <tgroup cols="3">
 <colspec colname="enum_members_name" colwidth="300px"/>
 <colspec colname="enum_members_description"/>
 <colspec colname="enum_members_annotations" colwidth="200px"/>
 <tbody>
-''' % sid
-
-    for field_name in fields:
-        field_descr = field_descrs[field_name]
-        param_annotations = ''
-
-        sid = common.CreateValidSGMLID(field_name)
-        condition = MakeConditionDescription(field_name)
-        desc += "<row role=\"constant\"><entry role=\"enum_member_name\"><para 
id=\"%s\">$field_name</para></entry>\n" % sid
-        if field_descr:
-            field_descr, param_annotations = ExpandAnnotation(symbol, field_descr)
-            field_descr = ConvertMarkDown(symbol, field_descr)
-            desc += "<entry role=\"enum_member_description\">%s</entry>\n<entry 
role=\"enum_member_annotations\">%s</entry>\n" % (field_descr, param_annotations)
-            del field_descrs[field_name]
-        else:
-            if found:
-                common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                  "Value description for %s::%s is missing in source code comment block." % 
(symbol, field_name))
-                if missing_parameters != '':
-                    missing_parameters += ", " + field_name
-                else:
-                    missing_parameters = field_name
-            desc += "<entry /><entry />\n"
-        desc += "</row>\n"
-
-    desc += "</tbody></tgroup></informaltable>\n</refsect3>"
-    for field_name in field_descrs:
-        common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                          "Value description for %s::%s is not used from source code comment block." % 
(symbol, field_name))
-        if unused_parameters != '':
-            unused_parameters += ", " + field_name
-        else:
-            unused_parameters = field_name
+EOF
+
+    for my $field_name (@fields) {
+        my $field_descr = $field_descrs{$field_name};
+        my $param_annotations = "";
+
+        $id = &CreateValidSGMLID ($field_name);
+        $condition = &MakeConditionDescription ($field_name);
+        $desc .= "<row role=\"constant\"><entry role=\"enum_member_name\"><para 
id=\"$id\">$field_name</para></entry>\n";
+        if (defined $field_descr) {
+            ($field_descr,$param_annotations) = &ExpandAnnotation($symbol, $field_descr);
+            $field_descr = &ConvertMarkDown($symbol, $field_descr);
+            $desc .= "<entry role=\"enum_member_description\">$field_descr</entry>\n<entry 
role=\"enum_member_annotations\">$param_annotations</entry>\n";
+            delete $field_descrs{$field_name};
+        } else {
+            if ($found) {
+                &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                    "Value description for $symbol"."::"."$field_name is missing in source code comment 
block.");
+                if ($missing_parameters ne "") {
+                    $missing_parameters .= ", ".$field_name;
+                } else {
+                    $missing_parameters = $field_name;
+                }
+            }
+            $desc .= "<entry /><entry />\n";
+        }
+        $desc .= "</row>\n";
+    }
+    $desc .= "</tbody></tgroup></informaltable>\n</refsect3>";
+    foreach my $field_name (keys %field_descrs) {
+        &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+            "Value description for $symbol"."::"."$field_name is not used from source code comment block.");
+        if ($unused_parameters ne "") {
+            $unused_parameters .= ", ".$field_name;
+        } else {
+            $unused_parameters = $field_name;
+        }
+    }
 
     # remember missing/unused parameters (needed in tmpl-free build)
-    if missing_parameters != '' and (symbol not in AllIncompleteSymbols):
-        AllIncompleteSymbols[symbol] = missing_parameters
-
-    if unused_parameters != '' and (symbol not in AllUnusedSymbols):
-        AllUnusedSymbols[symbol] = unused_parameters
-
-    if not found:
-        if len(fields) > 0:
-            if symbol not in AllIncompleteSymbols:
-                AllIncompleteSymbols[symbol] = "<items>"
-                common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                  "Value descriptions for %s are missing in source code comment block." % 
symbol)
-
-    desc += OutputSymbolTraits(symbol)
-    desc += "</refsect2>\n"
-    return (synop, desc)
-
+    if (($missing_parameters ne "") and (! exists ($AllIncompleteSymbols{$symbol}))) {
+        $AllIncompleteSymbols{$symbol}=$missing_parameters;
+    }
+    if (($unused_parameters ne "") and (! exists ($AllUnusedSymbols{$symbol}))) {
+        $AllUnusedSymbols{$symbol}=$unused_parameters;
+    }
+
+    if (!$found) {
+        if (scalar(@fields) > 0) {
+            if (! exists ($AllIncompleteSymbols{$symbol})) {
+                $AllIncompleteSymbols{$symbol}="<items>";
+                &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                    "Value descriptions for $symbol are missing in source code comment block.");
+            }
+        }
+    }
+
+    $desc .= OutputSymbolTraits ($symbol);
+    $desc .= "</refsect2>\n";
+    return ($synop, $desc);
+}
 
 
 #############################################################################
@@ -1930,69 +2089,58 @@ def OutputEnum(symbol, declaration):
 #                $declaration - the declaration of the variable.
 #############################################################################
 
-def OutputVariable(symbol, declaration):
-    sid = common.CreateValidSGMLID(symbol)
-    condition = MakeConditionDescription(symbol)
-
-    logging.info("ouputing variable: '%s' '%s'", symbol, declaration)
-
-    type_output = None
-    m1 = 
re.search(r'^\s*extern\s+((const\s+|signed\s+|unsigned\s+|long\s+|short\s+)*\w+)(\s+\*+|\*+|\s)(\s*)(const\s+)*([A-Za-z]\w*)\s*;',
 declaration)
-    m2 = 
re.search(r'\s*((const\s+|signed\s+|unsigned\s+|long\s+|short\s+)*\w+)(\s+\*+|\*+|\s)(\s*)(const\s+)*([A-Za-z]\w*)\s*=',
 declaration)
-    if m1:
-        g1 = m1.group(1)
-        g2 = m1.group(2)
-        g3 = m1.group(3)
-        g4 = m1.group(4)
-        g5 = m1.group(5)
-        mod1 = g1 if g1 else ''
-        ptr = g3 if g2 else ''
-        space = g4 if g4 else ''
-        mod2 = g5 if g5 else ''
-        type_output = "extern %s%s%s%s" % (mod1, ptr, space, mod2)
-    elif m2:
-        g1 = m1.group(1)
-        g2 = m1.group(2)
-        g3 = m1.group(3)
-        g4 = m1.group(4)
-        g5 = m1.group(5)
-        mod1 = g1 if g1 else ''
-        ptr = g3 if g3 else ''
-        space = g4 if g4 else ''
-        mod2 = g5 if g5 else ''
-        type_output = '%s%s%s%s' % (mod1, ptr, space, mod2)
-    else:
-        type_output = "extern"
-
-    synop = "<row><entry role=\"variable_type\">%s</entry><entry role=\"function_name\"><link 
linkend=\"%s\">%s</link></entry></row>\n" % (type_output, sid, symbol)
-
-    desc = "<refsect2 id=\"%s\" role=\"variable\"%s>\n<title>%s</title>\n" % (sid, condition, symbol)
-
-    desc += MakeIndexterms(symbol, sid)
-    desc += "\n"
-    desc += OutputSymbolExtraLinks(symbol)
-
-    decl_out = CreateValidSGML(declaration)
-    desc += "<programlisting language=\"C\">%s</programlisting>\n" % decl_out
-
-    desc += MakeDeprecationNote(symbol)
-
-    if symbol in SymbolDocs:
-        desc += ConvertMarkDown(symbol, SymbolDocs[symbol])
-
-    if symbol in SymbolAnnotations:
-        param_desc = SymbolAnnotations[symbol]
-        param_annotations = ''
-        (param_desc, param_annotations) = ExpandAnnotation(symbol, param_desc)
-        if param_annotations != '':
-            desc += "\n<para>$param_annotations</para>"
-
-
-
-    desc += OutputSymbolTraits(symbol)
-    desc += "</refsect2>\n"
-    return (synop, desc)
-
+sub OutputVariable {
+    my ($symbol, $declaration) = @_;
+    my $id = &CreateValidSGMLID ($symbol);
+    my $condition = &MakeConditionDescription ($symbol);
+
+    @TRACE@("ouputing variable: '$symbol' '$declaration'");
+
+    my $type_output;
+    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*;/)
 {
+        my $mod1 = defined ($1) ? $1 : "";
+        my $ptr = defined ($3) ? $3 : "";
+        my $space = defined ($4) ? $4 : "";
+        my $mod2 = defined ($5) ? $5 : "";
+        $type_output = "extern $mod1$ptr$space$mod2";
+    } 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*=/)
 {
+        my $mod1 = defined ($1) ? $1 : "";
+        my $ptr = defined ($3) ? $3 : "";
+        my $space = defined ($4) ? $4 : "";
+        my $mod2 = defined ($5) ? $5 : "";
+        $type_output = "$mod1$ptr$space$mod2";
+    } else {
+        $type_output = "extern";
+    }
+    my $synop = "<row><entry role=\"variable_type\">${type_output}</entry><entry 
role=\"function_name\"><link linkend=\"$id\">$symbol</link></entry></row>\n";
+
+    my $desc = "<refsect2 id=\"$id\" role=\"variable\"$condition>\n<title>$symbol</title>\n";
+
+    $desc .= MakeIndexterms($symbol, $id);
+    $desc .= "\n";
+    $desc .= OutputSymbolExtraLinks($symbol);
+
+    my $decl_out = &CreateValidSGML ($declaration);
+    $desc .= "<programlisting language=\"C\">$decl_out</programlisting>\n";
+
+    $desc .= &MakeDeprecationNote($symbol);
+
+    if (defined ($SymbolDocs{$symbol})) {
+        $desc .= &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
+    }
+    if (defined ($SymbolAnnotations{$symbol})) {
+        my $param_desc = $SymbolAnnotations{$symbol};
+        my $param_annotations = "";
+        ($param_desc,$param_annotations) = &ExpandAnnotation($symbol, $param_desc);
+        if ($param_annotations ne "") {
+            $desc .= "\n<para>$param_annotations</para>";
+        }
+    }
+
+    $desc .= OutputSymbolTraits ($symbol);
+    $desc .= "</refsect2>\n";
+    return ($synop, $desc);
+}
 
 
 #############################################################################
@@ -2002,88 +2150,102 @@ def OutputVariable(symbol, declaration):
 #                $declaration - the declaration of the function.
 #############################################################################
 
-def OutputFunction(symbol, declaration, symbol_type):
-    sid = common.CreateValidSGMLID(symbol)
-    condition = MakeConditionDescription(symbol)
+sub OutputFunction {
+    my ($symbol, $declaration, $symbol_type) = @_;
+    my $id = &CreateValidSGMLID ($symbol);
+    my $condition = &MakeConditionDescription ($symbol);
 
-    # Take out the return type          $1                                                                   
                    $2   $3
-    m = 
re.search(r'<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',
 declaration)
-    type_modifier = m.group(1) if m.group(1) else ''
-    type = m.group(2)
-    pointer = m.group(3)
+    # Take out the return type     $1                                                                        
               $2   $3
+    $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//;
+    my $type_modifier = defined($1) ? $1 : "";
+    my $type = $2;
+    my $pointer = $3;
     # Trim trailing spaces as we are going to pad to $RETURN_TYPE_FIELD_WIDTH below anyway
-    pointer = pointer.rstrip()
-    xref = MakeXRef(type, tagify(type, "returnvalue"))
-    start = ''
-    #if ($symbol_type == 'USER_FUNCTION')
-    #    $start = "typedef "
-    #
+    $pointer =~ s/\s+$//;
+    my $xref = &MakeXRef ($type, &tagify($type, "returnvalue"));
+    my $start = "";
+    #if ($symbol_type eq 'USER_FUNCTION') {
+    #    $start = "typedef ";
+    #}
 
     # We output const rather than G_CONST_RETURN.
-    type_modifier = re.sub(r'G_CONST_RETURN', 'const', type_modifier)
-    pointer = re.sub(r'G_CONST_RETURN', 'const', pointer)
-    pointer = re.sub(r'^\s+', '&#160', pointer)
-
-    ret_type_output = None
-    ret_type_output = "%s%s%s%s\n" % (start, type_modifier, xref, pointer)
-
-    indent_len = len(symbol) + 2
-    char1 = char2 = char3 = ''
-    if symbol_type == 'USER_FUNCTION':
-        indent_len += 3
-        char1 = "<phrase role=\"c_punctuation\">(</phrase>"
-        char2 = "*"
-        char3 = "<phrase role=\"c_punctuation\">)</phrase>"
-
-
-    symbol_output = "%s<link linkend=\"%s\">%s%s</link>%s" % (char1, sid, char2, symbol, char3)
-    if indent_len < MAX_SYMBOL_FIELD_WIDTH:
-        symbol_desc_output = "%s%s%s%s" % (char1, char2, symbol, char3)
-    else:
-        indent_len = MAX_SYMBOL_FIELD_WIDTH - 8
-        symbol_desc_output = ('%s%s%s%s\n' % (char1, char2, symbol, char3)) + (' ' * (indent_len - 1))
-
-    synop = "<row><entry role=\"function_type\">%s</entry><entry role=\"function_name\">%s&#160;<phrase 
role=\"c_punctuation\">()</phrase></entry></row>\n" % (ret_type_output, symbol_output)
-
-    desc = "<refsect2 id=\"%s\" role=\"function\"%s>\n<title>%s&#160;()</title>\n" % (sid, condition, symbol)
-
-    desc += MakeIndexterms(symbol, sid)
-    desc += "\n"
-    desc += OutputSymbolExtraLinks(symbol)
-
-    desc += "<programlisting language=\"C\">%s%s(" % (ret_type_output, symbol_desc_output)
-
-    def tagfun(*args):
-        return tagify(args[0], "parameter")
-
-    fields = common.ParseFunctionDeclaration(declaration, MakeXRef, tagfun)
-
-    for i in range(1, len(fields) +1, 2):
-        field_name = fields[i]
-
-        if i == 1:
-            desc += field_name
-        else:
-            desc += ",\n" + (' ' * indent_len) + field_name
-
-    desc += ");</programlisting>\n"
-
-    desc += MakeDeprecationNote(symbol)
-
-    if symbol in SymbolDocs:
-        desc += ConvertMarkDown(symbol, SymbolDocs[symbol])
-
-    if symbol in SymbolAnnotations:
-        param_desc = SymbolAnnotations[symbol]
-        param_annotations = ''
-        (param_desc, param_annotations) = ExpandAnnotation(symbol, param_desc)
-        if param_annotations != '':
-            desc += "\n<para>%s</para>" % param_annotations
+    $type_modifier =~ s/G_CONST_RETURN/const/g;
+    $pointer =~ s/G_CONST_RETURN/const/g;
+    $pointer =~ s/^\s+/&#160;/g;
+
+    my $ret_type_output;
+    $ret_type_output = "$start$type_modifier$xref$pointer\n";
+
+    my $indent_len;
+    $indent_len = length ($symbol) + 2;
+    my $char1 = my $char2 = my $char3 = "";
+    if ($symbol_type eq 'USER_FUNCTION') {
+        $indent_len += 3;
+        $char1 = "<phrase role=\"c_punctuation\">(</phrase>";
+        $char2 = "*";
+        $char3 = "<phrase role=\"c_punctuation\">)</phrase>";
+    }
+
+    my ($symbol_output, $symbol_desc_output);
+    $symbol_output = "$char1<link linkend=\"$id\">$char2$symbol</link>$char3";
+    if ($indent_len < $MAX_SYMBOL_FIELD_WIDTH) {
+        $symbol_desc_output = "$char1$char2$symbol$char3 ";
+    } else {
+        $indent_len = $MAX_SYMBOL_FIELD_WIDTH - 8;
+        $symbol_desc_output = "$char1$char2$symbol$char3\n"
+          . (' ' x ($indent_len - 1));
+    }
+
+    my $synop = "<row><entry role=\"function_type\">${ret_type_output}</entry><entry 
role=\"function_name\">${symbol_output}&#160;<phrase role=\"c_punctuation\">()</phrase></entry></row>\n";
+
+    my $desc = "<refsect2 id=\"$id\" role=\"function\"$condition>\n<title>${symbol}&#160;()</title>\n";
+
+    $desc .= MakeIndexterms($symbol, $id);
+    $desc .= "\n";
+    $desc .= OutputSymbolExtraLinks($symbol);
+
+    $desc  .= "<programlisting language=\"C\">${ret_type_output}$symbol_desc_output(";
+
+    my @fields = ParseFunctionDeclaration($declaration, \&MakeXRef,
+                                        sub {
+                                            &tagify($_[0],"parameter");
+                                        });
+
+    for (my $i = 1; $i <= $#fields; $i += 2) {
+        my $field_name = $fields[$i];
+
+        if ($i == 1) {
+            $desc  .= "$field_name";
+        } else {
+            $desc  .= ",\n"
+                . (' ' x $indent_len)
+                . "$field_name";
+        }
+
+    }
+
+    $desc  .= ");</programlisting>\n";
+
+    $desc .= &MakeDeprecationNote($symbol);
+
+    if (defined ($SymbolDocs{$symbol})) {
+        $desc .= &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
+    }
+    if (defined ($SymbolAnnotations{$symbol})) {
+        my $param_desc = $SymbolAnnotations{$symbol};
+        my $param_annotations = "";
+        ($param_desc,$param_annotations) = &ExpandAnnotation($symbol, $param_desc);
+        if ($param_annotations ne "") {
+            $desc .= "\n<para>$param_annotations</para>";
+        }
+    }
+
+    $desc .= &OutputParamDescriptions ("FUNCTION", $symbol, @fields);
+    $desc .= OutputSymbolTraits ($symbol);
+    $desc .= "</refsect2>\n";
+    return ($synop, $desc);
+}
 
-    desc += OutputParamDescriptions("FUNCTION", symbol, fields)
-    desc += OutputSymbolTraits(symbol)
-    desc += "</refsect2>\n"
-    return (synop, desc)
 
 #############################################################################
 # Function    : OutputParamDescriptions
@@ -2096,110 +2258,123 @@ def OutputFunction(symbol, declaration, symbol_type):
 #                  undocumented/unused entries
 #############################################################################
 
-def OutputParamDescriptions(symbol_type, symbol, fields):
-    output = ''
-    params = SymbolParams[symbol]
-    num_params = 0
-    field_descrs = {}
-
-    if len(fields) > 0:
-        field_descrs = {} # FIXME convert @fields
-        del field_descrs["void"]
-        del field_descrs["Returns"]
-
-
-    if params:
-        returns = ''
-        params_desc = ''
-        missing_parameters = ''
-        unused_parameters = ''
-
-        for j in range(0, len(params), PARAM_FIELD_COUNT):
-            param_name = params[j]
-            param_desc = params[j + 1]
-            param_annotations = ''
-
-            (param_desc, param_annotations) = ExpandAnnotation(symbol, param_desc)
-            param_desc = ConvertMarkDown(symbol, param_desc)
+sub OutputParamDescriptions {
+    my ($symbol_type, $symbol, @fields) = @_;
+    my $output = "";
+    my $params = $SymbolParams{$symbol};
+    my $num_params = 0;
+    my %field_descrs = ();
+
+    if (@fields) {
+        %field_descrs = @fields;
+        delete $field_descrs{"void"};
+        delete $field_descrs{"Returns"};
+    }
+
+    if (defined $params) {
+        my $returns = "";
+        my $params_desc = "";
+        my $missing_parameters = "";
+        my $unused_parameters = "";
+        my $j;
+
+        for ($j = 0; $j <= $#$params; $j += $PARAM_FIELD_COUNT) {
+            my $param_name = $$params[$j];
+            my $param_desc = $$params[$j + 1];
+            my $param_annotations = "";
+
+            ($param_desc,$param_annotations) = &ExpandAnnotation($symbol, $param_desc);
+            $param_desc = &ConvertMarkDown($symbol, $param_desc);
             # trim
-            param_desc = re.sub(r'^(\s|\n)+', '', param_desc, flags=re.M|re.S)
-            param_desc = re.sub(r'(\s|\n)+', '', param_desc, flags=re.M|re.S)
-            if param_name == "Returns":
-                returns = param_desc
-                if param_annotations != '':
-                    returns += "\n<para>%s</para>" % param_annotations
-
-                elif param_name == "void":
-                    # FIXME: &common.LogWarning()?
-                    logging.info("!!!! void in params for %s?\n", symbol)
-            else:
-                if len(fields) > 0:
-                    if param_name in field_descrs:
-                        common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                          "Parameter description for %s::%s is not used from source code 
comment block." % (symbol, param_name))
-                        if unused_parameters != '':
-                            unused_parameters += ", " + param_name
-                        else:
-                            unused_parameters = param_name
-                    else:
-                        del field_descrs[param_name]
-
-
-                if param_desc != '':
-                    params_desc += "<row><entry role=\"parameter_name\"><para>%s</para></entry>\n<entry 
role=\"parameter_description\">%s</entry>\n<entry role=\"parameter_annotations\">%s</entry></row>\n" % 
(param_name, param_desc, param_annotations)
-                    num_params += 1
-
-        for param_name in field_descrs:
-            common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                              "Parameter description for %s::%s is missing in source code comment block." % 
(symbol, param_name))
-            if missing_parameters != '':
-                missing_parameters += ", " + param_name
-            else:
-                missing_parameters = param_name
+            $param_desc =~ s/^(\s|\n)+//msg;
+            $param_desc =~ s/(\s|\n)+$//msg;
+            if ($param_name eq "Returns") {
+                $returns = $param_desc;
+                if ($param_annotations ne "") {
+                    $returns .= "\n<para>$param_annotations</para>";
+                }
+            } elsif ($param_name eq "void") {
+                # FIXME: &LogWarning()?
+                @TRACE@("!!!! void in params for $symbol?\n");
+            } else {
+                if (@fields) {
+                    if (!defined $field_descrs{$param_name}) {
+                        &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                            "Parameter description for $symbol"."::"."$param_name is not used from source 
code comment block.");
+                        if ($unused_parameters ne "") {
+                          $unused_parameters .= ", ".$param_name;
+                        } else {
+                           $unused_parameters = $param_name;
+                        }
+                    } else {
+                        delete $field_descrs{$param_name};
+                    }
+                }
+                if($param_desc ne "") {
+                    $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";
+                    $num_params++;
+                }
+            }
+        }
+        foreach my $param_name (keys %field_descrs) {
+            &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                "Parameter description for $symbol"."::"."$param_name is missing in source code comment 
block.");
+            if ($missing_parameters ne "") {
+              $missing_parameters .= ", ".$param_name;
+            } else {
+               $missing_parameters = $param_name;
+            }
+        }
 
         # Signals have an implicit user_data parameter which we describe.
-        if symbol_type == "SIGNAL":
-            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"
-
+        if ($symbol_type eq "SIGNAL") {
+            $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";
+        }
 
         # Start a table if we need one.
-        if params_desc != '':
-            sid = common.CreateValidSGMLID("%s.parameters" % symbol)
+        if ($params_desc ne "") {
+          my $id = &CreateValidSGMLID ("$symbol".".parameters");
 
-            output += '''<refsect3 id="%s" role="parameters">\n<title>Parameters</title>
+          $output .= <<EOF;
+<refsect3 id="$id" role="parameters">\n<title>Parameters</title>
 <informaltable role="parameters_table" pgwide="1" frame="none">
 <tgroup cols="3">
 <colspec colname="parameters_name" colwidth="150px"/>
 <colspec colname="parameters_description"/>
 <colspec colname="parameters_annotations" colwidth="200px"/>
 <tbody>
-''' % sid
-            output += params_desc
-            output += "</tbody></tgroup></informaltable>\n</refsect3>"
+EOF
+          $output .= $params_desc;
+          $output .= "</tbody></tgroup></informaltable>\n</refsect3>";
+        }
 
         # Output the returns info last
-        if returns != '':
-            sid = common.CreateValidSGMLID("%s.returns" % symbol)
-
-            output += '''
-<refsect3 id="%s" role=\"returns\">\n<title>Returns</title>
-''' % sid
-            output += returns
-            output += "\n</refsect3>"
+        if ($returns ne "") {
+          my $id = &CreateValidSGMLID ("$symbol".".returns");
 
+          $output .= <<EOF;
+<refsect3 id="$id" role=\"returns\">\n<title>Returns</title>
+EOF
+          $output .= $returns;
+          $output .= "\n</refsect3>";
+        }
 
         # remember missing/unused parameters (needed in tmpl-free build)
-        if missing_parameters != '' and (symbol not in AllIncompleteSymbols):
-            AllIncompleteSymbols[symbol] = missing_parameters
-
-        if unused_parameters != '' and (symbol not in AllUnusedSymbols):
-            AllUnusedSymbols[symbol] = unused_parameters
-
-    if num_params == 0 and len(fields) > 0 and len(field_descrs) > 0:
-        if symbol not in AllIncompleteSymbols:
-            AllIncompleteSymbols[symbol] = "<parameters>"
-    return output
-
+        if (($missing_parameters ne "") and (! exists ($AllIncompleteSymbols{$symbol}))) {
+            $AllIncompleteSymbols{$symbol}=$missing_parameters;
+        }
+        if (($unused_parameters ne "") and (! exists ($AllUnusedSymbols{$symbol}))) {
+            $AllUnusedSymbols{$symbol}=$unused_parameters;
+        }
+    }
+    if (($num_params == 0) && @fields && (scalar(keys(%field_descrs)) > 0)) {
+        if (! exists ($AllIncompleteSymbols{$symbol})) {
+            $AllIncompleteSymbols{$symbol}="<parameters>";
+        }
+    }
+
+    return $output;
+}
 
 
 #############################################################################
@@ -2213,22 +2388,23 @@ def OutputParamDescriptions(symbol_type, symbol, fields):
 # Returns     : The parsed stability level string.
 #############################################################################
 
-def ParseStabilityLevel(stability, file, line, message):
-
-    stability = stability.strip()
-    sl = stability.lower()
-
-    if sl == 'stable':
-        stability = "Stable"
-    elif stability == 'unstable':
-        stability = "Unstable"
-    elif stability == 'private':
-        stability = "Private"
-    else:
-        common.LogWarning(file, line, "%s is %s." % (message, stability) +\
-            "It should be one of these: Stable, Unstable, or Private.")
-    return stability
-
+sub ParseStabilityLevel {
+    my ($stability, $file, $line, $message) = @_;
+
+    $stability =~ s/^\s*//;
+    $stability =~ s/\s*$//;
+    if ($stability =~ m/^stable$/i) {
+        $stability = "Stable";
+    } elsif ($stability =~ m/^unstable$/i) {
+        $stability = "Unstable";
+    } elsif ($stability =~ m/^private$/i) {
+        $stability = "Private";
+    } else {
+        &LogWarning ($file, $line, "$message is $stability.".
+            "It should be one of these: Stable, Unstable, or Private.");
+    }
+    return $stability;
+}
 
 
 #############################################################################
@@ -2239,7 +2415,7 @@ def ParseStabilityLevel(stability, file, line, message):
 #                 will be overridden by the title in the template file.
 #               $section_id - the id to use for the toplevel tag.
 #               $includes - comma-separates list of include files added at top of
-#                 synopsis, with '<' '>' around them (if not already enclosed in '').
+#                 synopsis, with '<' '>' around them (if not already enclosed in "").
 #               $functions_synop - reference to the DocBook for the Functions Synopsis part.
 #               $other_synop - reference to the DocBook for the Types and Values Synopsis part.
 #               $functions_details - reference to the DocBook for the Functions Details part.
@@ -2256,149 +2432,159 @@ def ParseStabilityLevel(stability, file, line, message):
 #               $file_objects - reference to an array of objects in this file
 #############################################################################
 
-def OutputDBFile(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):
+sub OutputDBFile {
+    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) = @_;
 
-    logging.info("Output docbook for file %s with title '%s'\n", file, title)
+    @TRACE@("Output docbook for file $file with title '$title'\n");
 
     # The edited title overrides the one from the sections file.
-    new_title = SymbolDocs[os.path.join(TMPL_DIR, file + ":Title")]
-    if new_title and not re.search(r'^\s*$', new_title):
-        title = new_title
-        logging.info("Found title: %s", title)
-
-    short_desc = SymbolDocs[os.path.join(TMPL_DIR, file + ":Short_Description")]
-    if not short_desc or re.search(r'^\s*$', short_desc):
-        short_desc = ''
-    else:
+    my $new_title = $SymbolDocs{"$TMPL_DIR/$file:Title"};
+    if (defined ($new_title) && $new_title !~ m/^\s*$/) {
+        $title = $new_title;
+        @TRACE@("Found title: $title\n");
+    }
+    my $short_desc = $SymbolDocs{"$TMPL_DIR/$file:Short_Description"};
+    if (!defined ($short_desc) || $short_desc =~ m/^\s*$/) {
+        $short_desc = "";
+    } else {
         # Don't use ConvertMarkDown here for now since we don't want blocks
-        short_desc = ExpandAbbreviations(":Short_description" % title,
-                                         short_desc)
-        logging.info("Found short_desc: %s", short_desc)
-
-    long_desc = SymbolDocs[os.path.join(TMPL_DIR, file + ":Long_Description")]
-    if not long_desc or re.search(r'^\s*$', long_desc):
-        long_desc = ''
-    else:
-        long_desc = ConvertMarkDown(":Long_description" % title,
-                                    long_desc)
-        logging.info("Found long_desc: ", long_desc)
-
-    see_also = SymbolDocs[os.path.join(TMPL_DIR, file + ":See_Also")]
-    if not see_also or re.search(r'^\s*(<para>)?\s*(</para>)?\s*$', see_also):
-        see_also = ''
-    else:
-        see_also = ConvertMarkDown("%s:See_Also" % title, see_also)
-        logging.info("Found see_also: %s", see_also)
-
-    if see_also:
-        see_also = "<refsect1 id=\"%s.see-also\">\n<title>See Also</title>\n%s\n</refsect1>\n" % 
(section_id, see_also)
-
-    stability = SymbolDocs[os.path.join(TMPL_DIR, file + ":Stability_Level")]
-    if not stability or re.search(r'^\s*$', stability):
-        stability = ''
-    else:
-        stability = ParseStabilityLevel(stability, file, line_number, "Section stability level")
-        logging.info("Found stability: %s", stability)
-
-    if stability:
-        AnnotationsUsed[stability] = 1
-        stability = "<refsect1 id=\"%s.stability-level\">\n<title>Stability 
Level</title>\n<acronym>%s</acronym>, unless otherwise indicated\n</refsect1>\n" % (section_id, stability)
-    elif DEFAULT_STABILITY:
-        AnnotationsUsed[DEFAULT_STABILITY] = 1
-        stability = "<refsect1 id=\"%s.stability-level\">\n<title>Stability 
Level</title>\n<acronym>%s</acronym>, unless otherwise indicated\n</refsect1>\n" % (section_id, 
DEFAULT_STABILITY)
-
-
-    image = SymbolDocs[os.path.join(TMPL_DIR, file + ":Image")]
-    if image or re.search(r'^\s*$', image):
-        image = ''
-    else:
-        image = image.strip()
-
-        format = None
-
-        il = image.lower()
-        if re.search(r'jpe?g$', il):
-            format = "format='JPEG'"
-        elif il.endswith('png'):
-            format = "format='PNG'"
-        elif il.endswith('svg'):
-            format = "format='SVG'"
-        else:
-            format = ''
-
-
-        image = "  <inlinegraphic fileref='%s' %s/>\n" % (image, format)
-
-    include_output = ''
-    if includes:
-        include_output += "<refsect1 id=\"%s.includes\"><title>Includes</title><synopsis>" % section_id
-        for include in includes.split(','):
-            if re.search(r'^\".+\"$', include):
-                include_output += "#include %s\n" % include
-            else:
-                include = re.sub(r'^\s+|\s+$', '', include, flags=re.S)
-                include_output += "#include &lt;%s&gt;\n" % include
-
-
-        include_output += "</synopsis></refsect1>\n"
-
-
-    extralinks = OutputSectionExtraLinks(title, "Section:%s" % file)
-
-    old_db_file = os.path.join(DB_OUTPUT_DIR, file + '.xml')
-    new_db_file = os.path.join(DB_OUTPUT_DIR, file, '.xml.new')
-
-    OUTPUT = open(new_db_file, 'w')
-
-    object_anchors = ''
-    for fobject in file_objects:
-        if fobject == section_id:
-            continue
-        sid = common.CreateValidSGMLID(fobject)
-        logging.info("Adding anchor for %s\n", fobject)
-        object_anchors += "<anchor id=\"%s\"/>" % sid
+        $short_desc = &ExpandAbbreviations("$title:Short_description",
+                                           $short_desc);
+        @TRACE@("Found short_desc: $short_desc");
+    }
+    my $long_desc = $SymbolDocs{"$TMPL_DIR/$file:Long_Description"};
+    if (!defined ($long_desc) || $long_desc =~ m/^\s*$/) {
+        $long_desc = "";
+    } else {
+        $long_desc = &ConvertMarkDown("$title:Long_description",
+                                          $long_desc);
+        @TRACE@("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 = &ConvertMarkDown("$title:See_Also", $see_also);
+        @TRACE@("Found see_also: $see_also");
+    }
+    if ($see_also) {
+        $see_also = "<refsect1 id=\"$section_id.see-also\">\n<title>See 
Also</title>\n$see_also\n</refsect1>\n";
+    }
+    my $stability = $SymbolDocs{"$TMPL_DIR/$file:Stability_Level"};
+    if (!defined ($stability) || $stability =~ m/^\s*$/) {
+        $stability = "";
+    } else {
+        $stability = &ParseStabilityLevel($stability, $file, $., "Section stability level");
+        @TRACE@("Found stability: $stability");
+    }
+    if ($stability) {
+        $AnnotationsUsed{$stability} = 1;
+        $stability = "<refsect1 id=\"$section_id.stability-level\">\n<title>Stability 
Level</title>\n<acronym>$stability</acronym>, unless otherwise indicated\n</refsect1>\n";
+    } elsif ($DEFAULT_STABILITY) {
+        $AnnotationsUsed{$DEFAULT_STABILITY} = 1;
+        $stability = "<refsect1 id=\"$section_id.stability-level\">\n<title>Stability 
Level</title>\n<acronym>$DEFAULT_STABILITY</acronym>, unless otherwise indicated\n</refsect1>\n";
+    }
+
+    my $image = $SymbolDocs{"$TMPL_DIR/$file:Image"};
+    if (!defined ($image) || $image =~ m/^\s*$/) {
+      $image = "";
+    } else {
+      $image =~ s/^\s*//;
+      $image =~ s/\s*$//;
+
+      my $format;
+
+      if ($image =~ /jpe?g$/i) {
+        $format = "format='JPEG'";
+      } elsif ($image =~ /png$/i) {
+        $format = "format='PNG'";
+      } elsif ($image =~ /svg$/i) {
+        $format = "format='SVG'";
+      } else {
+        $format = "";
+      }
+
+      $image = "  <inlinegraphic fileref='$image' $format/>\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 = "";
+    if ($includes) {
+      $include_output .= "<refsect1 id=\"$section_id.includes\"><title>Includes</title><synopsis>";
+      my $include;
+      foreach $include (split (/,/, $includes)) {
+        if ($include =~ m/^\".+\"$/) {
+          $include_output .= "#include ${include}\n";
+        }
+        else {
+          $include =~ s/^\s+|\s+$//gs;
+          $include_output .= "#include &lt;${include}&gt;\n";
+        }
+      }
+      $include_output .= "</synopsis></refsect1>\n";
+    }
+
+    my $extralinks = OutputSectionExtraLinks($title,"Section:$file");
+
+    my $old_db_file = "$DB_OUTPUT_DIR/$file.xml";
+    my $new_db_file = "$DB_OUTPUT_DIR/$file.xml.new";
+
+    open (OUTPUT, ">$new_db_file")
+        || die "Can't create $new_db_file: $!";
+
+    my $object_anchors = "";
+    foreach my $object (@$file_objects) {
+        next if ($object eq $section_id);
+        my $id = CreateValidSGMLID($object);
+        @TRACE@("Adding anchor for $object\n");
+        $object_anchors .= "<anchor id=\"$id\"/>";
+    }
 
     # Make sure we produce valid docbook
-    if not functions_details:
-        functions_details = "<para />"
+    $$functions_details ||= "<para />";
 
-    # We used to output this, but is messes up our common.UpdateFileIfChanged code
+    # We used to output this, but is messes up our UpdateFileIfChanged code
     # since it changes every day (and it is only used in the man pages):
     # "<refentry id="$section_id" revision="$mday $month $year">"
 
-    OUTPUT.write(r'''${\( MakeDocHeader ("refentry") )
+    print OUTPUT <<EOF;
+${\( MakeDocHeader ("refentry") )}
 <refentry id="$section_id">
 <refmeta>
-<refentrytitle role="top_of_page" id="%s.top_of_page">%s</refentrytitle>
+<refentrytitle role="top_of_page" id="$section_id.top_of_page">$title</refentrytitle>
 <manvolnum>3</manvolnum>
-<refmiscinfo>\U%s\E Library%s</refmiscinfo>
+<refmiscinfo>\U$MODULE\E Library$image</refmiscinfo>
 </refmeta>
 <refnamediv>
-<refname>%s</refname>
-<refpurpose>%s</refpurpose>
+<refname>$title</refname>
+<refpurpose>$short_desc</refpurpose>
 </refnamediv>
-%s
-%s%s%s%s%s%s%s%s%s%s
+$stability
+$$functions_synop$$args_synop$$signals_synop$object_anchors$$other_synop$$hierarchy$$prerequisites$$derived$$interfaces$$implementations
 $include_output
-<refsect1 id="%s.description" role="desc">
+<refsect1 id="$section_id.description" role="desc">
 <title role="desc.title">Description</title>
-%s%s
+$extralinks$long_desc
 </refsect1>
-<refsect1 id="%s.functions_details" role="details">
+<refsect1 id="$section_id.functions_details" role="details">
 <title role="details.title">Functions</title>
-%s
+$$functions_details
 </refsect1>
-<refsect1 id="%s.other_details" role="details">
+<refsect1 id="$section_id.other_details" role="details">
 <title role="details.title">Types and Values</title>
-%s
+$$other_details
 </refsect1>
-%s%s%s
+$$args_desc$$signals_desc$see_also
 </refentry>
-''' % (section_id, title, MODULE, image, title, short_desc, stability, functions_synop, args_synop, 
signals_synop, object_anchors, other_synop, hierarchy, prerequisites, derived, interfaces, implementations, 
section_id, extralinks, long_desc, section_id, functions_details, section_id, other_details, args_desc, 
signals_desc, see_also))
-    OUTPUT.close()
-
-    return common.UpdateFileIfChanged(old_db_file, new_db_file, 0)
+EOF
+    close (OUTPUT);
 
+    return &UpdateFileIfChanged ($old_db_file, $new_db_file, 0);
+}
 
 #############################################################################
 # Function    : OutputProgramDBFile
@@ -2407,141 +2593,152 @@ $include_output
 #               $section_id - the id to use for the toplevel tag.
 #############################################################################
 
-def OutputProgramDBFile(program, section_id):
-    logging.info("Output program docbook for %s", program)
+sub OutputProgramDBFile {
+    my ($program, $section_id) = @_;
 
-    short_desc = SourceSymbolDocs[os.path.join(TMPL_DIR, program + ":Short_Description")]
-    if not short_desc or re.search(r'^\s*$', short_desc):
-        short_desc = ''
-    else:
-        # Don't use ConvertMarkDown here for now since we don't want blocks
-        short_desc = ExpandAbbreviations(program, short_desc)
-        logging.info("Found short_desc: %s", short_desc)
+    @TRACE@("Output program docbook for $program\n");
 
-    synopsis = SourceSymbolDocs[os.path.join(TMPL_DIR, program + ":Synopsis")]
-    if synopsis and re.search(r'~\s*$', synopsis):
-        items = synopsis.split(' ')
-        for i in range(0, len(items)):
-            parameter = items[i]
-            choice = "plain"
-            rep = ''
+    my $short_desc = $SourceSymbolDocs{"$TMPL_DIR/$program:Short_Description"};
+    if (!defined ($short_desc) || $short_desc =~ m/^\s*$/) {
+        $short_desc = "";
+    } else {
+        # Don't use ConvertMarkDown here for now since we don't want blocks
+        $short_desc = &ExpandAbbreviations("$program", $short_desc);
+        @TRACE@("Found short_desc: $short_desc");
+    }
+
+    my $synopsis = $SourceSymbolDocs{"$TMPL_DIR/$program:Synopsis"};
+    if (defined ($synopsis) && $synopsis !~ m/^\s*$/) {
+        my $i;
+        my @items = split(' ', $synopsis);
+        for ($i = 0; $i <= $#items; $i++) {
+            my $parameter = $items[$i];
+            my $choice = "plain";
+            my $rep = "";
 
             # first parameter is the command name
-            if i == 0:
-                synopsis = "<command>%s</command>\n" % parameter
-                continue
+            if ($i == 0) {
+                $synopsis = "<command>$parameter</command>\n";
+                next;
+            }
 
             # square brackets indicate optional parameters, curly brackets
             # indicate required parameters ("plain" parameters are also
             # mandatory, but do not get extra decoration)
-            m1 = re.search(r'^\[(.+?)\]$', parameter)
-            m2 = re.search(r'^\{(.+?)\}$', parameter)
-            m3 = re.search(r'\.\.\.$', parameter)
-            m4 = re.search(r'\*(.+?)\*', parameter)
-            if m1:
-                choice = "opt"
-            elif m2:
-                choice = "req"
+            if ($parameter =~ s/^\[(.+?)\]$/$1/) {
+                $choice = "opt";
+            } elsif ($parameter =~ s/^\{(.+?)\}$/$1/) {
+                $choice = "req";
+            }
 
             # parameters ending in "..." are repeatable
-            if m3:
-                rep = ' rep=\"repeat\"'
+            if ($parameter =~ s/\.\.\.$//) {
+                $rep = " rep=\"repeat\"";
+            }
 
             # italic parameters are replaceable parameters
-            if m4:
-                parameter = "<replaceable>%s</replaceable>" % parameter
-
-
-            synopsis += "<arg choice=\"%s\"%s>" % (choice, rep)
-            synopsis += parameter
-            synopsis += "</arg>\n"
-
-        logging.info("Found synopsis: %s", synopsis)
-    else:
-        synopsis = "<command>%s</command>" % program
-
-
-    long_desc = SourceSymbolDocs[os.path.join(TMPL_DIR, program + ":Long_Description")]
-    if not long_desc or re.search(r'^\s*$', long_desc):
-        long_desc = ''
-    else:
-        long_desc = ConvertMarkDown("%s:Long_description" % program, long_desc)
-        logging.info("Found long_desc: %s", long_desc)
-
-    options = ''
-    o = os.path.join(TMPL_DIR, program + ":Options")
-    if o in SourceSymbolDocs:
-        opts = SourceSymbolDocs[o]
-
-        options = "<refsect1>\n<title>Options</title>\n<variablelist>\n"
-        for k in range(0, len(opts), 2):
-            opt_desc = opts[k+1]
-
-            opt_desc = re.sub(r'\*(.+?)\*', r'<replaceable>\1<\/replaceable>', opt_desc)
-
-            options += "<varlistentry>\n<term>"
-            opt_names = opts[k].split(' ')
-            for i in range(len(opt_names)):
-                prefix = ', ' if i > 0 else ''
-                opt_names[i] = re.sub(r'\*(.+?)\*', r'<replaceable>\1<\/replaceable>', opt_names[i])
-
-                options += "%s<option>%s</option>\n" % (prefix, opt_names[i])
-
-            options += "</term>\n"
-            options += "<listitem><para>%s</para></listitem>\n" % opt_desc
-            options += "</varlistentry>\n"
-
-        options += "</variablelist></refsect1>\n"
-
-
-    exit_status = SourceSymbolDocs[os.path.join(TMPL_DIR, program + ":Returns")]
-    if exit_status and exit_status != '':
-        exit_status = ConvertMarkDown("%s:Returns" % program, exit_status)
-        exit_status = "<refsect1 id=\"%s.exit-status\">\n<title>Exit Status</title>\n%s\n</refsect1>\n" % 
(section_id, exit_status)
-    else:
-        exit_status = ''
-
-
-    see_also = SourceSymbolDocs[os.path.join(TMPL_DIR, program + ":See_Also")]
-    if see_also or re.search(r'^\s*(<para>)?\s*(</para>)?\s*$', see_also):
-        see_also = ''
-    else:
-        see_also = ConvertMarkDown("%s:See_Also" % program, see_also)
-        logging.info("Found see_also: %s", see_also)
-
-    if see_also:
-        see_also = "<refsect1 id=\"%s.see-also\">\n<title>See Also</title>\n%s\n</refsect1>\n" % 
(section_id, see_also)
-
-
-    old_db_file = os.path.join(DB_OUTPUT_DIR, program + ".xml")
-    new_db_file = os.path.join(DB_OUTPUT_DIR, program + ".xml.new")
-
-    OUTPUT = open(new_db_file, 'w')
-
-    OUTPUT.write('''%s
-<refentry id="%s">
+            if ($parameter =~ s/\*(.+?)\*/$1/) {
+                $parameter = "<replaceable>$parameter</replaceable>";
+            }
+
+            $synopsis .= "<arg choice=\"$choice\"$rep>";
+            $synopsis .= $parameter;
+            $synopsis .= "</arg>\n";
+        }
+
+        @TRACE@("Found synopsis: $synopsis");
+    } else {
+        $synopsis = "<command>$program</command>";
+    }
+
+    my $long_desc = $SourceSymbolDocs{"$TMPL_DIR/$program:Long_Description"};
+    if (!defined ($long_desc) || $long_desc =~ m/^\s*$/) {
+        $long_desc = "";
+    } else {
+        $long_desc = &ConvertMarkDown("$program:Long_description", $long_desc);
+        @TRACE@("Found long_desc: $long_desc");
+    }
+
+    my $options = "";
+    if (defined ($SourceSymbolDocs{"$TMPL_DIR/$program:Options"})) {
+        my @opts = @{ $SourceSymbolDocs{"$TMPL_DIR/$program:Options"} };
+        my $k;
+
+        $options = "<refsect1>\n<title>Options</title>\n<variablelist>\n";
+        for ($k = 0; $k <= $#opts; $k += 2) {
+            my $opt_desc = $opts[$k+1];
+            my @opt_names;
+            my $i;
+
+            $opt_desc =~ s/\*(.+?)\*/<replaceable>$1<\/replaceable>/g;
+
+            $options .= "<varlistentry>\n<term>";
+            @opt_names = split (',', $opts[$k]);
+            for ($i = 0; $i <= $#opt_names; $i++) {
+                my $prefix = ($i > 0) ? ", " : "";
+                $opt_names[$i] =~ s/\*(.+?)\*/<replaceable>$1<\/replaceable>/g;
+
+                $options .= "$prefix<option>$opt_names[$i]</option>\n";
+            }
+            $options .= "</term>\n";
+            $options .= "<listitem><para>$opt_desc</para></listitem>\n";
+            $options .= "</varlistentry>\n";
+        }
+        $options .= "</variablelist></refsect1>\n";
+    }
+
+    my $exit_status = $SourceSymbolDocs{"$TMPL_DIR/$program:Returns"};
+    if (defined ($exit_status) && $exit_status ne "") {
+        $exit_status = &ConvertMarkDown("$program:Returns", $exit_status);
+        $exit_status = "<refsect1 id=\"$section_id.exit-status\">\n<title>Exit 
Status</title>\n$exit_status\n</refsect1>\n";
+    } else {
+        $exit_status = "";
+    }
+
+    my $see_also = $SourceSymbolDocs{"$TMPL_DIR/$program:See_Also"};
+    if (!defined ($see_also) || $see_also =~ m%^\s*(<para>)?\s*(</para>)?\s*$%) {
+        $see_also = "";
+    } else {
+        $see_also = &ConvertMarkDown("$program:See_Also", $see_also);
+        @TRACE@("Found see_also: $see_also");
+    }
+    if ($see_also) {
+        $see_also = "<refsect1 id=\"$section_id.see-also\">\n<title>See 
Also</title>\n$see_also\n</refsect1>\n";
+    }
+
+    my $old_db_file = "$DB_OUTPUT_DIR/$program.xml";
+    my $new_db_file = "$DB_OUTPUT_DIR/$program.xml.new";
+
+    open (OUTPUT, ">$new_db_file")
+        || die "Can't create $new_db_file: $!";
+
+    print OUTPUT <<EOF;
+${\( MakeDocHeader ("refentry") )}
+<refentry id="$section_id">
 <refmeta>
-<refentrytitle role="top_of_page" id="%s.top_of_page">$program</refentrytitle>
+<refentrytitle role="top_of_page" id="$section_id.top_of_page">$program</refentrytitle>
 <manvolnum>1</manvolnum>
 <refmiscinfo>User Commands</refmiscinfo>
 </refmeta>
 <refnamediv>
-<refname>%s</refname>
-<refpurpose>%s</refpurpose>
+<refname>$program</refname>
+<refpurpose>$short_desc</refpurpose>
 </refnamediv>
 <refsynopsisdiv>
-<cmdsynopsis>%s</cmdsynopsis>
+<cmdsynopsis>$synopsis</cmdsynopsis>
 </refsynopsisdiv>
-<refsect1 id="%s.description" role="desc">
+<refsect1 id="$section_id.description" role="desc">
 <title role="desc.title">Description</title>
-%s
+$long_desc
 </refsect1>
-%s%s%s
+$options$exit_status$see_also
 </refentry>
-''' % (MakeDocHeader("refentry"), section_id, section_id, program, short_desc, synopsis, section_id, 
long_desc, options, exit_status, see_also))
-    OUTPUT.close()
+EOF
+    close (OUTPUT);
+
+    return &UpdateFileIfChanged ($old_db_file, $new_db_file, 0);
+}
 
-    return common.UpdateFileIfChanged(old_db_file, new_db_file, 0)
 
 
 #############################################################################
@@ -2550,22 +2747,33 @@ def OutputProgramDBFile(program, section_id):
 #               expanding abbreviations
 # Arguments   : $file - the source file.
 #############################################################################
-def OutputExtraFile(file):
+sub OutputExtraFile {
+    my ($file) = @_;
+
+    my $basename;
 
-    basename = re.sub(r'^.*/', '', file)
+    ($basename = $file) =~ s!^.*/!!;
 
-    old_db_file = os.path.join(DB_OUTPUT_DIR, basename)
-    new_db_file = os.path.join(DB_OUTPUT_DIR, basename + ".new")
+    my $old_db_file = "$DB_OUTPUT_DIR/$basename";
+    my $new_db_file = "$DB_OUTPUT_DIR/$basename.new";
 
-    contents = open(file).read()
+    my $contents;
 
-    OUTPUT = open(new_db_file, 'w')
+    open(EXTRA_FILE, "<$file") || die "Can't open $file";
 
-    OUTPUT.write(ExpandAbbreviations(basename + " file", contents))
-    OUTPUT.close()
+    {
+        local $/;
+        $contents = <EXTRA_FILE>;
+    }
 
-    return common.UpdateFileIfChanged(old_db_file, new_db_file, 0)
+    open (OUTPUT, ">$new_db_file")
+        || die "Can't create $new_db_file: $!";
 
+    print OUTPUT &ExpandAbbreviations ("$basename file", $contents);
+    close (OUTPUT);
+
+    return &UpdateFileIfChanged ($old_db_file, $new_db_file, 0);
+}
 #############################################################################
 # Function    : OutputBook
 # Description : Outputs the entities that need to be included into the
@@ -2576,34 +2784,39 @@ def OutputExtraFile(file):
 #                  added in the main docbook file at the desired position.
 #############################################################################
 
-def OutputBook(book_top, book_bottom):
+sub OutputBook {
+    my ($book_top, $book_bottom) = @_;
 
-    old_file = os.path.join(DB_OUTPUT_DIR, MODULE + "-doc.top")
-    new_file = os.path.join(DB_OUTPUT_DIR, MODULE + "-doc.top.new")
+    my $old_file = "$DB_OUTPUT_DIR/$MODULE-doc.top";
+    my $new_file = "$DB_OUTPUT_DIR/$MODULE-doc.top.new";
 
-    OUTPUT = open(new_file, 'w')
-    OUTPUT.write(book_top)
-    OUTPUT.close()
+    open (OUTPUT, ">$new_file")
+        || die "Can't create $new_file: $!";
+    print OUTPUT $book_top;
+    close (OUTPUT);
 
-    common.UpdateFileIfChanged(old_file, new_file, 0)
+    &UpdateFileIfChanged ($old_file, $new_file, 0);
 
 
-    old_file = os.path.join(DB_OUTPUT_DIR, MODULE + "-doc.bottom")
-    new_file = os.path.join(DB_OUTPUT_DIR, MODULE + "-doc.bottom.new")
+    $old_file = "$DB_OUTPUT_DIR/$MODULE-doc.bottom";
+    $new_file = "$DB_OUTPUT_DIR/$MODULE-doc.bottom.new";
 
-    OUTPUT = open(new_file, 'w')
-    OUTPUT.write(book_bottom)
-    OUTPUT.close()
+    open (OUTPUT, ">$new_file")
+        || die "Can't create $new_file: $!";
+    print OUTPUT $book_bottom;
+    close (OUTPUT);
 
-    common.UpdateFileIfChanged(old_file, new_file, 0)
+    &UpdateFileIfChanged ($old_file, $new_file, 0);
 
 
     # If the main docbook file hasn't been created yet, we create it here.
     # The user can tweak it later.
-    if MAIN_SGML_FILE and not os.path.exists(MAIN_SGML_FILE):
-        OUTPUT = open(MAIN_SGML_FILE, 'w')
+    if ($MAIN_SGML_FILE && ! -e $MAIN_SGML_FILE) {
+        open (OUTPUT, ">$MAIN_SGML_FILE")
+          || die "Can't create $MAIN_SGML_FILE: $!";
 
-        OUTPUT.write('''
+        print OUTPUT <<EOF;
+${\( MakeDocHeader ("book") )}
 <book id="index">
   <bookinfo>
     <title>&package_name; Reference Manual</title>
@@ -2618,23 +2831,26 @@ def OutputBook(book_top, book_bottom):
     <title>[Insert title here]</title>
     $book_bottom
   </chapter>
-''' % MakeDocHeader("book"))
-        if os.path.exists(OBJECT_TREE_FILE):
-            OUTPUT.write('''  <chapter id="object-tree">
+EOF
+        if (-e $OBJECT_TREE_FILE) {
+            print OUTPUT <<EOF;
+  <chapter id="object-tree">
     <title>Object Hierarchy</title>
     <xi:include href="xml/tree_index.sgml"/>
   </chapter>
-''')
-        else:
-            OUTPUT.write('''  <!-- enable this when you use gobject types
+EOF
+        } else {
+            print OUTPUT <<EOF;
+  <!-- enable this when you use gobject types
   <chapter id="object-tree">
     <title>Object Hierarchy</title>
     <xi:include href="xml/tree_index.sgml"/>
   </chapter>
   -->
-''')
-
-        OUTPUT.write('''  <index id="api-index-full">
+EOF
+        }
+        print OUTPUT <<EOF;
+  <index id="api-index-full">
     <title>API Index</title>
     <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
   </index>
@@ -2642,21 +2858,26 @@ def OutputBook(book_top, book_bottom):
     <title>Index of deprecated API</title>
     <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
   </index>
-''')
-        if len(AnnotationsUsed) > 0:
-            OUTPUT.write('''  <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
-''')
-        else:
-            OUTPUT.write('''  <!-- enable this when you use gobject introspection annotations
+EOF
+        if (keys(%AnnotationsUsed)) {
+            print OUTPUT <<EOF;
+  <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
+EOF
+        } else {
+            print OUTPUT <<EOF;
+  <!-- enable this when you use gobject introspection annotations
   <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
   -->
-''')
-
-        OUTPUT.write('''
+EOF
+        }
+        print OUTPUT <<EOF;
 </book>
-''')
+EOF
+
+        close (OUTPUT);
+    }
+}
 
-        OUTPUT.close()
 
 #############################################################################
 # Function    : CreateValidSGML
@@ -2665,14 +2886,15 @@ def OutputBook(book_top, book_bottom):
 # Arguments   : $text - the text to turn into proper SGML.
 #############################################################################
 
-def CreateValidSGML(text):
-    text = re.sub(r'&', r'&amp;', text)        # Do this first, or the others get messed up.
-    text = re.sub(r'<', r'&lt;', text)
-    text = re.sub(r'>', r'&gt;', text)
-    # browsers render single tabs inconsistently
-    text = re.sub(r'([^\s])\t([^\s])', r'\1&#160;\2', text)
-    return text
-
+sub CreateValidSGML {
+    my ($text) = @_;
+    $text =~ s/&/&amp;/g;        # Do this first, or the others get messed up.
+    $text =~ s/</&lt;/g;
+    $text =~ s/>/&gt;/g;
+    # browers render single tabs inconsistently
+    $text =~ s/([^\s])\t([^\s])/$1&#160;$2/g;
+    return $text;
+}
 
 #############################################################################
 # Function    : ConvertSGMLChars
@@ -2684,63 +2906,77 @@ def CreateValidSGML(text):
 # Arguments   : $text - the text to turn into proper SGML.
 #############################################################################
 
-def ConvertSGMLChars(symbol, text):
+sub ConvertSGMLChars {
+    my ($symbol, $text) = @_;
 
-    if INLINE_MARKUP_MODE:
+    if ($INLINE_MARKUP_MODE) {
         # For the XML/SGML mode only convert to entities outside CDATA sections.
-        return ModifyXMLElements(text, symbol,
-                                 "<!\\[CDATA\\[|<programlisting[^>]*>",
-                                 ConvertSGMLCharsEndTag,
-                                 ConvertSGMLCharsCallback)
-    # For the simple non-sgml mode, convert to entities everywhere.
-
-    # First, convert freestanding & to &amp
-    text = re.sub(r'&(?![a-zA-Z#]+;)', r'&amp;', text)
-    text = re.sub(r'<', r'/&lt', text)
-    # Allow ">" at beginning of string for blockquote markdown
-    text = re.sub(r'''(?<=[^\w\n"'\/-])>''', r'&gt;', text)
-
-    return text
-
-def ConvertSGMLCharsEndTag(t):
-    if t == r'<!\[CDATA\[':
-        return "]]>"
-    return "</programlisting>"
-
-def ConvertSGMLCharsCallback(text, symbol, tag):
-    if re.search(r'^<programlisting', tag):
-        # We can handle <programlisting> specially here.
-        return ModifyXMLElements(text, symbol,
-                                 "<!\\[CDATA\\[",
-                                 ConvertSGMLCharsEndTag,
-                                 ConvertSGMLCharsCallback2)
-    elif tag == '':
-        # If we're not in CDATA convert to entities.
-        text = re.sub(r'&(?![a-zA-Z#]+;)', r'&amp;', text)        # Do this first, or the others get messed 
up.
-        text = re.sub(r'<(?![a-zA-Z\/!])', r'&lt;', text)
+        return &ModifyXMLElements ($text, $symbol,
+                                   "<!\\[CDATA\\[|<programlisting[^>]*>",
+                                   \&ConvertSGMLCharsEndTag,
+                                   \&ConvertSGMLCharsCallback);
+    } else {
+        # For the simple non-sgml mode, convert to entities everywhere.
+
+       # First, convert freestanding & to &amp;
+        $text =~ s/&(?![a-zA-Z#]+;)/&amp;/g;
+        $text =~ s/</&lt;/g;
         # Allow ">" at beginning of string for blockquote markdown
-        text = re.sub(r'''(?<=[^\w\n"'\/-])>''', r'&gt;', text)
+        $text =~ s/(?<=[^\w\n"'\/-])>/&gt;/g;
 
-        # Handle "#include <xxxxx>"
-        text = re.sub(r'#include(\s+)<([^>]+)>', r'#include\1&lt;\2&gt;', text)
+        return $text;
+    }
+}
 
-    return text
 
+sub ConvertSGMLCharsEndTag {
+  if ($_[0] eq "<!\[CDATA\[") {
+    return "]]>";
+  } else {
+    return "</programlisting>";
+  }
+}
 
-def ConvertSGMLCharsCallback2(text, symbol, tag):
+sub ConvertSGMLCharsCallback {
+  my ($text, $symbol, $tag) = @_;
 
+  if ($tag =~ m/^<programlisting/) {
+    # We can handle <programlisting> specially here.
+    return &ModifyXMLElements ($text, $symbol,
+                               "<!\\[CDATA\\[",
+                               \&ConvertSGMLCharsEndTag,
+                               \&ConvertSGMLCharsCallback2);
+  } elsif ($tag eq "") {
     # If we're not in CDATA convert to entities.
-    # We could handle <programlisting> differently, though I'm not sure it helps.
-    if tag == '':
-        # replace only if its not a tag
-        text = re.sub(r'&(?![a-zA-Z#]+;)', r'&amp;', text)        # Do this first, or the others get messed 
up.
-        text = re.sub(r'<(?![a-zA-Z\/!])', r'&lt;', text)
-        text = re.sub(r'''(?<![a-zA-Z0-9"'\/-])>''', r'&gt;', text)
-        # Handle "#include <xxxxx>"
-        text = re.sub(r'/#include(\s+)<([^>]+)>', r'#include\1&lt;\2&gt;', text)
+    $text =~ s/&(?![a-zA-Z#]+;)/&amp;/g;        # Do this first, or the others get messed up.
+    $text =~ s/<(?![a-zA-Z\/!])/&lt;/g;
+    # Allow ">" at beginning of string for blockquote markdown
+    $text =~ s/(?<=[^\w\n"'\/-])>/&gt;/g;
+
+    # Handle "#include <xxxxx>"
+    $text =~ s/#include(\s+)<([^>]+)>/#include$1&lt;$2&gt;/g;
+  }
 
-    return text
+  return $text;
+}
+
+sub ConvertSGMLCharsCallback2 {
+  my ($text, $symbol, $tag) = @_;
+
+  # If we're not in CDATA convert to entities.
+  # We could handle <programlisting> differently, though I'm not sure it helps.
+  if ($tag eq "") {
+    # replace only if its not a tag
+    $text =~ s/&(?![a-zA-Z#]+;)/&amp;/g;        # Do this first, or the others get messed up.
+    $text =~ s/<(?![a-zA-Z\/!])/&lt;/g;
+    $text =~ s/(?<![a-zA-Z0-9"'\/-])>/&gt;/g;
 
+    # Handle "#include <xxxxx>"
+    $text =~ s/#include(\s+)<([^>]+)>/#include$1&lt;$2&gt;/g;
+  }
+
+  return $text;
+}
 
 #############################################################################
 # Function    : ExpandAnnotation
@@ -2748,51 +2984,55 @@ def ConvertSGMLCharsCallback2(text, symbol, tag):
 # Arguments   : $symbol - the symbol being documented, for error messages.
 #                $text - the text to expand.
 #############################################################################
-def ExpandAnnotation(symbol, param_desc):
-    param_annotations = ''
+sub ExpandAnnotation {
+    my ($symbol, $param_desc) = @_;
+    my $param_annotations = "";
 
     # look for annotations at the start of the comment part
     # function level annotations don't end with a colon ':'
-    m = re.search(r'^\s*\((.*?)\)(:|$)', param_desc)
-    if m:
-        param_desc = param_desc[m.end():]
-
-        annotations = re.split(r'\)\s*\(', m.group(1))
-        logging.info("annotations for %s: '%s'\n", symbol, m.group(1))
-        for annotation in annotations:
+    if ($param_desc =~ m%^\s*\((.*?)\)(:|$)%) {
+        my @annotations;
+        my $annotation;
+        $param_desc = $';
+
+        @annotations = split(/\)\s*\(/,$1);
+        @TRACE@("annotations for $symbol: '$1'\n");
+        foreach $annotation (@annotations) {
             # need to search for the longest key-match in %AnnotationDefinition
-            match_length = 0
-            match_annotation = ''
-
-            for annotationdef in AnnotationDefinition:
-                if annotation.startswith(annotationdef):
-                    if len(annotationdef) > match_length:
-                        match_length = len(annotationdef)
-                        match_annotation = annotationdef
-
-            annotation_extra = ''
-            if match_annotation != '':
-                m = re.search(match_annotation + r'\s+(.*)', annotation)
-                if m:
-                    annotation_extra = " " + m.group(1)
-
-                AnnotationsUsed[match_annotation] = 1
-                param_annotations += "[<acronym>%s</acronym>%s]" % (match_annotation, annotation_extra)
-            else:
-                common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                  "unknown annotation \"%s\" in documentation for %s." % (annotation, 
symbol))
-                param_annotations += "[%s]" % annotation
-
-
-        param_desc = param_desc.strip()
-        m = re.search(r'^(.*?)\.*\s*$', param_desc)
-        param_desc = "%s. " % m.group(1)
-
-    if param_annotations != '':
-        param_annotations = "<emphasis role=\"annotation\">%s</emphasis>" % param_annotations
-
-    return (param_desc, param_annotations)
-
+            my $match_length=0;
+            my $match_annotation="";
+            my $annotationdef;
+            foreach $annotationdef (keys %AnnotationDefinition) {
+                if ($annotation =~ m/^$annotationdef/) {
+                    if (length($annotationdef)>$match_length) {
+                        $match_length=length($annotationdef);
+                        $match_annotation=$annotationdef;
+                    }
+                }
+            }
+            my $annotation_extra = "";
+            if ($match_annotation ne "") {
+                if ($annotation =~ m%$match_annotation\s+(.*)%) {
+                    $annotation_extra = " $1";
+                }
+                $AnnotationsUsed{$match_annotation} = 1;
+                $param_annotations .= "[<acronym>$match_annotation</acronym>$annotation_extra]";
+            }
+            else {
+                &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                    "unknown annotation \"$annotation\" in documentation for $symbol.");
+                $param_annotations .= "[$annotation]";
+            }
+        }
+        chomp($param_desc);
+        $param_desc =~ m/^(.*?)\.*\s*$/s;
+        $param_desc = "$1. ";
+    }
+    if ($param_annotations ne "") {
+        $param_annotations = "<emphasis role=\"annotation\">$param_annotations</emphasis>";
+    }
+    return ($param_desc, $param_annotations);
+}
 
 #############################################################################
 # Function    : ExpandAbbreviations
@@ -2803,130 +3043,133 @@ def ExpandAnnotation(symbol, param_desc):
 #                $text - the text to expand.
 #############################################################################
 
-def ExpandAbbreviations(symbol, text):
-    # Note: This is a fallback and normally done in the markdown parser
+sub ExpandAbbreviations {
+  my ($symbol, $text) = @_;
+
+  # Note: This is a fallback and normally done in the markdown parser
 
-    # Convert "|[" and "]|" into the start and end of program listing examples.
-    # Support \[<!-- language="C" --> modifiers
-    text = re.sub(r'\|\[<!-- language="([^"]+)" -->', r'<informalexample><programlisting 
language="\1"><![CDATA[', text)
-    text = re.sub(r'\|\[', r'<informalexample><programlisting><![CDATA[', text)
-    text = re.sub(r'\]\|', r']]></programlisting></informalexample>', text)
+  # Convert "|[" and "]|" into the start and end of program listing examples.
+  # Support \[<!-- language="C" --> modifiers
+  $text =~ s%\|\[<!-- language="([^"]+)" -->%<informalexample><programlisting language="$1"><![CDATA[%g;
+  $text =~ s%\|\[%<informalexample><programlisting><![CDATA[%g;
+  $text =~ s%\]\|%]]></programlisting></informalexample>%g;
 
-    # keep CDATA unmodified, preserve ulink tags (ideally we preseve all tags
-    # as such)
-    return ModifyXMLElements(text, symbol,
+  # keep CDATA unmodified, preserve ulink tags (ideally we preseve all tags
+  # as such)
+  return &ModifyXMLElements ($text, $symbol,
                              "<!\\[CDATA\\[|<ulink[^>]*>|<programlisting[^>]*>|<!DOCTYPE",
-                             ExpandAbbreviationsEndTag,
-                             ExpandAbbreviationsCallback)
+                             \&ExpandAbbreviationsEndTag,
+                             \&ExpandAbbreviationsCallback);
+}
 
 
 # Returns the end tag (as a regexp) corresponding to the given start tag.
-def ExpandAbbreviationsEndTag(start_tag):
-    if start_tag == r'<!\[CDATA\[':
-        return "]]>"
-    if start_tag == "<!DOCTYPE":
-        return ">"
-    m = re.search(r'<(\w+)', start_tag)
-    return "</%s>" % m.group(1)
+sub ExpandAbbreviationsEndTag {
+  my ($start_tag) = @_;
+
+  if ($start_tag eq "<!\[CDATA\[") {
+    return "]]>";
+  } elsif ($start_tag eq "<!DOCTYPE") {
+    return ">";
+  } elsif ($start_tag =~ m/<(\w+)/) {
+    return "</$1>";
+  }
+}
 
 # Called inside or outside each CDATA or <programlisting> section.
-def ExpandAbbreviationsCallback(text, symbol, tag):
-
-    if tag.startswith(r'^<programlisting'):
-        # Handle any embedded CDATA sections.
-        return ModifyXMLElements(text, symbol,
-                                 "<!\\[CDATA\\[",
-                                 ExpandAbbreviationsEndTag,
-                                 ExpandAbbreviationsCallback2)
-    elif tag == '':
-        # NOTE: this is a fallback. It is normally done by the Markdown parser.
-
-        # We are outside any CDATA or <programlisting> sections, so we expand
-        # any gtk-doc abbreviations.
-
-        # Convert '@param()'
-        # FIXME: we could make those also links ($symbol.$2), but that would be less
-        # useful as the link target is a few lines up or down
-        text = re.sub(r'(\A|[^\\])\@(\w+((\.|->)\w+)*)\s*\(\)', r'\1<parameter>\2()', text)
-
-        # Convert 'function()' or 'macro()'.
-        # if there is abc_*_def() we don't want to make a link to _def()
-        # FIXME: also handle abc(def(....)) : but that would need to be done recursively :/
-        def f1(m):
-            return '%s.%s;' % (m.group(1), MakeXRef(m.group(2), tagify(m.group(2) + "()", "function")))
-        text = re.sub(r'([^\*.\w])(\w+)\s*\(\)', f1, text)
-        # handle #Object.func()
-        text = re.sub(r'(\A|[^\\])#([\w\-:\.]+[\w]+)\s*\(\)', f1, text)
+sub ExpandAbbreviationsCallback {
+  my ($text, $symbol, $tag) = @_;
+
+  if ($tag =~ m/^<programlisting/) {
+    # Handle any embedded CDATA sections.
+    return &ModifyXMLElements ($text, $symbol,
+                               "<!\\[CDATA\\[",
+                               \&ExpandAbbreviationsEndTag,
+                               \&ExpandAbbreviationsCallback2);
+  } elsif ($tag eq "") {
+    # NOTE: this is a fallback. It is normally done by the Markdown parser.
+
+    # We are outside any CDATA or <programlisting> sections, so we expand
+    # any gtk-doc abbreviations.
+
+    # Convert '@param()'
+    # FIXME: we could make those also links ($symbol.$2), but that would be less
+    # useful as the link target is a few lines up or down
+    $text =~ s/(\A|[^\\])\@(\w+((\.|->)\w+)*)\s*\(\)/$1<parameter>$2()<\/parameter>/g;
 
-        # Convert '@param', but not '\@param'.
-        text = re.sub(r'(\A|[^\\])\@(\w+((\.|->)\w+)*)', r'\1<parameter>\2<\/parameter>', text)
-        text = re.sub(r'/\\\@', r'\@', text)
-
-        # Convert '%constant', but not '\%constant'.
-        # Also allow negative numbers, e.g. %-1.
-        def f2(m):
-            return '%s.%s;' % (m.group(1), MakeXRef(m.group(2), tagify(m.group(2), "literal")))
-        text = re.sub(r'(\A|[^\\])\%(-?\w+)', f2, text)
-        text = re.sub(r'\\\%', r'\%', text)
+    # Convert 'function()' or 'macro()'.
+    # if there is abc_*_def() we don't want to make a link to _def()
+    # FIXME: also handle abc(def(....)) : but that would need to be done recursively :/
+    $text =~ s/([^\*.\w])(\w+)\s*\(\)/$1.&MakeXRef($2, &tagify($2 . "()", "function"));/eg;
+    # handle #Object.func()
+    $text =~ s/(\A|[^\\])#([\w\-:\.]+[\w]+)\s*\(\)/$1.&MakeXRef($2, &tagify($2 . "()", "function"));/eg;
 
-        # Convert '#symbol', but not '\#symbol'.
-        def f3(m):
-            return '%s.%s;' % (m.group(1), MakeHashXRef(m.group(2), "type"))
-        text = re.sub(r'(\A|[^\\])#([\w\-:\.]+[\w]+)', f3, text)
-        text = re.sub(r'\\#', '#', text)
+    # Convert '@param', but not '\@param'.
+    $text =~ s/(\A|[^\\])\@(\w+((\.|->)\w+)*)/$1<parameter>$2<\/parameter>/g;
+    $text =~ s/\\\@/\@/g;
 
+    # Convert '%constant', but not '\%constant'.
+    # Also allow negative numbers, e.g. %-1.
+    $text =~ s/(\A|[^\\])\%(-?\w+)/$1.&MakeXRef($2, &tagify($2, "literal"));/eg;
+    $text =~ s/\\\%/\%/g;
 
-    return text
+    # Convert '#symbol', but not '\#symbol'.
+    $text =~ s/(\A|[^\\])#([\w\-:\.]+[\w]+)/$1.&MakeHashXRef($2, "type");/eg;
+    $text =~ s/\\#/#/g;
+  }
 
+  return $text;
+}
 
 # This is called inside a <programlisting>
-def ExpandAbbreviationsCallback2(text, symbol, tag):
-    if tag == '':
-        # We are inside a <programlisting> but outside any CDATA sections,
-        # so we expand any gtk-doc abbreviations.
-        # FIXME: why is this different from &ExpandAbbreviationsCallback(),
-        #        why not just call it
-        text = re.sub(r'#(\w+)', lambda m: '%s;' % MakeHashXRef(m.group(1), ''), text)
-    elif tag == "<![CDATA[":
-        # NOTE: this is a fallback. It is normally done by the Markdown parser.
-        text = ReplaceEntities(text, symbol)
-
-
-    return text
-
+sub ExpandAbbreviationsCallback2 {
+  my ($text, $symbol, $tag) = @_;
+
+  if ($tag eq "") {
+    # We are inside a <programlisting> but outside any CDATA sections,
+    # so we expand any gtk-doc abbreviations.
+    # FIXME: why is this different from &ExpandAbbreviationsCallback(),
+    #        why not just call it
+    $text =~ s/#(\w+)/&MakeHashXRef($1, "");/eg;
+  } elsif ($tag eq "<![CDATA[") {
+    # NOTE: this is a fallback. It is normally done by the Markdown parser.
+    $text = &ReplaceEntities ($text, $symbol);
+  }
+
+  return $text;
+}
 
-def MakeHashXRef(symbol, tag):
-    text = symbol
+sub MakeHashXRef {
+    my ($symbol, $tag) = @_;;
+    my $text = $symbol;
 
     # Check for things like '#include', '#define', and skip them.
-    if PreProcessorDirectives[symbol]:
-        return "#%s" % symbol
+    if ($PreProcessorDirectives{$symbol}) {
+      return "#$symbol";
+    }
 
     # Get rid of special suffixes ('-struct','-enum').
-    text = re.sub(r'-struct$', '', text)
-    text = re.sub(r'-enum$', '', text)
+    $text =~ s/-struct$//;
+    $text =~ s/-enum$//;
 
     # If the symbol is in the form "Object::signal", then change the symbol to
     # "Object-signal" and use "signal" as the text.
-    if '::' in symbol:
-        o, s = symbol.split('::', 1)
-        symbol = '%s-%s' % (o, s)
-        text = s
+    if ($symbol =~ s/::/-/) {
+      $text = "“$'”";
+    }
 
     # If the symbol is in the form "Object:property", then change the symbol to
     # "Object--property" and use "property" as the text.
-    if '-' in symbol:
-        o, p = symbol.split(':', 1)
-        symbol = '%s--%s' % (o, p)
-        text = p
-
-
-    if tag != '':
-        text = tagify(text, tag)
-
+    if ($symbol =~ s/:/--/) {
+      $text = "“$'”";
+    }
 
-    return MakeXRef(symbol, text)
+    if ($tag ne "") {
+      $text = tagify ($text, $tag);
+    }
 
+    return &MakeXRef($symbol, $text);
+}
 
 
 #############################################################################
@@ -2945,55 +3188,57 @@ def MakeHashXRef(symbol, tag):
 #                      and should return the appropriate end tag string regexp.
 #               $callback - callback called with each part of the text. It is
 #                      called with a piece of text, the symbol being
-#                      documented, and the matched start tag or '' if the text
+#                      documented, and the matched start tag or "" if the text
 #                      is outside the XML elements being matched.
 #############################################################################
-def ModifyXMLElements(text, symbol, start_tag_regexp, end_tag_func, callback):
-    before_tag = start_tag = end_tag_regexp = end_tag = None
-    result = ''
-
-    m = re.search(start_tag_regexp, text, flags=re.S)
-    while m:
-        before_tag = text[0:m.begin()] # Prematch for last successful match string
-        start_tag = m.group(0)      # Last successful match
-        text = text[m.end():]       # Postmatch for last successful match string
-
-        result += callback(before_tag, symbol, '')
-        result += start_tag
-
-        # get the matching end-tag for current tag
-        end_tag_regexp = end_tag_func(start_tag)
-
-        m2 = re.search(end_tag_regexp, text, flags=re.S)
-        if m2:
-            before_tag = text[0:m2.begin()]
-            end_tag = m2.group(0)
-            text = text[m2.end():]
-
-            result += callback(before_tag, symbol, start_tag)
-            result += end_tag
-        else:
-            common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                              "Can't find tag end: %s in docs for: %s." % (end_tag_regexp, symbol))
-            # Just assume it is all inside the tag.
-            result += callback(text, symbol, start_tag)
-            text = ''
-        m = re.search(start_tag_regexp, text, flags=re.S)
+sub ModifyXMLElements {
+    my ($text, $symbol, $start_tag_regexp, $end_tag_func, $callback) = @_;
+    my ($before_tag, $start_tag, $end_tag_regexp, $end_tag);
+    my $result = "";
+
+    while ($text =~ m/$start_tag_regexp/s) {
+      $before_tag = $`; # Prematch for last successful match string
+      $start_tag = $&;  # Last successful match
+      $text = $';       # Postmatch for last successful match string
+
+      $result .= &$callback ($before_tag, $symbol, "");
+      $result .= $start_tag;
+
+      # get the matching end-tag for current tag
+      $end_tag_regexp = &$end_tag_func ($start_tag);
+
+      if ($text =~ m/$end_tag_regexp/s) {
+        $before_tag = $`;
+        $end_tag = $&;
+        $text = $';
+
+        $result .= &$callback ($before_tag, $symbol, $start_tag);
+        $result .= $end_tag;
+      } else {
+        &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+            "Can't find tag end: $end_tag_regexp in docs for: $symbol.");
+        # Just assume it is all inside the tag.
+        $result .= &$callback ($text, $symbol, $start_tag);
+        $text = "";
+      }
+    }
 
     # Handle any remaining text outside the tags.
-    result += callback(text, symbol, '')
-
-    return result
-
+    $result .= &$callback ($text, $symbol, "");
 
-def noop(*args):
-    return args[0]
+    return $result;
+}
 
+sub noop {
+  return $_[0];
+}
 
 # Adds a tag around some text.
 # e.g tagify("Text", "literal") => "<literal>Text</literal>".
-def tagify(text, elem):
-    return "<" + elem + ">" + +text + "</" + +elem + ">"
+sub tagify {
+   my ($text, $elem) = @_;
+   return "<" . $elem . ">" . $text . "</" . $elem . ">";
+}
 
 #############################################################################
 # Function    : MakeDocHeader
@@ -3001,15 +3246,18 @@ def tagify(text, elem):
 # Arguments   : $tag - doctype tag
 #############################################################################
 
-def MakeDocHeader(tag):
-    header = doctype_header
-    header = re.sub(r'<!DOCTYPE \w+', r'<!DOCTYPE ' + tag, header)
+sub MakeDocHeader {
+    my ($tag) = @_;
+    my $header = $doctype_header;
+    $header =~ s/<!DOCTYPE \w+/<!DOCTYPE $tag/;
 
     # fix the path for book since this is one level up
-    if tag == "book":
-        header = re.sub(r'<!ENTITY % gtkdocentities SYSTEM \"../([a-zA-Z./]+)\">', r'<!ENTITY % 
gtkdocentities SYSTEM \"\1\">', header)
-    return header
+    if ($tag eq "book") {
+        $header =~ s#<!ENTITY % gtkdocentities SYSTEM \"../([a-zA-Z./]+)\">#<!ENTITY % gtkdocentities SYSTEM 
\"$1\">#;
+    }
 
+    return $header;
+}
 
 
 #############################################################################
@@ -3021,23 +3269,30 @@ def MakeDocHeader(tag):
 #               $text - text text to put inside the XRef, defaults to $symbol
 #############################################################################
 
-def MakeXRef(symbol, text=None):
-    symbol = symbol.strip()
+sub MakeXRef {
+    my ($symbol, $text) = ($_[0], $_[1]);
+
+    $symbol =~ s/^\s+//;
+    $symbol =~ s/\s+$//;
 
-    if not text:
-        text = symbol
+    if (!defined($text)) {
+        $text = $symbol;
 
         # Get rid of special suffixes ('-struct','-enum').
-        text = re.sub(r'-struct$', '', text)
-        text = re.sub(r'-enum$', '', text)
+        $text =~ s/-struct$//;
+        $text =~ s/-enum$//;
+    }
 
-    if ' ' in symbol:
-        return text
+    if ($symbol =~ m/ /) {
+        return "$text";
+    }
 
-    logging.info("Getting type link for %s -> %s\n", symbol, text)
+    @TRACE@("Getting type link for $symbol -> $text\n");
+
+    my $symbol_id = &CreateValidSGMLID ($symbol);
+    return "<link linkend=\"$symbol_id\">$text</link>";
+}
 
-    symbol_id = common.CreateValidSGMLID(symbol)
-    return "<link linkend=\"%s\">%s</link>" % (symbol_id, text)
 
 #############################################################################
 # Function    : MakeIndexterms
@@ -3045,30 +3300,40 @@ def MakeXRef(symbol, text=None):
 # Arguments   : $symbol - the symbol to create indexterms for
 #############################################################################
 
-def MakeIndexterms(symbol, sid):
-    terms = ''
-    sortas = ''
-
-    # make the index useful, by ommiting the namespace when sorting
-    if NAME_SPACE != '':
-        m = re.search(r'^$NAME_SPACE\_?(.*)', symbol, flags=re.I)
-        if m:
-            sortas = ' sortas=\"%s\"' % m.group(1)
-    if symbol in Deprecated:
-        terms += "<indexterm zone=\"%s\" role=\"deprecated\"><primary%s>%s</primary></indexterm>" % (sid, 
sortas, symbol)
-        IndexEntriesDeprecated[symbol] = sid
-        IndexEntriesFull[symbol] = sid
-    if symbol in Since:
-        since = Since[symbol].strip()
-        if since != '':
-            terms += "<indexterm zone=\"%s\" role=\"%s\"><primary%s>%s</primary></indexterm>" % (sid, since, 
sortas, symbol)
-        IndexEntriesSince[symbol] = sid
-        IndexEntriesFull[symbol] = sid
-    if terms == '':
-        terms += "<indexterm zone=\"%s\"><primary%s>%s</primary></indexterm>" % (sid, sortas, symbol)
-        IndexEntriesFull[symbol] = sid
-    return terms
-
+sub MakeIndexterms {
+  my ($symbol, $id) = @_;
+  my $terms =  "";
+  my $sortas = "";
+
+  # make the index useful, by ommiting the namespace when sorting
+  if ($NAME_SPACE ne "") {
+    if ($symbol =~ m/^$NAME_SPACE\_?(.*)/i) {
+       $sortas=" sortas=\"$1\"";
+    }
+  }
+
+  if (exists $Deprecated{$symbol}) {
+      $terms .= "<indexterm zone=\"$id\" role=\"deprecated\"><primary$sortas>$symbol</primary></indexterm>";
+      $IndexEntriesDeprecated{$symbol}=$id;
+      $IndexEntriesFull{$symbol}=$id;
+  }
+  if (exists $Since{$symbol}) {
+     my $since = $Since{$symbol};
+     $since =~ s/^\s+//;
+     $since =~ s/\s+$//;
+     if ($since ne "") {
+         $terms .= "<indexterm zone=\"$id\" role=\"$since\"><primary$sortas>$symbol</primary></indexterm>";
+     }
+     $IndexEntriesSince{$symbol}=$id;
+     $IndexEntriesFull{$symbol}=$id;
+  }
+  if ($terms eq "") {
+     $terms .= "<indexterm zone=\"$id\"><primary$sortas>$symbol</primary></indexterm>";
+     $IndexEntriesFull{$symbol}=$id;
+  }
+
+  return $terms;
+ }
 
 #############################################################################
 # Function    : MakeDeprecationNote
@@ -3076,30 +3341,32 @@ def MakeIndexterms(symbol, sid):
 # Arguments   : $symbol - the symbol to try to create a warning for.
 #############################################################################
 
-def MakeDeprecationNote(symbol):
-    desc = ''
-    if symbol in Deprecated:
-        desc += "<warning><para><literal>%s</literal> " % symbol
-
-        note = Deprecated[symbol]
-
-        m = re.search(r'^\s*([0-9\.]+)\s*:?', note)
-        if m:
-            desc += "has been deprecated since version %s and should not be used in newly-written 
code.</para>" % m.group(1)
-        else:
-            desc += "is deprecated and should not be used in newly-written code.</para>"
-
-        note = re.sub(r'^\s*([0-9\.]+)\s*:?\s*', '', note)
-        note = note.strip()
-
-        if note != '':
-            note = ConvertMarkDown(symbol, note)
-            desc += " " + note
-
-        desc += "</warning>\n"
-
-    return desc
-
+sub MakeDeprecationNote {
+    my ($symbol) = $_[0];
+    my $desc = "";
+    if (exists $Deprecated{$symbol}) {
+        my $note;
+
+        $desc .= "<warning><para><literal>$symbol</literal> ";
+
+        $note = $Deprecated{$symbol};
+
+        if ($note =~ /^\s*([0-9\.]+)\s*:?/) {
+                $desc .= "has been deprecated since version $1 and should not be used in newly-written 
code.</para>";
+        } else {
+                $desc .= "is deprecated and should not be used in newly-written code.</para>";
+        }
+        $note =~ s/^\s*([0-9\.]+)\s*:?\s*//;
+        $note =~ s/^\s+//;
+        $note =~ s/\s+$//;
+        if ($note ne "") {
+            $note = &ConvertMarkDown($symbol, $note);
+            $desc .= " " . $note;
+        }
+        $desc .= "</warning>\n";
+    }
+    return $desc;
+}
 
 #############################################################################
 # Function    : MakeConditionDescription
@@ -3107,43 +3374,49 @@ def MakeDeprecationNote(symbol):
 # Arguments   : $symbol - the symbol to try to create the sumary.
 #############################################################################
 
-def MakeConditionDescription(symbol):
-    desc = ''
-    if symbol in Deprecated:
-        if desc != '':
-            desc += "|"
-        m = re.search(r'^\s*(.*?)\s*$', Deprecated[symbol])
-        if m:
-            desc += "deprecated:%s" % m.group(1)
-        else:
-            desc += "deprecated"
-
-    if symbol in Since:
-        if desc != '':
-            desc += "|"
-        m = re.search(r'^\s*(.*?)\s*$', Since[symbol])
-        if m:
-            desc += "since:%s" % m.group(1)
-        else:
-            desc += "since"
-
-
-
-    if symbol in StabilityLevel:
-        if desc != '':
-            desc += "|"
-
-        desc += "stability:" + StabilityLevel[symbol]
-
-
-    if desc != '':
-        cond = desc
-        cond = re.sub(r'"', r'&quot', cond)
-        desc = ' condition=\"%s\"' % cond
-        logging.info("condition for '%s' = '%s'\n", symbol, desc)
-
-    return desc
-
+sub MakeConditionDescription {
+    my ($symbol) = $_[0];
+    my $desc = "";
+
+    if (exists $Deprecated{$symbol}) {
+        if ($desc ne "") {
+            $desc .= "|";
+        }
+
+        if ($Deprecated{$symbol} =~ /^\s*(.*?)\s*$/) {
+                $desc .= "deprecated:$1";
+        } else {
+                $desc .= "deprecated";
+        }
+    }
+
+    if (exists $Since{$symbol}) {
+        if ($desc ne "") {
+            $desc .= "|";
+        }
+
+        if ($Since{$symbol} =~ /^\s*(.*?)\s*$/) {
+                $desc .= "since:$1";
+        } else {
+                $desc .= "since";
+        }
+    }
+
+    if (exists $StabilityLevel{$symbol}) {
+        if ($desc ne "") {
+            $desc .= "|";
+        }
+        $desc .= "stability:".$StabilityLevel{$symbol};
+    }
+
+    if ($desc ne "") {
+        my $cond = $desc;
+        $cond =~ s/\"/&quot;/g;
+        $desc=" condition=\"".$cond."\"";
+        @TRACE@("condition for '$symbol' = '$desc'\n");
+    }
+    return $desc;
+}
 
 #############################################################################
 # Function    : GetHierarchy
@@ -3155,104 +3428,121 @@ def MakeConditionDescription(symbol):
 #               @hierarchy - previous hierarchy
 #############################################################################
 
-def GetHierarchy(gobject, hierarchy_ref):
-    hierarchy = hierarchy_ref
+sub GetHierarchy {
+    my ($object,$hierarchy_ref) = @_;
+    my @hierarchy = @{$hierarchy_ref};
 
     # Find object in the objects array.
-    found = False
-    children = []
-    level = 0
-    for i in range(len(Objects)):
-        if found:
-            if ObjectLevels[i] <= level:
-                continue
-
-            elif ObjectLevels[i] == level + 1:
-                children.append(Objects[i])
-
-        elif Objects[i] == gobject:
-            found = True
-            j = i
-            level = ObjectLevels[i]
-
-    if found:
-        return hierarchy
+    my $found = 0;
+    my @children = ();
+    my $i;
+    my $level;
+    my $j;
+    for ($i = 0; $i < @Objects; $i++) {
+        if ($found) {
+            if ($ObjectLevels[$i] <= $level) {
+            last;
+        }
+            elsif ($ObjectLevels[$i] == $level + 1) {
+                push (@children, $Objects[$i]);
+            }
+        }
+        elsif ($Objects[$i] eq $object) {
+            $found = 1;
+            $j = $i;
+            $level = $ObjectLevels[$i];
+        }
+    }
+    if (!$found) {
+        return @hierarchy;
+    }
 
     # Walk up the hierarchy, pushing ancestors onto the ancestors array.
-    ancestors = [gobject]
-    logging.info("Level: %s\n", level)
-    while level > 1:
-        j -= 1
-        if ObjectLevels[j] < level:
-            ancestors.append(Objects[j])
-            level = ObjectLevels[j]
-            logging.info("Level: %s", level)
+    my @ancestors = ();
+    push (@ancestors, $object);
+    @TRACE@("Level: $level\n");
+    while ($level > 1) {
+        $j--;
+        if ($ObjectLevels[$j] < $level) {
+            push (@ancestors, $Objects[$j]);
+            $level = $ObjectLevels[$j];
+            @TRACE@("Level: $level\n");
+        }
+    }
 
     # Output the ancestors, indented and with links.
-    last_index = 0
-    level = 1
-    for i in range(len(ancestors), -1, -1):
-        ancestor = ancestors[i]
-        ancestor_id = common.CreateValidSGMLID(ancestor)
-        indent = ' ' * (level * 4)
+    my $last_index = 0;
+    $level = 1;
+    for ($i = $#ancestors; $i >= 0; $i--) {
+        my $entry_text;
+        my $alt_text;
+        my $ancestor = $ancestors[$i];
+        my $ancestor_id = &CreateValidSGMLID ($ancestor);
+        my $indent = ' ' x ($level * 4);
         # Don't add a link to the current object, i.e. when i == 0.
-        if i > 0:
-            entry_text = indent + "<link linkend=\"%s\">%s</link>" % (ancestor_id, ancestor)
-            alt_text = indent + ancestor
-        else:
-            entry_text = indent + ancestor
-            alt_text = indent + "<link linkend=\"%s\">%s</link>" % (ancestor_id, ancestor)
-
-        logging.info("Checking for '%s' or '%s'", entry_text, alt_text)
+        if ($i > 0) {
+            $entry_text = $indent . "<link linkend=\"$ancestor_id\">$ancestor</link>";
+            $alt_text = $indent . $ancestor;
+        } else {
+            $entry_text = $indent . $ancestor;
+            $alt_text = $indent . "<link linkend=\"$ancestor_id\">$ancestor</link>";
+        }
+        @TRACE@("Checking for '$entry_text' or '$alt_text'");
         # Check if we already have this object
-        index = -1
-        for j in range(len(hierarchy)):
-            if hierarchy[j] == entry_text or (hierarchy[j] == alt_text):
-                index = j
-                break
-        if index == -1:
+        my $index = -1;
+        for ($j = 0; $j <= $#hierarchy; $j++) {
+            if (($hierarchy[$j] eq $entry_text) or ($hierarchy[$j] eq $alt_text)) {
+                $index = $j;
+                last;
+            }
+        }
+        if ($index == -1) {
             # We have a new entry, find insert position in alphabetical order
-            found = 0
-            for j in range(last_index, len(hierarchy)):
-                if re.search(r'^$%s' % indent, hierarchy[j]):
-                    last_index = j
-                    found = True
-                    break
-                elif re.search(r'^%s[^ ]' % indent, hierarchy[j]):
-                    stripped_text = hierarchy[j]
-                    if r'<link linkend' not in entry_text:
-                        stripped_text = re.sub(r'<link linkend="[A-Za-z]*">', '', stripped_text)
-                        stripped_text = re.sub(r'</link>', '', stripped_text)
-
-                    if entry_text < stripped_text:
-                        last_index = j
-                        found = True
-                        break
-
+            my $found = 0;
+            for ($j = $last_index; $j <= $#hierarchy; $j++) {
+                if ($hierarchy[$j] !~ m/^${indent}/) {
+                    $last_index = $j;
+                    $found = 1;
+                    last;
+                } elsif ($hierarchy[$j] =~ m/^${indent}[^ ]/) {
+                    my $stripped_text = $hierarchy[$j];
+                    if ($entry_text !~ m/<link linkend/) {
+                        $stripped_text =~ s%<link linkend="[A-Za-z]*">%%;
+                        $stripped_text =~ s%</link>%%;
+                    }
+                    if ($entry_text lt $stripped_text) {
+                        $last_index = $j;
+                        $found = 1;
+                        last;
+                    }
+                }
+            }
             # Append to bottom
-            if not found:
-                last_index = len(hierarchy)
-
-            hierarchy.insert(last_index, entry_text)
-            last_index += 1
-        else:
+            if (!$found) {
+              $last_index = 1 + $#hierarchy;
+            }
+            splice @hierarchy, $last_index, 0, ($entry_text);
+            $last_index++;
+        } else {
             # Already have this one, make sure we use the not linked version
-            if re.search(r'<link linkend=', entry_text):
-                hierarchy[j] = entry_text
-
+            if ($entry_text !~ m/<link linkend=/) {
+              $hierarchy[$j] = $entry_text;
+            }
             # Remember index as base insert point
-            last_index = index + 1
-
-        level += 1
-
+            $last_index = $index + 1;
+        }
+        $level++;
+    }
     # Output the children, indented and with links.
-    for i in range(len(children)):
-        sid = common.CreateValidSGMLID(children[i])
-        indented_text = ' ' * (level * 4) + "<link linkend=\"%s\">%s</link>" % (sid, children[i])
-        hierarchy.insert(last_index, indented_text)
-        last_index += 1
-    return hierarchy
-
+    for ($i = 0; $i <= $#children; $i++) {
+        my $id = &CreateValidSGMLID ($children[$i]);
+        my $indented_text = ' ' x ($level * 4) . "<link linkend=\"$id\">$children[$i]</link>";
+        splice @hierarchy, $last_index, 0, ($indented_text);
+        $last_index++;
+    }
+
+    return @hierarchy;
+}
 
 #############################################################################
 # Function    : GetInterfaces
@@ -3261,28 +3551,38 @@ def GetHierarchy(gobject, hierarchy_ref):
 # Arguments   : $object - the GtkObject subclass.
 #############################################################################
 
-def GetInterfaces(gobject):
-    text = ''
+sub GetInterfaces {
+    my ($object) = @_;
+    my $text = "";
+    my $i;
 
     # Find object in the objects array.
-    if gobject in Interfaces:
-        ifaces = Interfaces[gobject].split()
-        text = '''<para>
-% implements
-''' % gobject
-        for i in range(len(ifaces)):
-            sid = common.CreateValidSGMLID(ifaces[i])
-            text += " <link linkend=\"%s\">%s</link>" % (sid, ifaces[i])
-            if i < len(ifaces) - 1:
-                text += ', '
-            elif i < len(ifaces):
-                text += ' and '
-            else:
-                text += '.'
-        text += '''</para>
-'''
-    return text
-
+    if (exists($Interfaces{$object})) {
+        my @ifaces = split(' ', $Interfaces{$object});
+        $text = <<EOF;
+<para>
+$object implements
+EOF
+        for ($i = 0; $i <= $#ifaces; $i++) {
+            my $id = &CreateValidSGMLID ($ifaces[$i]);
+            $text .= " <link linkend=\"$id\">$ifaces[$i]</link>";
+            if ($i < $#ifaces - 1) {
+                $text .= ', ';
+            }
+            elsif ($i < $#ifaces) {
+                $text .= ' and ';
+            }
+            else {
+                $text .= '.';
+            }
+        }
+        $text .= <<EOF;
+</para>
+EOF
+    }
+
+    return $text;
+}
 
 #############################################################################
 # Function    : GetImplementations
@@ -3291,34 +3591,41 @@ def GetInterfaces(gobject):
 # Arguments   : $object - the GtkObject subclass.
 #############################################################################
 
-def GetImplementations(gobject):
-    impls = []
-    text = ''
-
-    for key in Interfaces:
-        if re.search(r'\b%s\b' % gobject, Interfaces[key]):
-            impls.append(key)
-
-    if len(impls) > 0:
-        impls.sort()
-        text = ''''<para>
-%s is implemented by
-''' % gobject
-        for i in range(len(impls)):
-            sid = common.CreateValidSGMLID(impls[i])
-            text += " <link linkend=\"%s\">%s</link>" % (sid, impls[i])
-            if i < len(impls) - 1:
-                text += ', '
-
-            elif i < len(impls):
-                text += ' and '
-
-            else:
-                text += '.'
-        text += '''</para>
-'''
-    return text
-
+sub GetImplementations {
+    my ($object) = @_;
+    my @impls = ();
+    my $text = "";
+    my $i;
+    foreach my $key (keys %Interfaces) {
+        if ($Interfaces{$key} =~ /\b$object\b/) {
+            push (@impls, $key);
+        }
+    }
+    if ($#impls >= 0) {
+        @impls = sort @impls;
+        $text = <<EOF;
+<para>
+$object is implemented by
+EOF
+        for ($i = 0; $i <= $#impls; $i++) {
+            my $id = &CreateValidSGMLID ($impls[$i]);
+            $text .= " <link linkend=\"$id\">$impls[$i]</link>";
+            if ($i < $#impls - 1) {
+                $text .= ', ';
+            }
+            elsif ($i < $#impls) {
+                $text .= ' and ';
+            }
+            else {
+                $text .= '.';
+            }
+        }
+        $text .= <<EOF;
+</para>
+EOF
+    }
+    return $text;
+}
 
 
 #############################################################################
@@ -3328,30 +3635,36 @@ def GetImplementations(gobject):
 # Arguments   : $iface - the interface.
 #############################################################################
 
-def GetPrerequisites(iface):
-    text = ''
+sub GetPrerequisites {
+    my ($iface) = @_;
+    my $text = "";
+    my $i;
 
-    if iface in Prerequisites:
-        text = '''
+    if (exists($Prerequisites{$iface})) {
+        $text = <<EOF;
 <para>
-%s requires
-''' % iface
-        prereqs = Prerequisites[iface].split()
-        for i in range(len(prereqs)):
-            sid = common.CreateValidSGMLID(prereqs[i])
-            text += " <link linkend=\"%s\">%s</link>" % (sid, prereqs[i])
-            if i < len(prereqs) - 1:
-                text += ', '
-            elif i < len(prereqs):
-                text += ' and '
-            else:
-                text += '.'
-
-
-        text += '''</para>
-'''
-    return text
-
+$iface requires
+EOF
+        my @prereqs = split(' ', $Prerequisites{$iface});
+        for ($i = 0; $i <= $#prereqs; $i++) {
+            my $id = &CreateValidSGMLID ($prereqs[$i]);
+            $text .= " <link linkend=\"$id\">$prereqs[$i]</link>";
+            if ($i < $#prereqs - 1) {
+                $text .= ', ';
+            }
+            elsif ($i < $#prereqs) {
+                $text .= ' and ';
+            }
+            else {
+                $text .= '.';
+            }
+        }
+        $text .= <<EOF;
+</para>
+EOF
+    }
+    return $text;
+}
 
 #############################################################################
 # Function    : GetDerived
@@ -3360,31 +3673,42 @@ def GetPrerequisites(iface):
 # Arguments   : $iface - the interface.
 #############################################################################
 
-def GetDerived(iface):
-    text = ''
-
-    derived = []
-    for key in Prerequisites:
-        if re.search(r'\b%s\b' % iface, Prerequisites[key]):
-            derived.append(key)
-    if len(derived) > 0:
-        derived.sort()
-        text = '''<para>
-%s is required by
-''' % iface
-        for i in range(len(derived)):
-            sid = common.CreateValidSGMLID(derived[i])
-            text += " <link linkend=\"%s\">%s</link>" % (sid, derived[i])
-            if i < len(derived) - 1:
-                text += ', '
-            elif i < len(derived):
-                text += ' and '
-            else:
-                text += '.'
-        text += '''</para>
-'''
-    return text
-
+sub GetDerived {
+    my ($iface) = @_;
+    my $text = "";
+    my $i;
+
+    my @derived = ();
+    foreach my $key (keys %Prerequisites) {
+        if ($Prerequisites{$key} =~ /\b$iface\b/) {
+            push (@derived, $key);
+        }
+    }
+    if ($#derived >= 0) {
+        @derived = sort @derived;
+        $text = <<EOF;
+<para>
+$iface is required by
+EOF
+        for ($i = 0; $i <= $#derived; $i++) {
+            my $id = &CreateValidSGMLID ($derived[$i]);
+            $text .= " <link linkend=\"$id\">$derived[$i]</link>";
+            if ($i < $#derived - 1) {
+                $text .= ', ';
+            }
+            elsif ($i < $#derived) {
+                $text .= ' and ';
+            }
+            else {
+                $text .= '.';
+            }
+        }
+        $text .= <<EOF;
+</para>
+EOF
+    }
+    return $text;
+}
 
 
 #############################################################################
@@ -3394,143 +3718,154 @@ def GetDerived(iface):
 # Arguments   : $object - the GtkObject subclass, e.g. 'GtkButton'.
 #############################################################################
 
-def GetSignals(gobject):
-    synop = ''
-    desc = ''
-
-    for i in range(len(SignalObjects)):
-        if SignalObjects[i] == gobject:
-            logging.info("Found signal: %s\n", SignalNames[i])
-            name = SignalNames[i]
-            symbol = '%s::%s' % (gobject, name)
-            sid = common.CreateValidSGMLID('%s-%s' % (gobject, name))
-
-            desc += "<refsect2 id=\"%s\" role=\"signal\"><title>The <literal>“%s”</literal> 
signal</title>\n" % (sid, name)
-            desc += MakeIndexterms(symbol, sid)
-            desc += "\n"
-            desc += OutputSymbolExtraLinks(symbol)
-
-            desc += "<programlisting language=\"C\">"
-
-            m = re.search(r'\s*(const\s+)?(\w+)\s*(\**)', SignalReturns[i])
-            type_modifier = m.group(1) if m.group(1) else ''
-            gtype = m.group(2)
-            pointer = m.group(3)
-            xref = MakeXRef(gtype, tagify(gtype, "returnvalue"))
-
-            ret_type_output = '%s%s%s' % (type_modifier, xref, pointer)
-            callback_name = "user_function"
-            desc += '%s\n%s (' % (ret_type_output, callback_name)
-
-            indentation = ' ' * len(callback_name) + 2
-            pad = indentation
-
-            sourceparams = SourceSymbolParams[symbol]
-            params = SignalPrototypes[i].split('\n')
-            type_len = len("gpointer")
-            name_len = len("user_data")
+sub GetSignals {
+    my ($object) = @_;
+    my $synop = "";
+    my $desc = "";
+
+    my $i;
+    for ($i = 0; $i <= $#SignalObjects; $i++) {
+        if ($SignalObjects[$i] eq $object) {
+            @TRACE@("Found signal: $SignalNames[$i]\n");
+            my $name = $SignalNames[$i];
+            my $symbol = "${object}::${name}";
+            my $id = &CreateValidSGMLID ("$object-$name");
+
+            $desc .= "<refsect2 id=\"$id\" role=\"signal\"><title>The <literal>“$name”</literal> 
signal</title>\n";
+            $desc .= MakeIndexterms($symbol, $id);
+            $desc .= "\n";
+            $desc .= OutputSymbolExtraLinks($symbol);
+
+            $desc .= "<programlisting language=\"C\">";
+
+            $SignalReturns[$i] =~ m/\s*(const\s+)?(\w+)\s*(\**)/;
+            my $type_modifier = defined($1) ? $1 : "";
+            my $type = $2;
+            my $pointer = $3;
+            my $xref = &MakeXRef ($type, &tagify($type, "returnvalue"));
+
+            my $ret_type_output = "$type_modifier$xref$pointer";
+            my $callback_name = "user_function";
+            $desc  .= "${ret_type_output}\n${callback_name} (";
+
+            my $indentation = ' ' x (length($callback_name) + 2);
+            my $pad = $indentation;
+
+            my $sourceparams = $SourceSymbolParams{$symbol};
+            my @params = split ("\n", $SignalPrototypes[$i]);
+            my $j;
+            my $l;
+            my $type_len = length("gpointer");
+            my $name_len = length("user_data");
             # do two passes, the first one is to calculate padding
-            for l in range(2):
-                for j in range(len(params)):
-                    param_name = None
+            for ($l = 0; $l < 2; $l++) {
+                for ($j = 0; $j <= $#params; $j++) {
+                    my $param_name;
                     # allow alphanumerics, '_', '[' & ']' in param names
-                    m = re.search(r'^\s*(\w+)\s*(\**)\s*([\w\[\]]+)\s*$', params[j])
-                    if m:
-                        gtype = m.group(1)
-                        pointer = m.group(2)
-                        if sourceparams:
-                            param_name = sourceparams[PARAM_FIELD_COUNT * j]
-
-                        else:
-                            param_name = m.group(3)
-
-                        if not param_name:
-                            param_name = "arg%d" % j
-
-                        if l == 0:
-                            if len(gtype) + len(pointer) > type_len:
-                                type_len = len(gtype) + len(pointer)
-                            if len(param_name) > name_len:
-                                name_len = len(param_name)
-                        else:
-                            xref = MakeXRef(gtype, tagify(gtype, "type"))
-                            pad = ' ' * (type_len - len(type) - len(pointer))
-                            desc += '%s%s %s%s,\n' % (xref, pad, pointer, param_name)
-                            desc += indentation
-
-                    else:
-                        common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                          "Can't parse arg: %s\nArgs:%s" % (params[j], SignalPrototypes[i]))
-
-            xref = MakeXRef("gpointer", tagify("gpointer", "type"))
-            pad = ' ' * (type_len - len("gpointer"))
-            desc += '%s%s user data)' % (xref, pad)
-            desc += "</programlisting>\n"
-
-            flags = SignalFlags[i]
-            flags_string = ''
-
-            if flags:
-                if 'f' in flags:
-                    flags_string = "<link linkend=\"G-SIGNAL-RUN-FIRST:CAPS\">Run First</link>"
-
-                elif 'l' in flags:
-                    flags_string = "<link linkend=\"G-SIGNAL-RUN-LAST:CAPS\">Run Last</link>"
-
-                elif 'c' in flags:
-                    flags_string = "<link linkend=\"G-SIGNAL-RUN-CLEANUP:CAPS\">Cleanup</link>"
-                    flags_string = "Cleanup"
-
-                if 'r' in flags:
-                    if flags_string:
-                        flags_string += " / "
-                    flags_string = "<link linkend=\"G-SIGNAL-NO-RECURSE:CAPS\">No Recursion</link>"
-
-                if 'd' in flags:
-                    if flags_string:
-                        flags_string += " / "
-                    flags_string = "<link linkend=\"G-SIGNAL-DETAILED:CAPS\">Has Details</link>"
-
-                if 'a' in flags:
-                    if flags_string:
-                        flags_string += " / "
-                    flags_string = "<link linkend=\"G-SIGNAL-ACTION:CAPS\">Action</link>"
-
-                if 'h' in flags:
-                    if flags_string:
-                        flags_string += " / "
-                    flags_string = "<link linkend=\"G-SIGNAL-NO-HOOKS:CAPS\">No Hooks</link>"
-
-            synop += "<row><entry role=\"signal_type\">%s</entry><entry role=\"signal_name\"><link 
linkend=\"%s\">%s</link></entry><entry role=\"signal_flags\">%s</entry></row>\n" % (ret_type_output, sid, 
name, flags_string)
-
-            parameters = OutputParamDescriptions("SIGNAL", symbol)
-
-            AllSymbols[symbol] = 1
-            if SymbolDocs[symbol]:
-                symbol_docs = ConvertMarkDown(symbol, SymbolDocs[symbol])
-
-                desc += symbol_docs
-
-                if not IsEmptyDoc(SymbolDocs[symbol]):
-                    AllDocumentedSymbols[symbol] = 1
-
-            if SymbolAnnotations[symbol]:
-                param_desc = SymbolAnnotations[symbol]
-                param_annotations = ''
-                (param_desc, param_annotations) = ExpandAnnotation(symbol, param_desc)
-                if param_annotations != '':
-                    desc += "\n<para>%s</para>" % param_annotations
-
-            desc += MakeDeprecationNote(symbol)
-
-            desc += parameters
-            if flags_string:
-                desc += "<para>Flags: %s</para>\n" % flags_string
-
-            desc += OutputSymbolTraits(symbol)
-            desc += "</refsect2>"
+                    if ($params[$j] =~ m/^\s*(\w+)\s*(\**)\s*([\w\[\]]+)\s*$/) {
+                        $type = $1;
+                        $pointer = $2;
+                        if (defined($sourceparams)) {
+                            $param_name = $$sourceparams[$PARAM_FIELD_COUNT * $j];
+                        }
+                        else {
+                            $param_name = $3;
+                        }
+                        if (!defined($param_name)) {
+                            $param_name = "arg$j";
+                        }
+                        if ($l == 0) {
+                            if (length($type) + length($pointer) > $type_len) {
+                                $type_len = length($type) + length($pointer);
+                            }
+                            if (length($param_name) > $name_len) {
+                                $name_len = length($param_name);
+                            }
+                        }
+                        else {
+                            $xref = &MakeXRef ($type, &tagify($type, "type"));
+                            $pad = ' ' x ($type_len - length($type) - length($pointer));
+                            $desc .= "$xref$pad $pointer${param_name},\n";
+                            $desc .= $indentation;
+                        }
+                    } else {
+                        &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                             "Can't parse arg: $params[$j]\nArgs:$SignalPrototypes[$i]");
+                    }
+                }
+            }
+            $xref = &MakeXRef ("gpointer", &tagify("gpointer", "type"));
+            $pad = ' ' x ($type_len - length("gpointer"));
+            $desc  .= "$xref$pad user_data)";
+            $desc  .= "</programlisting>\n";
+
+            my $flags = $SignalFlags[$i];
+            my $flags_string = "";
+
+            if (defined ($flags)) {
+              if ($flags =~ m/f/) {
+                $flags_string = "<link linkend=\"G-SIGNAL-RUN-FIRST:CAPS\">Run First</link>";
+              }
+              elsif ($flags =~ m/l/) {
+                $flags_string = "<link linkend=\"G-SIGNAL-RUN-LAST:CAPS\">Run Last</link>";
+              }
+              elsif ($flags =~ m/c/) {
+                $flags_string = "<link linkend=\"G-SIGNAL-RUN-CLEANUP:CAPS\">Cleanup</link>";
+                $flags_string = "Cleanup";
+              }
+              if ($flags =~ m/r/) {
+                if ($flags_string) { $flags_string .= " / "; }
+                $flags_string = "<link linkend=\"G-SIGNAL-NO-RECURSE:CAPS\">No Recursion</link>";
+              }
+              if ($flags =~ m/d/) {
+                if ($flags_string) { $flags_string .= " / "; }
+                $flags_string = "<link linkend=\"G-SIGNAL-DETAILED:CAPS\">Has Details</link>";
+              }
+              if ($flags =~ m/a/) {
+                if ($flags_string) { $flags_string .= " / "; }
+                $flags_string = "<link linkend=\"G-SIGNAL-ACTION:CAPS\">Action</link>";
+              }
+              if ($flags =~ m/h/) {
+                if ($flags_string) { $flags_string .= " / "; }
+                $flags_string = "<link linkend=\"G-SIGNAL-NO-HOOKS:CAPS\">No Hooks</link>";
+              }
+            }
+
+            $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";
+
+            my $parameters = &OutputParamDescriptions ("SIGNAL", $symbol);
+
+            $AllSymbols{$symbol} = 1;
+            if (defined ($SymbolDocs{$symbol})) {
+                my $symbol_docs = &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
+
+                $desc .= $symbol_docs;
+
+                if (!IsEmptyDoc($SymbolDocs{$symbol})) {
+                    $AllDocumentedSymbols{$symbol} = 1;
+                }
+            }
+            if (defined ($SymbolAnnotations{$symbol})) {
+                my $param_desc = $SymbolAnnotations{$symbol};
+                my $param_annotations = "";
+                ($param_desc,$param_annotations) = &ExpandAnnotation($symbol, $param_desc);
+                if ($param_annotations ne "") {
+                    $desc .= "\n<para>$param_annotations</para>";
+                }
+            }
+            $desc .= &MakeDeprecationNote($symbol);
+
+            $desc .= $parameters;
+            if ($flags_string) {
+                $desc  .= "<para>Flags: $flags_string</para>\n";
+            }
+            $desc .= OutputSymbolTraits ($symbol);
+            $desc .= "</refsect2>";
+        }
+    }
+    return ($synop, $desc);
+}
 
-    return (synop, desc)
 
 #############################################################################
 # Function    : GetArgs
@@ -3539,139 +3874,147 @@ def GetSignals(gobject):
 # Arguments   : $object - the GtkObject subclass, e.g. 'GtkButton'.
 #############################################################################
 
-def GetArgs(gobject):
-    synop = ''
-    desc = ''
-    child_synop = ''
-    child_desc = ''
-    style_synop = ''
-    style_desc = ''
-
-    for i in range(len(ArgObjects)):
-        if ArgObjects[i] == gobject:
-            logging.info("Found arg: %s", ArgNames[i])
-            name = ArgNames[i]
-            flags = ArgFlags[i]
-            flags_string = ''
-            kind = ''
-            id_sep = ''
-
-            if 'c' in flags:
-                kind = "child property"
-                id_sep = "c-"
-            elif 's' in flags:
-                kind = "style property"
-                id_sep = "s-"
-            else:
-                kind = "property"
-
+sub GetArgs {
+    my ($object) = @_;
+    my $synop = "";
+    my $desc = "";
+    my $child_synop = "";
+    my $child_desc = "";
+    my $style_synop = "";
+    my $style_desc = "";
+
+    my $i;
+    for ($i = 0; $i <= $#ArgObjects; $i++) {
+        if ($ArgObjects[$i] eq $object) {
+            @TRACE@("Found arg: $ArgNames[$i]\n");
+            my $name = $ArgNames[$i];
+            my $flags = $ArgFlags[$i];
+            my $flags_string = "";
+            my $kind = "";
+            my $id_sep = "";
+
+            if ($flags =~ m/c/) {
+                $kind = "child property";
+                $id_sep = "c-";
+            }
+            elsif ($flags =~ m/s/) {
+                $kind = "style property";
+                $id_sep = "s-";
+            }
+            else {
+                $kind = "property";
+            }
 
             # Remember only one colon so we don't clash with signals.
-            symbol = '%s:%s' % (gobject, name)
+            my $symbol = "${object}:${name}";
             # use two dashes and ev. an extra separator here for the same reason.
-            sid = common.CreateValidSGMLID('%s--%s%s' % (gobject, id_sep, name))
-
-            atype = ArgTypes[i]
-            type_output = None
-            arange = ArgRanges[i]
-            range_output = CreateValidSGML(arange)
-            default = ArgDefaults[i]
-            default_output = CreateValidSGML(default)
-
-            if type == "GtkString":
-                type = "char&#160;*"
-
-            if type == "GtkSignal":
-                type = "GtkSignalFunc, gpointer"
-                type_output = MakeXRef("GtkSignalFunc") + ", " + MakeXRef("gpointer")
-            elif re.search(r'^(\w+)\*$', type):
-                m = re.search(r'^(\w+)\*$', type)
-                type_output = MakeXRef(m.group(1), tagify(m.group(1), "type")) + "&#160;*"
-            else:
-                type_output = MakeXRef(atype, tagify(atype, "type"))
-
-            if 'r' in flags:
-                flags_string = "Read"
-
-            if 'w' in flags:
-                if flags_string:
-                    flags_string += " / "
-                flags_string += "Write"
-
-            if 'x' in flags:
-                if flags_string:
-                    flags_string += " / "
-                flags_string += "Construct"
-
-            if 'X' in flags:
-                if flags_string:
-                    flags_string += " / "
-                flags_string += "Construct Only"
-
-
-            AllSymbols[symbol] = 1
-            blurb = ''
-            if symbol in SymbolDocs and not IsEmptyDoc(SymbolDocs[symbol]):
-                blurb = ConvertMarkDown(symbol, SymbolDocs[symbol])
-                logging.info(".. [%s][%s]\n", SymbolDocs[symbol], blurb)
-                AllDocumentedSymbols[symbol] = 1
-
-            else:
-                if ArgBlurbs[i] != '':
-                    blurb = "<para>" + CreateValidSGML(ArgBlurbs[i]) + "</para>"
-                    AllDocumentedSymbols[symbol] = 1
-                else:
+            my $id = &CreateValidSGMLID ("$object--$id_sep$name");
+
+            my $type = $ArgTypes[$i];
+            my $type_output;
+            my $range = $ArgRanges[$i];
+            my $range_output = CreateValidSGML ($range);
+            my $default = $ArgDefaults[$i];
+            my $default_output = CreateValidSGML ($default);
+
+            if ($type eq "GtkString") {
+                $type = "char&#160;*";
+            }
+            if ($type eq "GtkSignal") {
+                $type = "GtkSignalFunc, gpointer";
+                $type_output = &MakeXRef ("GtkSignalFunc") . ", "
+                    . &MakeXRef ("gpointer");
+            } elsif ($type =~ m/^(\w+)\*$/) {
+                $type_output = &MakeXRef ($1, &tagify($1, "type")) . "&#160;*";
+            } else {
+                $type_output = &MakeXRef ($type, &tagify($type, "type"));
+            }
+
+            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";
+            }
+
+            $AllSymbols{$symbol} = 1;
+            my $blurb = "";
+            if (defined($SymbolDocs{$symbol}) &&
+                !IsEmptyDoc($SymbolDocs{$symbol})) {
+                $blurb = &ConvertMarkDown($symbol, $SymbolDocs{$symbol});
+                @TRACE@(".. [$SymbolDocs{$symbol}][$blurb]\n");
+                $AllDocumentedSymbols{$symbol} = 1;
+            }
+            else {
+                if ($ArgBlurbs[$i] ne "") {
+                    $blurb = "<para>" . &CreateValidSGML ($ArgBlurbs[$i]) . "</para>";
+                    $AllDocumentedSymbols{$symbol} = 1;
+                } else {
                     # FIXME: print a warning?
-                    logging.info(".. no description\n")
-
-            pad1 = ''
-            if len(name) < 24:
-                pad1 = " " * (24 - len(name))
-
-
-            arg_synop = "<row><entry role=\"property_type\">%s</entry><entry role=\"property_name\"><link 
linkend=\"%s\">%s</link></entry><entry role=\"property_flags\">%s</entry></row>\n" % (type_output, sid, name, 
flags_string)
-            arg_desc = "<refsect2 id=\"%s\" role=\"property\"><title>The <literal>“%s”</literal> 
%s</title>\n" % (sid, name, kind)
-            arg_desc += MakeIndexterms(symbol, sid)
-            arg_desc += "\n"
-            arg_desc += OutputSymbolExtraLinks(symbol)
-
-            arg_desc += "<programlisting>  “%s”%s %s</programlisting>\n" % (name, pad1, type_output)
-            arg_desc += blurb
-            if symbol in SymbolAnnotations:
-                param_desc = SymbolAnnotations[symbol]
-                param_annotations = ''
-                (param_desc, param_annotations) = ExpandAnnotation(symbol, param_desc)
-                if param_annotations != '':
-                    arg_desc += "\n<para>%s</para>" % param_annotations
-
-            arg_desc += MakeDeprecationNote(symbol)
-
-            if flags_string:
-                arg_desc += "<para>Flags: %s</para>\n" % flags_string
-
-            if range != '':
-                arg_desc += "<para>Allowed values: %s</para>\n" % range_output
-
-            if default != '':
-                arg_desc += "<para>Default value: %s</para>\n" % default_output
-
-            arg_desc += OutputSymbolTraits(symbol)
-            arg_desc += "</refsect2>\n"
-
-            if 'c' in flags:
-                child_synop += arg_synop
-                child_desc += arg_desc
-
-            elif 's' in flags:
-                style_synop += arg_synop
-                style_desc += arg_desc
-
-            else:
-                synop += arg_synop
-                desc += arg_desc
-
-    return (synop, child_synop, style_synop, desc, child_desc, style_desc)
-
+                    @TRACE@(".. no description\n");
+                }
+            }
+
+            my $pad1 = "";
+            if (length ($name) < 24) {
+              $pad1 = " " x (24 - length ($name));
+            }
+
+            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";
+            my $arg_desc = "<refsect2 id=\"$id\" role=\"property\"><title>The <literal>“$name”</literal> 
$kind</title>\n";
+            $arg_desc .= MakeIndexterms($symbol, $id);
+            $arg_desc .= "\n";
+            $arg_desc .= OutputSymbolExtraLinks($symbol);
+
+            $arg_desc .= "<programlisting>  “$name”$pad1 $type_output</programlisting>\n";
+            $arg_desc .= $blurb;
+            if (defined ($SymbolAnnotations{$symbol})) {
+                my $param_desc = $SymbolAnnotations{$symbol};
+                my $param_annotations = "";
+                ($param_desc,$param_annotations) = &ExpandAnnotation($symbol, $param_desc);
+                if ($param_annotations ne "") {
+                    $arg_desc .= "\n<para>$param_annotations</para>";
+                }
+            }
+            $arg_desc .= &MakeDeprecationNote($symbol);
+
+            if ($flags_string) {
+              $arg_desc  .= "<para>Flags: $flags_string</para>\n";
+            }
+            if ($range ne "") {
+                $arg_desc .= "<para>Allowed values: $range_output</para>\n";
+            }
+            if ($default ne "") {
+                $arg_desc .= "<para>Default value: $default_output</para>\n";
+            }
+            $arg_desc .= OutputSymbolTraits ($symbol);
+            $arg_desc .= "</refsect2>\n";
+
+            if ($flags =~ m/c/) {
+                $child_synop .= $arg_synop;
+                $child_desc .= $arg_desc;
+            }
+            elsif ($flags =~ m/s/) {
+                $style_synop .= $arg_synop;
+                $style_desc .= $arg_desc;
+            }
+            else {
+                $synop .= $arg_synop;
+                $desc .= $arg_desc;
+            }
+        }
+    }
+    return ($synop, $child_synop, $style_synop, $desc, $child_desc, $style_desc);
+}
 
 
 #############################################################################
@@ -3690,43 +4033,54 @@ def GetArgs(gobject):
 # Arguments   : $source_dir - the directory to scan.
 #############m###############################################################
 
-def ReadSourceDocumentation(source_dir):
+sub ReadSourceDocumentation {
+    my ($source_dir) = @_;
+    my ($file, $dir, @suffix_list, $suffix);
 
     # prepend entries from @SOURCE_DIR
-    for sdir in SOURCE_DIRS:
+    for my $dir (@SOURCE_DIRS) {
         # Check if the filename is in the ignore list.
-        m1 = re.search(r'^%s/(.*)$' % re.escape(sdir), source_dir)
-        if m1:
-            m2 = re.search(r'(\s|^)%s(\s|$)' % re.escape(m1.group(1)), IGNORE_FILES)
-            if m2:
-                logging.info("Skipping source directory: %s", source_dir)
-                return
-        else:
-            logging.info("No match for: %s", (m2.group(1) or source_dir))
+        if ($source_dir =~ m%^\Q$dir\E/(.*)$% and $IGNORE_FILES =~ m/(\s|^)\Q$1\E(\s|$)/) {
+            @TRACE@("Skipping source directory: $source_dir");
+            return;
+        } else {
+            @TRACE@("No match for: ".($1 || $source_dir));
+        }
+    }
 
-    logging.info("Scanning source directory: %s", source_dir)
+    @TRACE@("Scanning source directory: $source_dir");
 
     # This array holds any subdirectories found.
-    subdirs = []
-
-    suffix_list = SOURCE_SUFFIXES.split(',')
-
-    for ifile in os.listdir(source_dir):
-        fname = os.path.join(source_dir, ifile)
-        if ifile.startswith('.'):
-            continue
-        elif os.path.isdir(fname):
-            subdirs.append(ifile)
-        elif suffix_list:
-            for suffix in suffix_list:
-                if re.search(r'\.%s$' % re.escape(suffix), ifile):
-                    ScanSourceFile(fname)
-        elif re.search(r'\.[ch]$', ifile):
-            ScanSourceFile(fname)
+    my (@subdirs) = ();
+
+    @suffix_list = split (/,/, $SOURCE_SUFFIXES);
+
+    opendir (SRCDIR, $source_dir)
+        || die "Can't open source directory $source_dir: $!";
+
+    foreach $file (readdir (SRCDIR)) {
+      if ($file =~ /^\./) {
+        next;
+      } elsif (-d "$source_dir/$file") {
+        push (@subdirs, $file);
+      } elsif (@suffix_list) {
+        foreach $suffix (@suffix_list) {
+          if ($file =~ m/\.\Q${suffix}\E$/) {
+            &ScanSourceFile ("$source_dir/$file");
+          }
+        }
+      } elsif ($file =~ m/\.[ch]$/) {
+        &ScanSourceFile ("$source_dir/$file");
+      }
+    }
+    closedir (SRCDIR);
 
     # Now recursively scan the subdirectories.
-    for sdir in subdirs:
-        ReadSourceDocumentation(os.path.join(source_dir, sdir))
+    foreach $dir (@subdirs) {
+        &ReadSourceDocumentation ("$source_dir/$dir");
+    }
+}
+
 
 #############################################################################
 # Function    : ScanSourceFile
@@ -3738,353 +4092,350 @@ def ReadSourceDocumentation(source_dir):
 # Arguments   : $file - the file to scan.
 #############################################################################
 
-def ScanSourceFile(ifile):
+sub ScanSourceFile {
+    my ($file) = @_;
+    my $basename;
 
     # prepend entries from @SOURCE_DIR
-    for idir in SOURCE_DIRS:
+    for my $dir (@SOURCE_DIRS) {
         # Check if the filename is in the ignore list.
-        m1 = re.search(r'^%s/(.*)$' % re.escape(idir), ifile)
-        if m1:
-            m2 = re.search(r'(\s|^)%s(\s|$)' % re.escape(m1.group(1)), IGNORE_FILES)
-            if m2:
-                logging.info("Skipping source file: ", ifile)
-                return
-
-    m = re.search(r'^.*[\/\\]([^\/\\]*)$', ifile)
-    if m:
-        basename = m.group(1)
-    else:
-        common.LogWarning(ifile, 1, "Can't find basename for this filename.")
-        basename = ifile
-
+        if ($file =~ m%^\Q$dir\E/(.*)$% and $IGNORE_FILES =~ m/(\s|^)\Q$1\E(\s|$)/) {
+            @TRACE@("Skipping source file: $file");
+            return;
+        }
+    }
+
+    if ($file =~ m/^.*[\/\\]([^\/\\]*)$/) {
+        $basename = $1;
+    } else {
+        &LogWarning ($file, 1, "Can't find basename for this filename.");
+        $basename = $file;
+    }
 
     # Check if the basename is in the list of files to ignore.
-    if re.search(r'(\s|^)%s(\s|$)' % re.escape(basename), IGNORE_FILES):
-        logging.info("Skipping source file: %s", ifile)
-        return
-
-
-    logging.info("Scanning source file: %s", ifile)
-
-    SRCFILE = open(ifile)
-    in_comment_block = False
-    symbol = None
-    in_part = ''
-    description = ''
-    return_desc = ''
-    since_desc = stability_desc = deprecated_desc = ''
-    current_param = None
-    params = []
-    line_number = 0
-    for line in SRCFILE:
-        line_number += 1
+    if ($IGNORE_FILES =~ m/(\s|^)\Q${basename}\E(\s|$)/) {
+        @TRACE@("Skipping source file: $file");
+        return;
+    }
+
+    @TRACE@("Scanning source file: $file");
+
+    open (SRCFILE, $file)
+        || die "Can't open $file: $!";
+    my $in_comment_block = 0;
+    my $symbol;
+    my $in_part = "";
+    my ($description, $return_desc);
+    my ($since_desc, $stability_desc, $deprecated_desc);
+    my $current_param;
+    my @params;
+    while (<SRCFILE>) {
         # Look for the start of a comment block.
-        if not in_comment_block:
-            if re.search(r'^\s*/\*.*\*/', line):
+        if (!$in_comment_block) {
+            if (m%^\s*/\*.*\*/%) {
                 #one-line comment - not gtkdoc
-                pass
-            elif re.search(r'^\s*/\*\*\s', line):
-                logging.info("Found comment block start\n")
+            } elsif (m%^\s*/\*\*\s%) {
+                @TRACE@("Found comment block start\n");
 
-                in_comment_block = True
+                $in_comment_block = 1;
 
                 # Reset all the symbol data.
-                symbol = ''
-                in_part = ''
-                description = ''
-                return_desc = ''
-                since_desc = ''
-                deprecated_desc = ''
-                stability_desc = ''
-                current_param = -1
-                params = []
-
-            continue
+                $symbol = "";
+                $in_part = "";
+                $description = "";
+                $return_desc = "";
+                $since_desc = "";
+                $deprecated_desc = "";
+                $stability_desc = "";
+                $current_param = -1;
+                @params = ();
+            }
+            next;
+        }
 
         # We're in a comment block. Check if we've found the end of it.
-        if re.search(r'^\s*\*+/', line):
-            if symbol:
+        if (m%^\s*\*+/%) {
+            if (!$symbol) {
                 # maybe its not even meant to be a gtk-doc comment?
-                common.LogWarning(ifile, line_number, "Symbol name not found at the start of the comment 
block.")
-            else:
+                &LogWarning ($file, $., "Symbol name not found at the start of the comment block.");
+            } else {
                 # Add the return value description onto the end of the params.
-                if return_desc:
+                if ($return_desc) {
                     # TODO(ensonic): check for duplicated Return docs
-                    # &common.LogWarning($file, line_number, "Multiple Returns for $symbol.")
-                    params.append("Returns")
-                    params.append(return_desc)
-
+                    # &LogWarning ($file, $., "Multiple Returns for $symbol.");
+                    push (@params, "Returns");
+                    push (@params, $return_desc);
+                }
                 # Convert special characters
-                description = ConvertSGMLChars(symbol, description)
-                for k in range(1, len(params), PARAM_FIELD_COUNT):
-                    params[k] = ConvertSGMLChars(symbol, params[k])
-
+                $description = &ConvertSGMLChars ($symbol, $description);
+                my $k;
+                for ($k = 1; $k <= $#params; $k += $PARAM_FIELD_COUNT) {
+                    $params[$k] = &ConvertSGMLChars ($symbol, $params[$k]);
+                }
 
                 # Handle Section docs
-                m = re.search(r'SECTION:\s*(.*)', symbol)
-                m2 = re.search(r'PROGRAM:\s*(.*)', symbol)
-                if m:
-                    real_symbol = m.group(1)
-                    long_descr = os.path.join(TMPL_DIR, real_symbol + ":Long_Description")
-
-                    if len(KnownSymbols) > 0:
-                        if long_descr in KnownSymbols or KnownSymbols[long_descr] != 1:
-                            common.LogWarning(ifile, line_number, "Section %s is not defined in the 
%s-sections.txt file." % (real_symbol, MODULE))
-
-                    logging.info("SECTION DOCS found in source for : '%s'", real_symbol)
-                    for k in range(0, len(params), PARAM_FIELD_COUNT):
-                        logging.info("   '" + params[k] + "'\n")
-                        params[k] = params[k].lower()
-                        key = None
-                        if params[k] == "short_description":
-                            key = os.path.join(TMPL_DIR, real_symbol + ":Short_Description")
-                        elif params[k] == "see_also":
-                            key = os.path.join(TMPL_DIR, real_symbol + ":See_Also")
-                        elif params[k] == "title":
-                            key = os.path.join(TMPL_DIR, real_symbol + ":Title")
-                        elif params[k] == "stability":
-                            key = os.path.join(TMPL_DIR, real_symbol + ":Stability_Level")
-                        elif params[k] == "section_id":
-                            key = os.path.join(TMPL_DIR, real_symbol + ":Section_Id")
-                        elif params[k] == "include":
-                            key = os.path.join(TMPL_DIR, real_symbol + ":Include")
-                        elif params[k] == "image":
-                            key = os.path.join(TMPL_DIR, real_symbol + ":Image")
-
-                        if key:
-                            SourceSymbolDocs[key] = params[k+1]
-                            SourceSymbolSourceFile[key] = ifile
-                            SourceSymbolSourceLine[key] = line_number
-
-
-                    SourceSymbolDocs[long_descr] = description
-                    SourceSymbolSourceFile[long_descr] = ifile
-                    SourceSymbolSourceLine[long_descr] = line_number
-                    #$SourceSymbolTypes{$symbol} = "SECTION"
-                elif m2:
-                    real_symbol = m2.group(1)
-                    key = None
-                    section_id = None
-
-                    logging.info("PROGRAM DOCS found in source for '%s'", real_symbol)
-                    for k in range(0, len(params), PARAM_FIELD_COUNT):
-                        logging.info("   '" + params[k] + "'\n")
-                        params[k] = params[k].lower()
-                        key = None
-
-                        if params[k] == "short_description":
-                            key = os.path.join(TMPL_DIR, real_symbol, ":Short_Description")
-                        elif params[k] == "see_also":
-                            key = os.path.join(TMPL_DIR, real_symbol + ":See_Also")
-                        elif params[k] == "section_id":
-                            key = os.path.join(TMPL_DIR, real_symbol + ":Section_Id")
-                        elif params[k] == "synopsis":
-                            key = os.path.join(TMPL_DIR, real_symbol + ":Synopsis")
-                        elif params[k] == "returns":
-                            key = os.path.join(TMPL_DIR, real_symbol + ":Returns")
-                        elif re.search(r'^(-.*)', params[k]):
-                            m4 = re.search(r'^(-.*)', params[k])
-                            key = os.path.join(TMPL_DIR, real_symbol + ":Options")
-                            if key in SourceSymbolDocs:
-                                opts = SourceSymbolDocs[key]
-                            else:
-                                opts = []
-
-                            opts.append(m4.group(1))
-                            opts.append(params[k+1])
-
-                            SourceSymbolDocs[key] = opts
-                            continue
-
-                        if key:
-                            SourceSymbolDocs[key] = params[k+1]
-                            SourceSymbolSourceFile[key] = ifile
-                            SourceSymbolSourceLine[key] = line_number
-
-
-                    long_descr = os.path.join(TMPL_DIR, real_symbol + ":Long_Description")
-                    SourceSymbolDocs[long_descr] = description
-                    SourceSymbolSourceFile[long_descr] = ifile
-                    SourceSymbolSourceLine[long_descr] = line_number
-
-                    section_id = SourceSymbolDocs[os.path.join(TMPL_DIR, real_symbol + ":Section_Id")]
-                    if section_id and not re.search(r'^\s*$', section_id):
-                        # Remove trailing blanks and use as is
-                        section_id = section_id.rstrip()
-                    else:
-                        section_id = common.CreateValidSGMLID('%s-%s' % (MODULE, real_symbol))
-                    OutputProgramDBFile(real_symbol, section_id)
-
-                else:
-                    logging.info("SYMBOL DOCS found in source for : '%s' %d ", symbol, len(description))
-                    SourceSymbolDocs[symbol] = description
-                    SourceSymbolParams[symbol] = [params]
-                    # FIXME $SourceSymbolTypes{$symbol} = "STRUCT,SIGNAL,ARG,FUNCTION,MACRO"
-                    #if (defined $DeclarationTypes{$symbol})
-                    #    $SourceSymbolTypes{$symbol} = $DeclarationTypes{$symbol
-                    #
-                    SourceSymbolSourceFile[symbol] = ifile
-                    SourceSymbolSourceLine[symbol] = line_number
-
-
-                if since_desc:
-                    arr = since_desc.split('\n')
-                    since_desc = arr[0].strip()
-                    extra_lines = arr[1:]
-                    logging.info("Since(%s) : [%s]\n", symbol, since_desc)
-                    Since[symbol] = ConvertSGMLChars(symbol, since_desc)
-                    if len(extra_lines) > 0:
-                        common.LogWarning(ifile, line_number, "multi-line since docs found")
-
-                if stability_desc:
-                    stability_desc = ParseStabilityLevel(stability_desc, ifile, line_number, "Stability 
level for %s" % symbol)
-                    StabilityLevel[symbol] = ConvertSGMLChars(symbol, stability_desc)
-
-
-                if deprecated_desc:
-                    if symbol in Deprecated:
-                        # don't warn for signals and properties
-                        #if ($symbol !~ m/::?(.*)/)
-                        if symbol in DeclarationTypes:
-                            common.LogWarning(ifile, line_number,
-                                              "%s is deprecated in the inline comments, but no deprecation 
guards were found around the declaration. (See the --deprecated-guards option for gtkdoc-scan.)" % symbol)
+                if ($symbol =~ m/SECTION:\s*(.*)/) {
+                    my $real_symbol=$1;
+                    my $key;
 
+                    if (scalar %KnownSymbols) {
+                        if ((! defined($KnownSymbols{"$TMPL_DIR/$real_symbol:Long_Description"})) || 
$KnownSymbols{"$TMPL_DIR/$real_symbol:Long_Description"} != 1) {
+                            &LogWarning ($file, $., "Section $real_symbol is not defined in the 
$MODULE-sections.txt file.");
+                        }
+                    }
 
-                    Deprecated[symbol] = ConvertSGMLChars(symbol, deprecated_desc)
+                    @TRACE@("SECTION DOCS found in source for : '$real_symbol'\n");
+                    for ($k = 0; $k <= $#params; $k += $PARAM_FIELD_COUNT) {
+                        @TRACE@("   '".$params[$k]."'\n");
+                        $params[$k] = "\L$params[$k]";
+                        undef $key;
+                        if ($params[$k] eq "short_description") {
+                            $key = "$TMPL_DIR/$real_symbol:Short_Description";
+                        } elsif ($params[$k] eq "see_also") {
+                            $key = "$TMPL_DIR/$real_symbol:See_Also";
+                        } elsif ($params[$k] eq "title") {
+                            $key = "$TMPL_DIR/$real_symbol:Title";
+                        } elsif ($params[$k] eq "stability") {
+                            $key = "$TMPL_DIR/$real_symbol:Stability_Level";
+                        } elsif ($params[$k] eq "section_id") {
+                            $key = "$TMPL_DIR/$real_symbol:Section_Id";
+                        } elsif ($params[$k] eq "include") {
+                            $key = "$TMPL_DIR/$real_symbol:Include";
+                        } elsif ($params[$k] eq "image") {
+                            $key = "$TMPL_DIR/$real_symbol:Image";
+                        }
+                        if (defined($key)) {
+                            $SourceSymbolDocs{$key}=$params[$k+1];
+                            $SourceSymbolSourceFile{$key} = $file;
+                            $SourceSymbolSourceLine{$key} = $.;
+                        }
+                    }
+                    $SourceSymbolDocs{"$TMPL_DIR/$real_symbol:Long_Description"}=$description;
+                    $SourceSymbolSourceFile{"$TMPL_DIR/$real_symbol:Long_Description"} = $file;
+                    $SourceSymbolSourceLine{"$TMPL_DIR/$real_symbol:Long_Description"} = $.;
+                    #$SourceSymbolTypes{$symbol} = "SECTION";
+                } elsif ($symbol =~ m/PROGRAM:\s*(.*)/) {
+                    my $real_symbol = $1;
+                    my $key;
+                    my $section_id;
+
+                    @TRACE@("PROGRAM DOCS found in source for '$real_symbol'\n");
+                    for ($k = 0; $k <= $#params; $k += $PARAM_FIELD_COUNT) {
+                        @TRACE@("   '".$params[$k]."'\n");
+                        $params[$k] = "\L$params[$k]";
+                        undef $key;
+
+                        if ($params[$k] eq "short_description") {
+                            $key = "$TMPL_DIR/$real_symbol:Short_Description";
+                        } elsif ($params[$k] eq "see_also") {
+                            $key = "$TMPL_DIR/$real_symbol:See_Also";
+                        } elsif ($params[$k] eq "section_id") {
+                            $key = "$TMPL_DIR/$real_symbol:Section_Id";
+                        } elsif ($params[$k] eq "synopsis") {
+                            $key = "$TMPL_DIR/$real_symbol:Synopsis";
+                        } elsif ($params[$k] eq "returns") {
+                            $key = "$TMPL_DIR/$real_symbol:Returns";
+                        } elsif ($params[$k] =~ m/^(-.*)/) {
+                            $key = "$TMPL_DIR/$real_symbol:Options";
+                            my $opts;
+                            if (defined($SourceSymbolDocs{$key})) {
+                                $opts = $SourceSymbolDocs{$key};
+                            } else {
+                                $opts = [];
+                            }
+                            push (@{ $opts }, $1);
+                            push (@{ $opts }, $params[$k+1]);
+
+                            $SourceSymbolDocs{$key} = $opts;
+                            next;
+                        }
+                        if (defined($key)) {
+                            $SourceSymbolDocs{$key}=$params[$k+1];
+                            $SourceSymbolSourceFile{$key} = $file;
+                            $SourceSymbolSourceLine{$key} = $.;
+                        }
+                    }
+                    $SourceSymbolDocs{"$TMPL_DIR/$real_symbol:Long_Description"}=$description;
+                    $SourceSymbolSourceFile{"$TMPL_DIR/$real_symbol:Long_Description"} = $file;
+                    $SourceSymbolSourceLine{"$TMPL_DIR/$real_symbol:Long_Description"} = $.;
 
+                    $section_id = $SourceSymbolDocs{"$TMPL_DIR/$real_symbol:Section_Id"};
+                    if (defined ($section_id) && $section_id !~ m/^\s*$/) {
+                        # Remove trailing blanks and use as is
+                        $section_id =~ s/\s+$//;
+                    } else {
+                        $section_id = &CreateValidSGMLID ("$MODULE-$real_symbol");
+                    }
 
+                    &OutputProgramDBFile ($real_symbol, $section_id);
+
+                } else {
+                    @TRACE@("SYMBOL DOCS found in source for : '$symbol' ",length($description), "\n");
+                    $SourceSymbolDocs{$symbol} = $description;
+                    $SourceSymbolParams{$symbol} = [ @params ];
+                    # FIXME $SourceSymbolTypes{$symbol} = "STRUCT,SIGNAL,ARG,FUNCTION,MACRO";
+                    #if (defined $DeclarationTypes{$symbol}) {
+                    #    $SourceSymbolTypes{$symbol} = $DeclarationTypes{$symbol}
+                    #}
+                    $SourceSymbolSourceFile{$symbol} = $file;
+                    $SourceSymbolSourceLine{$symbol} = $.;
+                }
+
+                if ($since_desc) {
+                     ($since_desc, my @extra_lines) = split ("\n", $since_desc);
+                     $since_desc =~ s/^\s+//;
+                     $since_desc =~ s/\s+$//;
+                     @TRACE@("Since($symbol) : [$since_desc]\n");
+                     $Since{$symbol} = &ConvertSGMLChars ($symbol, $since_desc);
+                     if(scalar @extra_lines) {
+                         &LogWarning ($file, $., "multi-line since docs found");
+                     }
+                }
+
+                if ($stability_desc) {
+                    $stability_desc = &ParseStabilityLevel($stability_desc, $file, $., "Stability level for 
$symbol");
+                    $StabilityLevel{$symbol} = &ConvertSGMLChars ($symbol, $stability_desc);
+                }
+
+                if ($deprecated_desc) {
+                    if (!exists $Deprecated{$symbol}) {
+                         # don't warn for signals and properties
+                         #if ($symbol !~ m/::?(.*)/) {
+                         if (defined $DeclarationTypes{$symbol}) {
+                             &LogWarning ($file, $.,
+                                 "$symbol is deprecated in the inline comments, but no deprecation guards 
were found around the declaration.".
+                                 " (See the --deprecated-guards option for gtkdoc-scan.)");
+                         }
+                    }
+                    $Deprecated{$symbol} = &ConvertSGMLChars ($symbol, $deprecated_desc);
+                }
+            }
 
-            in_comment_block = False
-            continue
+            $in_comment_block = 0;
+            next;
+        }
 
         # Get rid of ' * ' at start of every line in the comment block.
-        line = re.sub(r'^\s*\*\s?', '', line)
+        s%^\s*\*\s?%%;
         # But make sure we don't get rid of the newline at the end.
-        if not line.endswith('\n'):
-            line = line + "\n"
-
-        logging.info("scanning : %s", line)
+        if (!$_) {
+            $_ = "\n";
+        }
+        @TRACE@("scanning :$_");
 
         # If we haven't found the symbol name yet, look for it.
-        if symbol:
-            m1 = re.search(r'^\s*(SECTION:\s*\S+)', line)
-            m2 = re.search(r'^\s*(PROGRAM:\s*\S+)', line)
-            m3 = re.search(r'^\s*([\w:-]*\w)\s*:?\s*(\(.+?\)\s*)*$', line)
-            if m1:
-                symbol = m1.group(1)
-                logging.info("SECTION DOCS found in source for : '%s'", symbol)
-            elif m2:
-                symbol = m2.group(1)
-                logging.info("PROGRAM DOCS found in source for : '%s'", symbol)
-            elif m3:
-                symbol = m3.group(1)
-                annotation = m3.group(2)
-                logging.info("SYMBOL DOCS found in source for : '%s'\n", symbol)
-                if annotation:
-                    annotation = annotation.strip()
-                    if annotation != '':
-                        SymbolAnnotations[symbol] = annotation
-                        logging.info("remaining text for $symbol: '%s'\n", annotation)
-
-            continue
-
-
-        if in_part == "description":
-            # Get rid of 'Description:'
-            line = re.sub(r'^\s*Description:', '', line)
-
+        if (!$symbol) {
+            if (m%^\s*(SECTION:\s*\S+)%) {
+                $symbol = $1;
+                @TRACE@("SECTION DOCS found in source for : '$symbol'\n");
+            } elsif (m%^\s*(PROGRAM:\s*\S+)%) {
+                $symbol = $1;
+                @TRACE@("PROGRAM DOCS found in source for : '$symbol'\n");
+            } elsif (m%^\s*([\w:-]*\w)\s*:?\s*(\(.+?\)\s*)*$%) {
+                $symbol = $1;
+                my $annotation = $2;
+                @TRACE@("SYMBOL DOCS found in source for : '$symbol'\n");
+                if (defined($annotation)) {
+                    chomp($annotation);
+                    if ($annotation ne "") {
+                        $SymbolAnnotations{$symbol} = $annotation;
+                        @TRACE@("remaining text for $symbol: '$annotation'\n");
+                    }
+                }
+            }
+            next;
+        }
 
-        m = re.search(r'^\s*(returns|return\s+value):', line, flags=re.I)
-        m2 = re.search(r'^\s*since:', line, flags=re.I)
-        m3 = re.search(r'^\s*deprecated:', line, flags=re.I)
-        m4 = re.search(r'^\s*stability:', line, flags=re.I)
+        if ($in_part eq "description") {
+            # Get rid of 'Description:'
+            s%^\s*Description:%%;
+        }
 
-        if m:
+        if (m%^\s*(returns|return\s+value):%i) {
             # we're in param section and have not seen the blank line
-            if in_part != '':
-                return_desc = line[m.end():]
-                in_part = "return"
-                continue
-
-        if m2:
+            if($in_part ne "") {
+              $return_desc = $';
+              $in_part = "return";
+              next;
+            }
+        } elsif (m%^\s*since:%i) {
             # we're in param section and have not seen the blank line
-            if in_part != "param":
-                since_desc = line[m2.end():]
-                in_part = "since"
-                continue
-
-        elif m3:
+            if($in_part ne "param") {
+              $since_desc = $';
+              $in_part = "since";
+              next;
+            }
+        } elsif (m%^\s*deprecated:%i) {
             # we're in param section and have not seen the blank line
-            if in_part != "param":
-                deprecated_desc = line[m.end():]
-                in_part = "deprecated"
-                continue
-
-        elif m4:
-            stability_desc = line[m.end():]
-            in_part = "stability"
-            continue
-
-
-        if in_part == "description":
-            description += line
-            continue
-        elif in_part == "return":
-            return_desc += line
-            continue
-        elif in_part == "since":
-            since_desc += line
-            continue
-        elif in_part == "stability":
-            stability_desc += line
-            continue
-        elif in_part == "deprecated":
-            deprecated_desc += line
-            continue
-
+            if($in_part ne "param") {
+              $deprecated_desc = $';
+              $in_part = "deprecated";
+              next;
+            }
+        } elsif (m%^\s*stability:%i) {
+            $stability_desc = $';
+            $in_part = "stability";
+            next;
+        }
+
+        if ($in_part eq "description") {
+            $description .= $_;
+            next;
+        } elsif ($in_part eq "return") {
+            $return_desc .= $_;
+            next;
+        } elsif ($in_part eq "since") {
+            $since_desc .= $_;
+            next;
+        } elsif ($in_part eq "stability") {
+            $stability_desc .= $_;
+            next;
+        } elsif ($in_part eq "deprecated") {
+            $deprecated_desc .= $_;
+            next;
+        }
 
         # We must be in the parameters. Check for the empty line below them.
-        if re.search(r'^\s*$', line):
-            in_part = "description"
-            continue
-
+        if (m%^\s*$%) {
+            $in_part = "description";
+            next;
+        }
 
         # Look for a parameter name.
-        m = re.search(r'^\s*@(.+?)\s*:\s*', line)
-        if m:
-            param_name = m.group(1)
-            param_desc = line[m.end():]
+        if (m%^\s*@(.+?)\s*:\s*%) {
+            my $param_name = $1;
+            my $param_desc = $';
 
-            logging.info("Found parameter: %s", param_name)
+            @TRACE@("Found parameter: $param_name\n");
             # Allow varargs variations
-            if re.search(r'^\.\.\.$', param_name):
-                param_name = "..."
-
-            logging.info("Found param for symbol $symbol : '%s'= '%s'", param_name, line)
-
-            params.append(param_name)
-            params.append(param_desc)
-            current_param += PARAM_FIELD_COUNT
-            in_part = "param"
-            continue
-        elif in_part == '':
-            logging.info("continuation for %s annotation '%s'", symbol, line)
-            annotation = line
-            annotation = re.sub(r'^\s+|\s+$', '', annotation)
-            SymbolAnnotations[symbol] += annotation
-            continue
-
+            if ($param_name =~ m/^\.\.\.$/) {
+                $param_name = "...";
+            }
+            @TRACE@("Found param for symbol $symbol : '$param_name'= '$_'");
+
+            push (@params, $param_name);
+            push (@params, $param_desc);
+            $current_param += $PARAM_FIELD_COUNT;
+            $in_part = "param";
+            next;
+        } elsif ($in_part eq "") {
+            @TRACE@("continuation for $symbol annotation '$_'");
+            my $annotation = $_;
+            $annotation =~ s/^\s+|\s+$//g ;
+            $SymbolAnnotations{$symbol} .= $annotation;
+            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:
-            common.LogWarning(file, line_number, "Parsing comment block file : parameter expected, but got 
'%s'" % line)
-        else:
-            params[len(params)] += line
-
-
-    SRCFILE.close()
-
+        if ($current_param == -1) {
+            &LogWarning ($file, $., "Parsing comment block file : parameter expected, but got '$_'");
+        } else {
+            $params[$#params] .= $_;
+        }
+    }
+    close (SRCFILE);
+}
 
 #############################################################################
 # Function    : OutputMissingDocumentation
@@ -4093,96 +4444,99 @@ def ScanSourceFile(ifile):
 # Arguments   : none
 #############################################################################
 
-def OutputMissingDocumentation():
-    old_undocumented_file = os.path.join(ROOT_DIR, MODULE + "undocumented.txt")
-    new_undocumented_file = os.path.join(ROOT_DIR, MODULE + "-undocumented.new")
+sub OutputMissingDocumentation {
+    my $old_undocumented_file = "$ROOT_DIR/$MODULE-undocumented.txt";
+    my $new_undocumented_file = "$ROOT_DIR/$MODULE-undocumented.new";
 
-    n_documented = 0
-    n_incomplete = 0
-    total = 0
-    symbol = None
-    percent = None
-    buffer = ''
-    buffer_deprecated = ''
-    buffer_descriptions = ''
+    my $n_documented = 0;
+    my $n_incomplete = 0;
+    my $total = 0;
+    my $symbol;
+    my $percent;
+    my $msg;
+    my $buffer = "";
+    my $buffer_deprecated = "";
+    my $buffer_descriptions = "";
 
-    UNDOCUMENTED = open(new_undocumented_file, 'w')
+    open(UNDOCUMENTED, ">$new_undocumented_file")
+      || die "Can't create $new_undocumented_file";
 
-    for symbol in sorted(AllSymbols.keys()):
-        # FIXME: should we print common.LogWarnings for undocumented stuff?
+    foreach $symbol (sort (keys (%AllSymbols))) {
+        # FIXME: should we print LogWarnings for undocumented stuff?
         # DEBUG
-        #my $ssfile = &GetSymbolSourceFile($symbol)
-        #my $ssline = &GetSymbolSourceLine($symbol)
-        #my $location = "defined at " . (defined($ssfile)?$ssfile:"?") . ":" . 
(defined($ssline)?$ssline:"0") . "\n"
+        #my $ssfile = &GetSymbolSourceFile($symbol);
+        #my $ssline = &GetSymbolSourceLine($symbol);
+        #my $location = "defined at " . (defined($ssfile)?$ssfile:"?") . ":" . 
(defined($ssline)?$ssline:"0") . "\n";
         # DEBUG
-        m = 
re.search(r':(Title|Long_Description|Short_Description|See_Also|Stability_Level|Include|Section_Id|Image)', 
symbol)
-        m2 = re.search(r':(Long_Description|Short_Description)', symbol)
-        if not m:
-            total += 1
-            if symbol in AllDocumentedSymbols:
-                n_documented += 1
-                if symbol in AllIncompleteSymbols:
-                    n_incomplete += 1
-                    buffer += symbol + " (" + AllIncompleteSymbols[symbol] + ")\n"
-                    #$buffer += "\t0: ".$location
-
-            elif symbol in Deprecated:
-                if symbol in AllIncompleteSymbols:
-                    n_incomplete += 1
-                    buffer_deprecated += symbol + " (" + AllIncompleteSymbols[symbol] + ")\n"
-                    #$buffer += "\t1a: ".$location
-                else:
-                    buffer_deprecated += symbol + "\n"
-                    #$buffer += "\t1b: ".$location
-
-            else:
-                if symbol in AllIncompleteSymbols:
-                    n_incomplete += 1
-                    buffer += symbol + " (" + AllIncompleteSymbols[symbol] + ")\n"
-                    #$buffer += "\t2a: ".$location
-                else:
-                    buffer += symbol + "\n"
-                    #$buffer += "\t2b: ".$location
-
-
-        elif m2:
-            total += 1
-            if symbol in SymbolDocs and len(SymbolDocs[symbol]) > 0\
-               or symbol in AllDocumentedSymbols and len(AllDocumentedSymbols[symbol]) > 0:
-                n_documented += 1
-            else:
-                # cut off the leading namespace ($TMPL_DIR)
-                m = re.search(r'^.*\/(.*)$', symbol)
-                buffer_descriptions += m.group(1) + "\n"
-
-    if total == 0:
-        percent = 100
-    else:
-        percent = (n_documented / total) * 100.0
-
-
-    UNDOCUMENTED.write("%.0f%% symbol docs coverage.\n"%percent)
-    UNDOCUMENTED.write("%s symbols documented.\n" % n_documented)
-    UNDOCUMENTED.write("%s symbols incomplete.\n" % n_incomplete)
-    UNDOCUMENTED.write("%d not documented.\n" % (total - n_documented))
-
-    if buffer_deprecated != '':
-        buffer += "\n" + buffer_deprecated
-
-    if buffer_descriptions != '':
-        buffer += "\n" + buffer_descriptions
-
-    if buffer != '':
-        UNDOCUMENTED.write("\n\n" + buffer)
-
-    UNDOCUMENTED.close()
-
-    return common.UpdateFileIfChanged(old_undocumented_file, new_undocumented_file, 0)
-
-#    printf "%.0f%% symbol docs coverage", $percent
-#    print "($n_documented symbols documented, $n_incomplete symbols incomplete, " . ($total - 
$n_documented) . " not documented)\n"
-#    print "See $MODULE-undocumented.txt for a list of missing docs.\nThe doc coverage percentage doesn't 
include intro sections.\n"
-
+        if ($symbol !~ 
/:(Title|Long_Description|Short_Description|See_Also|Stability_Level|Include|Section_Id|Image)/) {
+            $total++;
+            if (exists ($AllDocumentedSymbols{$symbol})) {
+                $n_documented++;
+                if (exists ($AllIncompleteSymbols{$symbol})) {
+                    $n_incomplete++;
+                    $buffer .= $symbol . " (" . $AllIncompleteSymbols{$symbol} . ")\n";
+                    #$buffer .= "\t0: ".$location;
+                }
+            } elsif (exists $Deprecated{$symbol}) {
+                if (exists ($AllIncompleteSymbols{$symbol})) {
+                    $n_incomplete++;
+                    $buffer_deprecated .= $symbol . " (" . $AllIncompleteSymbols{$symbol} . ")\n";
+                    #$buffer .= "\t1a: ".$location;
+                } else {
+                    $buffer_deprecated .= $symbol . "\n";
+                    #$buffer .= "\t1b: ".$location;
+                }
+            } else {
+                if (exists ($AllIncompleteSymbols{$symbol})) {
+                    $n_incomplete++;
+                    $buffer .= $symbol . " (" . $AllIncompleteSymbols{$symbol} . ")\n";
+                    #$buffer .= "\t2a: ".$location;
+                } else {
+                    $buffer .= $symbol . "\n";
+                    #$buffer .= "\t2b: ".$location;
+                }
+            }
+        } elsif ($symbol =~ /:(Long_Description|Short_Description)/) {
+            $total++;
+            if (((exists ($SymbolDocs{$symbol})) && (length ($SymbolDocs{$symbol}) > 0))
+            || ((exists ($AllDocumentedSymbols{$symbol})) && (length ($AllDocumentedSymbols{$symbol}) > 0))) 
{
+              $n_documented++;
+            } else {
+              # cut off the leading namespace ($TMPL_DIR)
+              $symbol =~ m/^.*\/(.*)$/;
+              $buffer_descriptions .= $1 . "\n";
+            }
+        }
+    }
+
+    if ($total == 0) {
+      $percent = 100;
+    } else {
+      $percent = ($n_documented / $total) * 100.0;
+    }
+
+    printf UNDOCUMENTED "%.0f%% symbol docs coverage.\n", $percent;
+    print UNDOCUMENTED "$n_documented symbols documented.\n";
+    print UNDOCUMENTED "$n_incomplete symbols incomplete.\n";
+    print UNDOCUMENTED ($total - $n_documented) . " not documented.\n";
+
+    if ($buffer_deprecated ne "") {
+      $buffer .= "\n" . $buffer_deprecated;
+    }
+    if ($buffer_descriptions ne "") {
+      $buffer .= "\n" . $buffer_descriptions;
+    }
+    if ($buffer ne "") {
+      print UNDOCUMENTED "\n\n$buffer";
+    }
+    close (UNDOCUMENTED);
+
+    return &UpdateFileIfChanged ($old_undocumented_file, $new_undocumented_file, 0);
+
+    printf "%.0f%% symbol docs coverage", $percent;
+    print "($n_documented symbols documented, $n_incomplete symbols incomplete, " . ($total - $n_documented) 
. " not documented)\n";
+    print "See $MODULE-undocumented.txt for a list of missing docs.\nThe doc coverage percentage doesn't 
include intro sections.\n";
+}
 
 
 #############################################################################
@@ -4193,21 +4547,22 @@ def OutputMissingDocumentation():
 # Arguments   : none
 #############################################################################
 
-def OutputUndeclaredSymbols():
-    old_undeclared_file = os.path.join(ROOT_DIR, MODULE + "-undeclared.txt")
-    new_undeclared_file = os.path.join(ROOT_DIR, MODULE + "-undeclared.new")
-
-    UNDECLARED = open(new_undeclared_file, 'w')
+sub OutputUndeclaredSymbols {
+    my $old_undeclared_file = "$ROOT_DIR/$MODULE-undeclared.txt";
+    my $new_undeclared_file = "$ROOT_DIR/$MODULE-undeclared.new";
 
-    if UndeclaredSymbols:
-        UNDECLARED.write("\n".join(sorted(UndeclaredSymbols.keys())))
-        UNDECLARED.write("\n")
-        print("See %s-undeclared.txt for the list of undeclared symbols." % MODULE)
+    open(UNDECLARED, ">$new_undeclared_file")
+        || die "Can't create $new_undeclared_file";
 
-    UNDECLARED.close()
-
-    return common.UpdateFileIfChanged(old_undeclared_file, new_undeclared_file, 0)
+    if (%UndeclaredSymbols) {
+        print UNDECLARED (join("\n", sort keys %UndeclaredSymbols));
+        print UNDECLARED "\n";
+        print "See $MODULE-undeclared.txt for the list of undeclared symbols.\n"
+    }
+    close(UNDECLARED);
 
+    return &UpdateFileIfChanged ($old_undeclared_file, $new_undeclared_file, 0);
+}
 
 #############################################################################
 # Function    : OutputUnusedSymbols
@@ -4217,30 +4572,32 @@ def OutputUndeclaredSymbols():
 # Arguments   : none
 #############################################################################
 
-def OutputUnusedSymbols():
-    num_unused = 0
-    old_unused_file = os.path.join(ROOT_DIR, MODULE + "-unused.txt")
-    new_unused_file = os.path.join(ROOT_DIR, MODULE + "-unused.new")
-
-    UNUSED = open(new_unused_file, 'w')
-
-    for symbol in sorted(Declarations.keys()):
-        if not symbol in DeclarationOutput:
-            UNUSED.write("%s\n" % symbol)
-            num_unused += 1
-
-
-    for symbol in sorted(AllUnusedSymbols.keys()):
-        UNUSED.write(symbol + "(" + AllUnusedSymbols[symbol] + ")\n")
-        num_unused += 1
-
-    UNUSED.close()
-    if num_unused != 0:
-        common.LogWarning(old_unused_file, 1, "%d unused declarations. They should be added to 
%s-sections.txt in the appropriate place." % (num_unused, MODULE))
-
-
-    return common.UpdateFileIfChanged(old_unused_file, new_unused_file, 0)
-
+sub OutputUnusedSymbols {
+    my $num_unused = 0;
+    my $old_unused_file = "$ROOT_DIR/$MODULE-unused.txt";
+    my $new_unused_file = "$ROOT_DIR/$MODULE-unused.new";
+
+    open (UNUSED, ">$new_unused_file")
+        || die "Can't open $new_unused_file";
+    my ($symbol);
+    foreach $symbol (sort keys (%Declarations)) {
+        if (!defined ($DeclarationOutput{$symbol})) {
+            print (UNUSED "$symbol\n");
+            $num_unused++;
+        }
+    }
+    foreach $symbol (sort (keys (%AllUnusedSymbols))) {
+        print (UNUSED "$symbol(" . $AllUnusedSymbols{$symbol} . ")\n");
+        $num_unused++;
+    }
+    close (UNUSED);
+    if ($num_unused != 0) {
+        &LogWarning ($old_unused_file, 1, "$num_unused unused declarations.".
+            "They should be added to $MODULE-sections.txt in the appropriate place.");
+    }
+
+    return &UpdateFileIfChanged ($old_unused_file, $new_unused_file, 0);
+}
 
 
 #############################################################################
@@ -4250,13 +4607,22 @@ def OutputUnusedSymbols():
 # Arguments   : none
 #############################################################################
 
-def OutputAllSymbols():
-    SYMBOLS = open(os.path.join(ROOT_DIR, MODULE + "-symbols.txt"), 'w')
+sub OutputAllSymbols {
+     my $n_documented = 0;
+     my $total = 0;
+     my $symbol;
+     my $percent;
+     my $msg;
+
+     open (SYMBOLS, ">$ROOT_DIR/$MODULE-symbols.txt")
+          || die "Can't create $ROOT_DIR/$MODULE-symbols.txt: $!";
 
-    for symbol in sorted(AllSymbols.keys()):
-        SYMBOLS.write(symbol + "\n")
-    SYMBOLS.close()
+     foreach $symbol (sort (keys (%AllSymbols))) {
+          print SYMBOLS $symbol . "\n";
+     }
 
+     close (SYMBOLS);
+}
 
 #############################################################################
 # Function    : OutputSymbolsWithoutSince
@@ -4265,13 +4631,25 @@ def OutputAllSymbols():
 # Arguments   : none
 #############################################################################
 
-def OutputSymbolsWithoutSince():
-    SYMBOLS = open(os.path.join(ROOT_DIR, MODULE + "-nosince.txt"), 'w')
+sub OutputSymbolsWithoutSince {
+     my $n_documented = 0;
+     my $total = 0;
+     my $symbol;
+     my $percent;
+     my $msg;
+
+     open (SYMBOLS, ">$ROOT_DIR/$MODULE-nosince.txt")
+          || die "Can't create $ROOT_DIR/$MODULE-nosince.txt: $!";
+
+     foreach $symbol (sort (keys (%SourceSymbolDocs))) {
+         if (!defined $Since{$symbol}) {
+             print SYMBOLS $symbol . "\n";
+         }
+     }
+
+     close (SYMBOLS);
+}
 
-    for symbol in sorted(SourceSymbolDocs.keys()):
-        if symbol in Since:
-            SYMBOLS.write(symbol + "\n")
-    SYMBOLS.close()
 
 #############################################################################
 # Function    : MergeSourceDocumentation
@@ -4285,229 +4663,258 @@ def OutputSymbolsWithoutSince():
 # Arguments   : none
 #############################################################################
 
-def MergeSourceDocumentation():
-    if len(SymbolDocs) > 0:
-        Symbols = SymbolDocs.keys()
-        logging.info("num existing entries: %d\n", len(Symbols))
+sub MergeSourceDocumentation {
+    my $symbol;
+    my @Symbols;
 
-    else:
+    if (scalar %SymbolDocs) {
+        @Symbols=keys (%SymbolDocs);
+        @TRACE@("num existing entries: ".(scalar @Symbols)."\n");
+    }
+    else {
         # filter scanned declarations, with what we suppress from -sections.txt
-        tmp = {}
-        for symbol in Declarations.keys():
-            if symbol in KnownSymbols and KnownSymbols[symbol] == 1:
-                tmp[symbol] = 1
-
-
+        my %tmp = ();
+        foreach $symbol (keys (%Declarations)) {
+            if (defined($KnownSymbols{$symbol}) && $KnownSymbols{$symbol} == 1) {
+                $tmp{$symbol}=1;
+            }
+        }
         # , add the rest from -sections.txt
-        for symbol in KnownSymbols.keys():
-            if KnownSymbols[symbol] == 1:
-                tmp[symbol] = 1
-
-
+        foreach $symbol (keys (%KnownSymbols)) {
+            if ($KnownSymbols{$symbol} == 1) {
+                $tmp{$symbol}=1;
+            }
+        }
         # and add whats found in the source
-        for symbol in SourceSymbolDocs.keys():
-            tmp[symbol] = 1
+        foreach $symbol (keys (%SourceSymbolDocs)) {
+            $tmp{$symbol}=1;
+        }
+        @Symbols = keys (%tmp);
+        @TRACE@("num source entries: ".(scalar @Symbols)."\n");
+    }
+    foreach $symbol (@Symbols) {
+        $AllSymbols{$symbol} = 1;
 
-        Symbols = tmp.keys()
-        logging.info("num source entries: %d\n", len(Symbols))
-
-    for symbol in Symbols:
-        AllSymbols[symbol] = 1
-
-        have_tmpl_docs = 0
+        my $have_tmpl_docs = 0;
 
         ## see if the symbol is documented in template
-        tmpl_doc = SymbolDocs.get(symbol, '')
-        check_tmpl_doc = tmpl_doc
+        my $tmpl_doc = defined ($SymbolDocs{$symbol}) ? $SymbolDocs{$symbol} : "";
+        my $check_tmpl_doc =$tmpl_doc;
         # remove all xml-tags and whitespaces
-        check_tmpl_doc = re.sub(r'<.*?>', '', check_tmpl_doc)
-        check_tmpl_doc = re.sub(r'\s', '', check_tmpl_doc)
+        $check_tmpl_doc =~ s/<.*?>//g;
+        $check_tmpl_doc =~ s/\s//g;
         # anything left ?
-        if check_tmpl_doc != '':
-            have_tmpl_docs = 1
-        else:
+        if ($check_tmpl_doc ne "") {
+            $have_tmpl_docs = 1;
+        } else {
             # if the docs have just an empty para, don't merge that.
-            check_tmpl_doc = re.sub(r'(\s|\n)', '', tmpl_doc, flags=re.M|re.S)
-            if check_tmpl_doc == "<para></para>":
-                tmpl_doc = ''
-
-        if symbol in SourceSymbolDocs:
-            stype = DeclarationTypes[symbol]
-
-            logging.info("merging [%s] from source\n", symbol)
-
-            item = "Parameter"
-            if stype:
-                if stype == 'STRUCT':
-                    item = "Field"
-                elif stype == 'ENUM':
-                    item = "Value"
-                elif stype == 'UNION':
-                    item = "Field"
-            else:
-                stype = "SIGNAL"
-
-            src_doc = SourceSymbolDocs[symbol]
+            $check_tmpl_doc = $tmpl_doc;
+            $check_tmpl_doc =~ s/(\s|\n)//msg;
+            if ($check_tmpl_doc eq "<para></para>") {
+               $tmpl_doc = "";
+            }
+        }
+
+        if (exists ($SourceSymbolDocs{$symbol})) {
+            my $type = $DeclarationTypes {$symbol};
+
+            @TRACE@("merging [$symbol] from source\n");
+
+            my $item = "Parameter";
+            if (defined ($type)) {
+                if ($type eq 'STRUCT') {
+                    $item = "Field";
+                } elsif ($type eq 'ENUM') {
+                    $item = "Value";
+                } elsif ($type eq 'UNION') {
+                    $item = "Field";
+                }
+            } else {
+                $type="SIGNAL";
+            }
+
+            my $src_doc = $SourceSymbolDocs{$symbol};
             # remove leading and training whitespaces
-            src_doc = src_doc.strip()
+            $src_doc =~ s/^\s+//;
+            $src_doc =~ s/\s+$//;
 
             # Don't output warnings for overridden titles as titles are
             # automatically generated in the -sections.txt file, and thus they
             # are often overridden.
-            m = re.search(r':Title$', symbol)
-            if have_tmpl_docs and not m:
+            if ($have_tmpl_docs && $symbol !~ m/:Title$/) {
                 # check if content is different
-                if tmpl_doc != src_doc:
-                    #print "[$tmpl_doc] [$src_doc]\n"
-                    common.LogWarning(SourceSymbolSourceFile[symbol], SourceSymbolSourceLine[symbol],
-                                      "Documentation in template " + SymbolSourceFile[symbol] + ":" + 
SymbolSourceLine[symbol] + " for %s being overridden by inline comments." % symbol)
-
-            if src_doc != '':
-                AllDocumentedSymbols[symbol] = 1
+                if ($tmpl_doc ne $src_doc) {
+                    #print "[$tmpl_doc] [$src_doc]\n";
+                    &LogWarning ($SourceSymbolSourceFile{$symbol}, $SourceSymbolSourceLine{$symbol},
+                        "Documentation in template 
".$SymbolSourceFile{$symbol}.":".$SymbolSourceLine{$symbol}." for $symbol being overridden by inline 
comments.");
+                }
+            }
 
+            if ($src_doc ne "") {
+                 $AllDocumentedSymbols{$symbol} = 1;
+            }
 
             # Do not add <para> to nothing, it breaks missing docs checks.
-            src_doc_para = ''
-            if src_doc != '':
-                src_doc_para = src_doc
-
-
-            m = re.search(r'$TMPL_DIR\/.+:Long_Description', symbol)
-            m2 = re.search(TMPL_DIR + r'\/.+:.+', symbol)
-            if m:
-                SymbolDocs[symbol] = '%s%s' % (src_doc_para, tmpl_doc)
-            elif m2:
+            my $src_doc_para = "";
+            if ($src_doc ne "") {
+                $src_doc_para = $src_doc;
+            }
+
+            if ($symbol =~ m/$TMPL_DIR\/.+:Long_Description/) {
+                $SymbolDocs{$symbol} = "$src_doc_para$tmpl_doc";
+            } elsif ($symbol =~ m/$TMPL_DIR\/.+:.+/) {
                 # For the title/summary/see also section docs we don't want to
                 # add any <para> tags.
-                SymbolDocs[symbol] = src_doc
-            else:
-                SymbolDocs[symbol] = '%s%s' % (src_doc_para, tmpl_doc)
+                $SymbolDocs{$symbol} = "$src_doc"
+            } else {
+                $SymbolDocs{$symbol} = "$src_doc_para$tmpl_doc";
+            }
 
             # merge parameters
-            if re.search(r'.*::.*', symbol):
+            if ($symbol =~ m/.*::.*/) {
                 # For signals we prefer the param names from the source docs,
                 # since the ones from the templates are likely to contain the
                 # artificial argn names which are generated by gtkdoc-scangobj.
-                SymbolParams[symbol] = SourceSymbolParams[symbol]
+                $SymbolParams{$symbol} = $SourceSymbolParams{$symbol};
                 # FIXME: we need to check for empty docs here as well!
-            else:
+            } else {
                 # The templates contain the definitive parameter names and order,
                 # so we will not change that. We only override the actual text.
-                tmpl_params = SymbolParams[symbol]
-                if tmpl_params:
-                    logging.info("No merge needed for %s\n", symbol)
-                    SymbolParams[symbol] = SourceSymbolParams[symbol]
+                my $tmpl_params = $SymbolParams{$symbol};
+                if (!defined ($tmpl_params)) {
+                    @TRACE@("No merge needed for $symbol\n");
+                    $SymbolParams{$symbol} = $SourceSymbolParams{$symbol};
                     #  FIXME: we still like to get the number of params and merge
                     #  1) we would noticed that params have been removed/renamed
                     #  2) we would catch undocumented params
                     #  params are not (yet) exported in -decl.txt so that we
                     #  could easily grab them :/
-                else:
-                    params = SourceSymbolParams[symbol]
-                    logging.info("Merge needed for %s, tmpl_params: %d, source_params: %d \n", symbol, 
len(tmpl_params), len(params))
-                    for j in range(0, len(tmpl_params), PARAM_FIELD_COUNT):
-                        tmpl_param_name = tmpl_params[j]
+                } else {
+                    my $params = $SourceSymbolParams{$symbol};
+                    my $j;
+                    @TRACE@("Merge needed for $symbol, tmpl_params: ",$#$tmpl_params,", source_params: 
",$#$params," \n");
+                    for ($j = 0; $j <= $#$tmpl_params; $j += $PARAM_FIELD_COUNT) {
+                        my $tmpl_param_name = $$tmpl_params[$j];
 
                         # Try to find the param in the source comment documentation.
-                        found = False
-                        logging.info("  try merge param %s\n", tmpl_param_name)
-                        for k in range(0, len(params), PARAM_FIELD_COUNT):
-                            param_name = params[k]
-                            param_desc = params[k + 1]
-
-                            logging.info("    test param  %s\n", param_name)
+                        my $found = 0;
+                        my $k;
+                        @TRACE@("  try merge param $tmpl_param_name\n");
+                        for ($k = 0; $k <= $#$params; $k += $PARAM_FIELD_COUNT) {
+                            my $param_name = $$params[$k];
+                            my $param_desc = $$params[$k + 1];
+
+                            @TRACE@("    test param  $param_name\n");
                             # We accept changes in case, since the Gnome source
                             # docs contain a lot of these.
-                            if param_name.lower() == tmpl_param_name.lower():
-                                found = True
+                            if ("\L$param_name" eq "\L$tmpl_param_name") {
+                                $found = 1;
 
                                 # Override the description.
-                                tmpl_params[j + 1] = param_desc
+                                $$tmpl_params[$j + 1] = $param_desc;
 
-                                # Set the name to '' to mark it as used.
-                                params[k] = ''
-                                break
+                                # Set the name to "" to mark it as used.
+                                $$params[$k] = "";
+                                last;
+                            }
+                        }
 
                         # If it looks like the parameters are there, but not
                         # in the right place, try to explain a bit better.
-                        if found and re.search(r'\@%s:' % tmpl_param_name, src_doc):
-                            common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                              "Parameters for %s must start on the line immediately after 
the function or macro name." % symbol)
+                        if ((!$found) && ($src_doc =~ m/\@$tmpl_param_name:/)) {
+                            &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                                "Parameters for $symbol must start on the line immediately after the 
function or macro name.");
+                        }
+                    }
 
                     # Now we output a warning if parameters have been described which
                     # do not exist.
-                    for j in range(0, len(params), PARAM_FIELD_COUNT):
-                        param_name = params[j]
-                        if param_name:
+                    for ($j = 0; $j <= $#$params; $j += $PARAM_FIELD_COUNT) {
+                        my $param_name = $$params[$j];
+                        if ($param_name) {
                             # the template builder cannot detect if a macro returns
                             # a result or not
-                            if stype == "MACRO" and param_name == "Returns":
+                            if(($type eq "MACRO") && ($param_name eq "Returns")) {
                                 # FIXME: do we need to add it then to tmpl_params[] ?
-                                num = len(tmpl_params)
-                                logging.info("  adding Returns: to macro docs for %s.", symbol)
-                                tmpl_params[num+1] = "Returns"
-                                tmpl_params[num+2] = params[j+1]
-                                continue
-
-                            common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                              "%s described in source code comment block but does not exist. 
%s: %s %s: %s." % (item, stype, symbol, item, param_name))
-
-        else:
-            if have_tmpl_docs:
-                AllDocumentedSymbols[symbol] = 1
-                logging.info("merging [%s] from template", symbol)
-
-            else:
-                logging.info("[%s] undocumented\n", symbol)
+                                my $num=$#$tmpl_params;
+                                @TRACE@("  adding Returns: to macro docs for $symbol.\n");
+                                $$tmpl_params[$num+1]="Returns";
+                                $$tmpl_params[$num+2]=$$params[$j+1];
+                                next;
+                            }
+                            &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                                "$item described in source code comment block but does not exist. $type: 
$symbol $item: $param_name.");
+                        }
+                    }
+                }
+            }
+        } else {
+            if ($have_tmpl_docs) {
+                $AllDocumentedSymbols{$symbol} = 1;
+                @TRACE@("merging [$symbol] from template\n");
+            }
+            else {
+                @TRACE@("[$symbol] undocumented\n");
+            }
+        }
 
         # if this symbol is documented, check if docs are complete
-        check_tmpl_doc = SymbolDocs.get(symbol, '')
+        $check_tmpl_doc = defined ($SymbolDocs{$symbol}) ? $SymbolDocs{$symbol} : "";
         # remove all xml-tags and whitespaces
-        check_tmpl_doc = re.sub(r'<.*?>', '', check_tmpl_doc)
-        check_tmpl_doc = re.sub(r'\s', '', check_tmpl_doc)
-        if check_tmpl_doc != '':
-            tmpl_params = SymbolParams[symbol]
-            if tmpl_params:
-                stype = DeclarationTypes[symbol]
-
-                item = "Parameter"
-                if stype:
-                    if stype == 'STRUCT':
-                        item = "Field"
-                    elif stype == 'ENUM':
-                        item = "Value"
-                    elif stype == 'UNION':
-                        item = "Field"
-
-                else:
-                    stype = "SIGNAL"
-                logging.info("Check param docs for %s, tmpl_params: %s entries, type=%s\n", symbol, 
len(tmpl_params), stype)
-
-                if len(tmpl_params > 0):
-                    for j in range(0, len(tmpl_params), PARAM_FIELD_COUNT):
+        $check_tmpl_doc =~ s/<.*?>//g;
+        $check_tmpl_doc =~ s/\s//g;
+        if ($check_tmpl_doc ne "") {
+            my $tmpl_params = $SymbolParams{$symbol};
+            if (defined ($tmpl_params)) {
+                my $type = $DeclarationTypes {$symbol};
+
+                my $item = "Parameter";
+                if (defined ($type)) {
+                    if ($type eq 'STRUCT') {
+                        $item = "Field";
+                    } elsif ($type eq 'ENUM') {
+                        $item = "Value";
+                    } elsif ($type eq 'UNION') {
+                        $item = "Field";
+                    }
+                } else {
+                    $type="SIGNAL";
+                }
+
+                @TRACE@("Check param docs for $symbol, tmpl_params: ",$#$tmpl_params," entries, 
type=$type\n");
+
+                if ($#$tmpl_params > 0) {
+                    my $j;
+                    for ($j = 0; $j <= $#$tmpl_params; $j += $PARAM_FIELD_COUNT) {
                         # Output a warning if the parameter is empty and
                         # remember for stats.
-                        tmpl_param_name = tmpl_params[j]
-                        tmpl_param_desc = tmpl_params[j + 1]
-                        if tmpl_param_name != "void" and not re.search(r'\S', tmpl_param_desc):
-                            if symbol in AllIncompleteSymbols[symbol]:
-                                AllIncompleteSymbols[symbol] += ", " + tmpl_param_name
-                            else:
-                                AllIncompleteSymbols[symbol] = tmpl_param_name
-
-                            common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                              "%s description for %s::%s is missing in source code comment 
block." % (item, symbol, tmpl_param_name))
-
-                else:
-                    if len(tmpl_params) == 0:
-                        AllIncompleteSymbols[symbol] = "<items>"
-                        common.LogWarning(GetSymbolSourceFile(symbol), GetSymbolSourceLine(symbol),
-                                          "%s descriptions for %s are missing in source code comment block." 
% (item, symbol))
-
+                        my $tmpl_param_name = $$tmpl_params[$j];
+                        my $tmpl_param_desc = $$tmpl_params[$j + 1];
+                        if ($tmpl_param_name ne "void" && $tmpl_param_desc !~ m/\S/) {
+                            if (exists ($AllIncompleteSymbols{$symbol})) {
+                                $AllIncompleteSymbols{$symbol}.=", ".$tmpl_param_name;
+                            } else {
+                                $AllIncompleteSymbols{$symbol}=$tmpl_param_name;
+                            }
+                            &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                                "$item description for $symbol"."::"."$tmpl_param_name is missing in source 
code comment block.");
+                        }
+                    }
+                }
+                else {
+                    if ($#$tmpl_params == 0) {
+                        $AllIncompleteSymbols{$symbol}="<items>";
+                        &LogWarning (&GetSymbolSourceFile ($symbol), &GetSymbolSourceLine($symbol),
+                            "$item descriptions for $symbol are missing in source code comment block.");
+                    }
                     # $#$tmpl_params==-1 means we don't know about parameters
                     # this unfortunately does not tell if there should be some
-    logging.info("num doc entries: %d\n", len(SymbolDocs))
-
+                }
+            }
+        }
+   }
+   @TRACE@("num doc entries: ".(scalar %SymbolDocs)."\n");
+}
 
 #############################################################################
 # Function    : IsEmptyDoc
@@ -4515,18 +4922,19 @@ def MergeSourceDocumentation():
 #               it only consist of whitespace or e.g. FIXME.
 # Arguments   : the doc-string
 #############################################################################
-def IsEmptyDoc(doc):
-
-    if re.search(r'^\s*$', doc):
-        return True
-
+sub IsEmptyDoc {
+    my ($doc) = @_;
 
-    if re.search(r'^\s*<para>\s*(FIXME)?\s*<\/para>\s*$', doc):
-        return True
+    if ($doc =~ /^\s*$/) {
+        return 1;
+    }
 
+    if ($doc =~ /^\s*<para>\s*(FIXME)?\s*<\/para>\s*$/) {
+        return 1;
+    }
 
-    return False
-
+    return 0;
+}
 
 #############################################################################
 # Function    : ConvertMarkDown
@@ -4538,10 +4946,13 @@ def IsEmptyDoc(doc):
 # Arguments   : the symbol name, the doc-string
 #############################################################################
 
-def ConvertMarkDown(symbol, text):
-    text = MarkDownParse(text, symbol)
-    return text
+sub ConvertMarkDown {
+    my ($symbol, $text) = @_;
 
+    $text = &MarkDownParse ($text, $symbol);
+
+    return $text
+}
 
 # SUPPORTED MARKDOWN
 # ==================
@@ -4577,719 +4988,728 @@ def ConvertMarkDown(symbol, text):
 
 # TODO(ensonic): it would be nice to add id parameters to the refsect2 elements
 
-def MarkDownParseBlocks(linesref, symbol, context):
-  md_blocks = []
-  md_block = {"type": ''}
-
-  # FIXME the original code had OUTER tag here but there does not seem to be inner loops.
-  for line in linesref:
-    first_char = line[0]
-
-    logging.info("in '" + md_block["type"] + "' state, parsing '%s'" % line)
-
-    if md_block["type"] == "markup":
-      if not md_block["closed"]:
-        if md_block["start"] in line:
-          md_block["depth"] += 1
-
-        if md_block["end"] in line:
-          if md_block["depth"] > 0:
-            md_block["depth"] -= 1
-          else:
-            logging.info("closing tag '%s'", line)
-            md_block["closed"] = 1
+sub MarkDownParseBlocks {
+  my ($linesref, $symbol, $context) = @_;
+  my $line;
+  my @md_blocks = ();
+  my $md_block = { type => "" };
+
+ OUTER: foreach $line (@$linesref) {
+    my $first_char = substr ($line, 0, 1);
+    my $deindented_line;
+
+    @TRACE@("in '".$md_block->{"type"}."' state, parsing '$line'");
+
+    if ($md_block->{"type"} eq "markup") {
+      if (!$md_block->{"closed"}) {
+        if (index ($line, $md_block->{"start"}) != -1) {
+          $md_block->{"depth"}++;
+        }
+        if (index ($line, $md_block->{"end"}) != -1) {
+          if ($md_block->{"depth"} > 0) {
+            $md_block->{"depth"}--;
+          } else {
+            @TRACE@("closing tag '$line'");
+            $md_block->{"closed"} = 1;
             # TODO(ensonic): reparse inner text with MarkDownParseLines?
+          }
+        }
+        $md_block->{"text"} .= "\n" . $line;
+        @TRACE@("add to markup");
+        next OUTER;
+      }
+    }
 
-        md_block["text"] += "\n" + line
-        logging.info("add to markup")
-        continue
-
-    deindented_line = line.lstrip()
+    $deindented_line = $line;
+    $deindented_line =~ s/^\s+//;
 
-    m = re.search(r'^[#][ \t]+(.+?)[ \t]*[#]*[ \t]*(?:{#([^}]+)})?[ \t]*$', line)
-    if md_block["type"] == "heading":
+    if ($md_block->{"type"} eq "heading") {
       # a heading is ended by any level less than or equal
-      if md_block["level"] == 1:
-        if re.search(r'^={4,}[ \t]*$', line):
-          text = md_block["lines"].pop()
-          md_block["interrupted"] = 0
-          md_blocks.append(md_block)
-
-          md_block = {'type': "heading",
-                      'text': text,
-                      'lines': [],
-                      'level': 1,
-                     }
-          continue
-        elif m:
-          md_block["interrupted"] = 0
-          md_blocks.append(md_block)
-
-          md_block = {'type': "heading",
-                      'text': m.group(1),
-                      'id': m.group(2),
-                      'lines': [],
-                      'level': 1,
-                     }
-          continue
-        else:
+      if ($md_block->{"level"} == 1) {
+        if ($line =~ /^={4,}[ \t]*$/) {
+          my $text = pop @{$md_block->{"lines"}};
+          $md_block->{"interrupted"} = 0;
+          push @md_blocks, $md_block;
+
+          $md_block = { type => "heading",
+                        text => $text,
+                        lines => [],
+                        level => 1 };
+          next OUTER;
+        } elsif ($line =~ /^[#][ \t]+(.+?)[ \t]*[#]*[ \t]*(?:{#([^}]+)})?[ \t]*$/) {
+          $md_block->{"interrupted"} = 0;
+          push @md_blocks, $md_block;
+
+          $md_block = { type => "heading",
+                        text => $1,
+                        id => $2,
+                        lines => [],
+                        level => 1 };
+          next OUTER;
+        } else {
           # push lines into the block until the end is reached
-          md_block["lines"].append(line)
-          continue
-
-      else:
-        m2 = re.search(r'^([#]{1,2})[ \t]+(.+?)[ \t]*[#]*[ \t]*(?:{#([^}]+)})?[ \t]*$', line)
-        if re.search(r'^[=]{4,}[ \t]*$', line):
-          text = md_block["lines"].pop()
-          md_block["interrupted"] = 0
-          md_blocks.append(md_block)
-
-          md_block = {'type': "heading",
-                      'text': text,
-                      'lines': [],
-                      'level': 1,
-          }
-          continue
-        elif re.search(r'^[-]{4,}[ \t]*$', line):
-          text = md_block["lines"].pop()
-          md_block["interrupted"] = 0
-          md_blocks.append(md_block)
-
-          md_block = {'type': "heading",
-                      'text': text,
-                      'lines': [],
-                      'level': 2,
-                      }
-          continue
-        elif m2:
-          md_block["interrupted"] = 0
-          md_blocks.append(md_block)
-
-          md_block = {'type': "heading",
-                      'text': m2.group(2),
-                      'id': m2.group(3),
-                      'lines': [],
-                      'level': len(m2.group(1))
-                      }
-          continue
-        else:
+          push @{$md_block->{"lines"}}, $line;
+          next OUTER;
+        }
+      } else {
+        if ($line =~ /^[=]{4,}[ \t]*$/) {
+          my $text = pop @{$md_block->{"lines"}};
+          $md_block->{"interrupted"} = 0;
+          push @md_blocks, $md_block;
+
+          $md_block = { type => "heading",
+                        text => $text,
+                        lines => [],
+                        level => 1 };
+          next OUTER;
+        } elsif ($line =~ /^[-]{4,}[ \t]*$/) {
+          my $text = pop @{$md_block->{"lines"}};
+          $md_block->{"interrupted"} = 0;
+          push @md_blocks, $md_block;
+
+          $md_block = { type => "heading",
+                        text => $text,
+                        lines => [],
+                        level => 2 };
+          next OUTER;
+        } elsif ($line =~ /^([#]{1,2})[ \t]+(.+?)[ \t]*[#]*[ \t]*(?:{#([^}]+)})?[ \t]*$/) {
+          $md_block->{"interrupted"} = 0;
+          push @md_blocks, $md_block;
+
+          $md_block = { type => "heading",
+                        text => $2,
+                        id => $3,
+                        lines => [],
+                        level => length($1) };
+          next OUTER;
+        } else {
           # push lines into the block until the end is reached
-          md_block["lines"].append(line)
-          continue
-    elif md_block["type"] == "code":
-      m3 = re.search(r'^[ \t]*\]\|(.*)', line)
-      if m3:
-        md_blocks.append(md_block)
-        md_block = {'type': "paragraph",
-                    'text': "$1",
-                    'lines': [],
-                    }
-      else:
-        md_block["lines"].append(line)
-
-      continue
-
-    if deindented_line == '':
-      md_block["interrupted"] = 1
-      continue
-
-
-    if md_block["type"] == "quote":
-      if not md_block["interrupted"]:
-        line = re.sub(r'^[ ]*>[ ]?', '', line)
-        md_block["lines"].append(line)
-        continue
-
-    elif md_block["type"] == "li":
-      marker = md_block["marker"]
-      m4 = re.search(r'^([ ]{0,3})($marker)[ ](.*)', line)
-      if m4:
-        indentation = m.group(1)
-        if md_block["indentation"] != indentation:
-          md_block["lines"].append(line)
-        else:
-          lines = m4.group(3)
-          ordered = md_block["ordered"]
-          lines = re.sub(r'^[ ]{0,4}', '', lines)
-          md_block["last"] = 0
-          md_blocks.append(md_block)
-          md_block = {'type': "li",
-                      'ordered': ordered,
-                      'indentation': indentation,
-                      'marker': marker,
-                      'first': 0,
-                      'last': 1,
-                      'lines': [lines],
-                      }
-
-        continue
-
-      if md_block["interrupted"]:
-        if first_char == " ":
-          md_block["lines"].append('')
-          line =  re.sub(r'^[ ]{0,4}', '', line)
-          md_block["lines"].append(line)
-          md_block["interrupted"] = 0
-          continue
-
-      else:
-        line = re.sub(r'^[ ]{0,4}', '', line)
-        md_block["lines"].append(line)
-        continue
+          push @{$md_block->{"lines"}}, $line;
+          next OUTER;
+        }
+      }
+    } elsif ($md_block->{"type"} eq "code") {
+      if ($line =~ /^[ \t]*\]\|(.*)/) {
+        push @md_blocks, $md_block;
+        $md_block = { type => "paragraph",
+                      text => "$1",
+                      lines => [] };
+      } else {
+        push @{$md_block->{"lines"}}, $line;
+      }
+      next OUTER;
+    }
+
+    if ($deindented_line eq "") {
+      $md_block->{"interrupted"} = 1;
+      next;
+    }
+
+    if ($md_block->{"type"} eq "quote") {
+      if (!$md_block->{"interrupted"}) {
+        $line =~ s/^[ ]*>[ ]?//;
+        push @{$md_block->{"lines"}}, $line;
+        next OUTER;
+      }
+    } elsif ($md_block->{"type"} eq "li") {
+      my $marker = $md_block->{"marker"};
+      if ($line =~ /^([ ]{0,3})($marker)[ ](.*)/) {
+        my $indentation = $1;
+        if ($md_block->{"indentation"} ne $indentation) {
+          push @{$md_block->{"lines"}}, $line;
+        } else {
+          my $lines = $3;
+          my $ordered = $md_block->{"ordered"};
+          $lines =~ s/^[ ]{0,4}//;
+          $md_block->{"last"} = 0;
+          push @md_blocks, $md_block;
+          $md_block = { type => "li",
+                        ordered => $ordered,
+                        indentation => $indentation,
+                        marker => $marker,
+                        first => 0,
+                        last => 1,
+                        lines => [ $lines ] };
+        }
+        next OUTER;
+      }
+
+      if ($md_block->{"interrupted"}) {
+        if ($first_char eq " ") {
+          push @{$md_block->{"lines"}}, "";
+          $line =~ s/^[ ]{0,4}//;
+          push @{$md_block->{"lines"}}, $line;
+          $md_block->{"interrupted"} = 0;
+          next OUTER;
+        }
+      } else {
+        $line =~ s/^[ ]{0,4}//;
+        push @{$md_block->{"lines"}}, $line;
+        next OUTER;
+      }
+    }
 
     # indentation sensitive types
-    logging.info("parsing '%s'", line)
-
-    m5 = re.search(r'^([#]{1,2})[ \t]+(.+?)[ \t]*[#]*[ \t]*(?:{#([^}]+)})?[ \t]*$', line)
-    m6 = re.search(r'^[ \t]*\|\[[ ]*(?:<!-- language="([^"]+?)" -->)?', line)
-    m7 = re.search(r'^[ ]*<\??(\w+)[^>]*([\/\?])?[ \t]*>', line)
-    m8 = re.search(r'^([ ]*)[*+-][ ](.*)', line)
-    m9 = re.search(r'^[ ]*>[ ]?(.*)', line)
-    if m5:
+    @TRACE@("parsing '$line'");
+
+    if ($line =~ /^([#]{1,2})[ \t]+(.+?)[ \t]*[#]*[ \t]*(?:{#([^}]+)})?[ \t]*$/) {
       # atx heading (#)
-      md_blocks.append(md_block)
+      push @md_blocks, $md_block;
 
-      md_block = {'type': "heading",
-                  'text': m5.group(2),
-                  'id:': m5.group(3),
-                  'lines': [],
-                  'level': len(m5.group(1)),
-                  }
+      $md_block = { type => "heading",
+                    text => $2,
+                    id => $3,
+                    lines => [],
+                    level => length($1) };
 
-      continue
-    elif re.search(r'^={4,}[ \t]*$', line):
+      next OUTER;
+    } elsif ($line =~ /^={4,}[ \t]*$/) {
       # setext heading (====)
 
-      if md_block["type"] == "paragraph" and md_block["interrupted"]:
-        md_blocks.append(md_block)
-        md_block["type"] = "heading"
-        md_block["lines"] = []
-        md_block["level"] = 1
-      continue
-    elif re.search(r'^-{4,}[ \t]*$/', line):
+      if ($md_block->{"type"} eq "paragraph" && $md_block->{"interrupted"}) {
+        push @md_blocks, $md_block;
+        $md_block->{"type"} = "heading";
+        $md_block->{"lines"} = [];
+        $md_block->{"level"} = 1;
+      }
+
+      next OUTER;
+    } elsif ($line =~ /^-{4,}[ \t]*$/) {
       # setext heading (-----)
 
-      if md_block["type"] == "paragraph" and md_block["interrupted"]:
-        md_blocks.append(md_block)
-        md_block["type"] = "heading"
-        md_block["lines"] = []
-        md_block["level"] = 2
+      if ($md_block->{"type"} eq "paragraph" && $md_block->{"interrupted"}) {
+        push @md_blocks, $md_block;
+        $md_block->{"type"} = "heading";
+        $md_block->{"lines"} = [];
+        $md_block->{"level"} = 2;
+      }
 
-      continue
-    elif m6:
+      next OUTER;
+    } elsif ($line =~ /^[ \t]*\|\[[ ]*(?:<!-- language="([^"]+?)" -->)?/) {
       # code
-      md_block["interrupted"] = 1
-      md_blocks.append(md_block)
-      md_block = {'type': "code",
-                  'language': m6.group(1),
-                  'lines': [],
-                  }
-      continue
+      $md_block->{"interrupted"} = 1;
+      push @md_blocks, $md_block;
+      $md_block = { type => "code",
+                    language => $1,
+                    lines => [] };
+      next OUTER;
+    }
 
     # indentation insensitive types
-    if re.search(r'^[ ]*<!DOCTYPE/', line):
-      md_blocks.append(md_block)
-
-      md_block = {'type'   : "markup",
-                  'text'   : deindented_line,
-                  'start'  : "<",
-                  'end'    : ">",
-                  'closed' : 0,
-                  'depth'  : 0,
-                  }
-
-    elif m7:
+    if ($line =~ /^[ ]*<!DOCTYPE/) {
+      push @md_blocks, $md_block;
+
+      $md_block = { type   => "markup",
+                    text   => $deindented_line,
+                    start  => "<",
+                    end    => ">",
+                    closed => 0,
+                    depth  => 0 };
+
+    } elsif ($line =~ /^[ ]*<\??(\w+)[^>]*([\/\?])?[ \t]*>/) {
       # markup, including <?xml version="1.0"?>
-      tag = m7.group(1)
-      is_self_closing = m7.group(2) is not None
+      my $tag = $1;
+      my $is_self_closing = defined($2);
 
       # skip link markdown
       # TODO(ensonic): consider adding more uri schemes (ftp, ...)
-      if re.search(r'https?', tag):
-        logging.info("skipping link '%s'", tag)
-      else:
+      if ($tag =~ /^https?/) {
+        @TRACE@("skipping link '$tag'");
+      } else {
         # for TEXT_LEVEL_ELEMENTS, we want to keep them as-is in the paragraph
         # instead of creation a markdown block.
-        scanning_for_end_of_text_level_tag = (
-            md_block["type"] == "paragraph" and
-            'start' in md_block and
-            not md_block["closed"])
-        logging.info("markup found '%s', scanning %s ?", tag, scanning_for_end_of_text_level_tag)
-        if not MD_TEXT_LEVEL_ELEMENTS[tag] and not scanning_for_end_of_text_level_tag:
-          md_blocks.append(md_block)
-
-          if is_self_closing:
-            logging.info("self-closing docbook '%s'", tag)
-            md_block = {'type': "self-closing tag",
-                        'text': deindented_line,
-                        }
-            is_self_closing = 0
-            continue
-
-          logging.info("new markup '%s'", tag)
-          md_block = {'type'   : "markup",
-                      'text'   : deindented_line,
-                      'start'  : "<" + tag + ">",
-                      'end'    : "</" + tag + ">",
-                      'closed' : 0,
-                      'depth'  : 0,
-                      }
-          if re.search(r'<\/%s>' % tag, deindented_line):
-            md_block["closed"] = 1
-
-          continue
-        else:
-          if MD_TEXT_LEVEL_ELEMENTS[tag]:
-            logging.info("text level docbook '%s' in '%s' state", tag, md_block["type"])
+        my $scanning_for_end_of_text_level_tag = (
+            $md_block->{"type"} eq "paragraph" &&
+            defined($md_block->{"start"}) &&
+            !$md_block->{"closed"});
+        @TRACE@("markup found '$tag', scanning $scanning_for_end_of_text_level_tag ?");
+        if (!$MD_TEXT_LEVEL_ELEMENTS{$tag} && !$scanning_for_end_of_text_level_tag) {
+          push @md_blocks, $md_block;
+
+          if ($is_self_closing) {
+            @TRACE@("self-closing docbook '$tag'");
+            $md_block = { type => "self-closing tag",
+                          text => $deindented_line };
+            $is_self_closing = 0;
+            next OUTER;
+          }
+
+          @TRACE@("new markup '$tag'");
+          $md_block = { type   => "markup",
+                        text   => $deindented_line,
+                        start  => "<" . $tag . ">",
+                        end    => "</" . $tag . ">",
+                        closed => 0,
+                        depth  => 0 };
+          if ($deindented_line =~ /<\/$tag>/) {
+            $md_block->{"closed"} = 1;
+          }
+          next OUTER;
+        } else {
+          if ($MD_TEXT_LEVEL_ELEMENTS{$tag}) {
+            @TRACE@("text level docbook '$tag' in '".$md_block->{"type"}."' state");
             # TODO(ensonic): handle nesting
-            if scanning_for_end_of_text_level_tag:
-              if not re.search(r'<\/%s>' % tag, deindented_line):
-                logging.info("new text level markup '%s'", tag)
-                md_block["start"] = "<" + tag + ">"
-                md_block["end"] = "</" + tag + ">"
-                md_block["closed"] = 0
-                logging.info("scanning for end of '%s'", tag)
-
-            else:
-              if re.search(md_block["end"], deindented_line):
-                md_block["closed"] = 1
-                logging.info("found end of '%s'", tag)
-
-    elif m8:
+            if (!$scanning_for_end_of_text_level_tag) {
+              if ($deindented_line !~ /<\/$tag>/) {
+                @TRACE@("new text level markup '$tag'");
+                $md_block->{"start"} = "<" . $tag . ">";
+                $md_block->{"end"} = "</" . $tag . ">";
+                $md_block->{"closed"} = 0;
+                @TRACE@("scanning for end of '$tag'");
+              }
+            } else {
+              if ($deindented_line =~ /$md_block->{"end"}/) {
+                $md_block->{"closed"} = 1;
+                @TRACE@("found end of '$tag'");
+              }
+            }
+          }
+        }
+      }
+    } elsif ($line =~ /^([ ]*)[*+-][ ](.*)/) {
       # li
-      md_blocks.append(md_block)
-      lines = m8.group(2)
-      indentation = m8.group(1)
-      lines = re.sub(r'^[ ]{0,4}', '', lines)
-      md_block = {'type': "li",
-                  'ordered': 0,
-                  'indentation': indentation,
-                  'marker': "[*+-]",
-                  'first': 1,
-                  'last': 1,
-                  'lines': [lines],
-                  }
-      continue
-    elif m9:
-      md_blocks.append(md_block)
-      md_block = {'type': "quote",
-                  'lines': [m9.group(1)],
-                  }
-      continue
-
+      push @md_blocks, $md_block;
+      my $lines = $2;
+      my $indentation = $1;
+      $lines =~ s/^[ ]{0,4}//;
+      $md_block = { type => "li",
+                    ordered => 0,
+                    indentation => $indentation,
+                    marker => "[*+-]",
+                    first => 1,
+                    last => 1,
+                    lines => [ $lines ] };
+      next OUTER;
+    } elsif ($line =~ /^[ ]*>[ ]?(.*)/) {
+      push @md_blocks, $md_block;
+      $md_block = { type => "quote",
+                    lines => [ $1 ] };
+      next OUTER;
+    }
 
     # list item
-    m10 = re.search(r'^([ ]{0,4})\d+[.][ ]+(.*)', line)
-    if m10:
-      md_blocks.append(md_block)
-      lines = m10.group(2)
-      indentation = m10.group(1)
-      lines = re.sub(r'^[ ]{0,4}', '', lines)
-
-      md_block = {'type': "li",
-                  'ordered': 1,
-                  'indentation': indentation,
-                  'marker': "\\d+[.]",
-                  'first': 1,
-                  'last': 1,
-                  'lines': [lines],
-                  }
-
-      continue
-
+    if ($line =~ /^([ ]{0,4})\d+[.][ ]+(.*)/) {
+      push @md_blocks, $md_block;
+      my $lines = $2;
+      my $indentation = $1;
+      $lines =~ s/^[ ]{0,4}//;
+
+      $md_block = { type => "li",
+                    ordered => 1,
+                    indentation => $indentation,
+                    marker => "\\d+[.]",
+                    first => 1,
+                    last => 1,
+                    lines => [ $lines ] };
+
+      next;
+    }
 
     # paragraph
-    if md_block["type"] == "paragraph":
-      if md_block["interrupted"]:
-        md_blocks.append(md_block)
-        md_block = {'type': "paragraph",
-                    'interrupted': 0,
-                    'text': line,
-                    }
-        logging.info("new paragraph due to interrupted")
-      else:
-        md_block["text"] += "\n" + line
-        logging.info("add to paragraph")
-
-    else:
-      md_blocks.append(md_block)
-      md_block = {'type': "paragraph",
-                  'text': line,
-                  }
-      logging.info("new paragraph due to different block type")
-
-  md_blocks.append(md_block)
-
-  return md_blocks[1:]
-
-
-def MarkDownParseSpanElementsInner(text, markersref):
-  markup = ''
-  markers = {}
-  for i in markersref:
-      markers[i] = 1
-
-  while text != '':
-    closest_marker = ''
-    # closest_marker_index = 0
-    closest_marker_position = -1
-    text_marker = ''
-    # i = 0
-    offset = 0
-    markers_rest = []
-
-    for marker, use in markers.items():
-      if not use:
-        continue
-
-
-      marker_position = text.find(marker)
-
-      if marker_position < 0:
-        markers[marker] = 0
-        continue
-
-
-      if closest_marker == '' or marker_position < closest_marker_position:
-        closest_marker = marker
-        # closest_marker_index = i
-        closest_marker_position = marker_position
-
-    if closest_marker_position >= 0:
-      text_marker = text[closest_marker_position:]
-
-
-    if text_marker == '':
-      markup += text
-      text = ''
-      continue # last
-
-
-    markup += text[0:closest_marker_position]
-    text = text[closest_marker_position:]
-    markers_rest = []
-    for key in markers.keys():
-        if markers[key]:
-            if key == closest_marker:
-                markers_rest.append([])
-            else:
-                markers_rest.append(key)
-        else:
-            markers_rest.append([])
-
-    if closest_marker == "![" or closest_marker == "[":
-      element = {}
-
-      m = re.search(r'\[((?:[^][]|(?R))*)\]', text)
-      if ']' in text and m:
-
-        element = {"!": text[0] == "!",
-                   "a": m.group(1),
-                   }
-
-        offset = len(m.group(0))
-        if element["!"]:
-          offset+=1
-
-
-        remaining_text = text[offset:]
-        m2 = re.search(r'''^\([ ]*([^)'"]*?)(?:[ ]+['"](.+?)['"])?[ ]*\)''', remaining_text)
-        m3 = re.search(r'^\s*\[([^\]<]*?)\]', remaining_text)
-        if m2:
-          element["»"] = m2.group(1)
-          if m2.group(2):
-            element["#"] = m2.group(2)
-            offset += len(m2.group(0))
-        elif m3:
-          element["ref"] = m3.group(1)
-          offset += len(m3.group(0))
-        else:
-          element = None
-
-      if element:
-        if element["»"]:
-          element["»"] = element["»"].replace('&', '&amp;')
-          element["»"] = element["»"].replace('<', '&lt;')
-
-        if element["!"]:
-          markup += '<inlinemediaobject><imageobject><imagedata fileref="' + element['»'] + 
'"></imagedata></imageobject>'
-
-          if 'a' in element:
-            markup += "<textobject><phrase>" + element["a"] + "</phrase></textobject>"
+    if ($md_block->{"type"} eq "paragraph") {
+      if ($md_block->{"interrupted"}) {
+        push @md_blocks, $md_block;
+        $md_block = { type => "paragraph",
+                      interrupted => 0,
+                      text => $line };
+        @TRACE@("new paragraph due to interrupted");
+      } else {
+        $md_block->{"text"} .= "\n" . $line;
+        @TRACE@("add to paragraph");
+      }
+    } else {
+      push @md_blocks, $md_block;
+      $md_block = { type => "paragraph",
+                    text => $line };
+      @TRACE@("new paragraph due to different block type");
+    }
+  }
+
+  push @md_blocks, $md_block;
+
+  shift @md_blocks;
+
+  return @md_blocks;
+}
 
+sub MarkDownParseSpanElementsInner {
+  my ($text, $markersref) = @_;
+  my $markup = "";
+  my %markers = map { $_ => 1 } @$markersref;
+
+  while ($text ne "") {
+    my $closest_marker = "";
+    my $closest_marker_index = 0;
+    my $closest_marker_position = -1;
+    my $text_marker = "";
+    my $i = 0;
+    my $offset = 0;
+    my @markers_rest;
+    my $marker;
+    my $use;
+
+    while ( ($marker, $use) = each %markers ) {
+      my $marker_position;
+
+      if (!$use) {
+        next;
+      }
+
+      $marker_position = index ($text, $marker);
+
+      if ($marker_position < 0) {
+        $markers{$marker} = 0;
+        next;
+      }
+
+      if ($closest_marker eq "" || $marker_position < $closest_marker_position) {
+        $closest_marker = $marker;
+        $closest_marker_index = $i;
+        $closest_marker_position = $marker_position;
+      }
+    }
+
+    if ($closest_marker_position >= 0) {
+      $text_marker = substr ($text, $closest_marker_position);
+    }
+
+    if ($text_marker eq "") {
+      $markup .= $text;
+      $text = "";
+      next; # last
+    }
+
+    $markup .= substr ($text, 0, $closest_marker_position);
+    $text = substr ($text, $closest_marker_position);
+    @markers_rest = map { $markers{$_} ? ($_ eq $closest_marker ? () : $_) : () } keys %markers;
+
+    if ($closest_marker eq "![" || $closest_marker eq "[") {
+      my %element;
+
+      if (index ($text, "]") && $text =~ /\[((?:[^][]|(?R))*)\]/) {
+        my $remaining_text;
+
+        %element = ( "!" => (substr ($text, 0, 1) eq "!"),
+                     "a" => $1 );
+
+        $offset = length ($&);
+        if ($element{"!"}) {
+          $offset++;
+        }
+
+        $remaining_text = substr ($text, $offset);
+        if ($remaining_text =~ /^\([ ]*([^)'"]*?)(?:[ ]+['"](.+?)['"])?[ ]*\)/) {
+          $element{"»"} = $1;
+          if (defined ($2)) {
+            $element{"#"} = $2;
+          }
+          $offset += length ($&);
+        } elsif ($remaining_text =~ /^\s*\[([^\]<]*?)\]/) {
+          $element{"ref"} = $1;
+          $offset += length ($&);
+        } else {
+          undef %element;
+        }
+      }
+
+      if (%element) {
+        if ($element{"»"}) {
+          $element{"»"} =~ s/&/&amp;/g;
+          $element{"»"} =~ s/</&lt;/g;
+        }
+        if ($element{"!"}) {
+          $markup .= "<inlinemediaobject><imageobject><imagedata fileref=\"" . $element{"»"} . 
"\"></imagedata></imageobject>";
+
+          if (defined ($element{"a"})) {
+            $markup .= "<textobject><phrase>" . $element{"a"} . "</phrase></textobject>";
+          }
 
-            markup += "</inlinemediaobject>"
-        elif element["ref"]:
-          element["a"] = MarkDownParseSpanElementsInner(element["a"], markers_rest)
-          markup += '<link linkend="' + element['ref'] + '"'
+          $markup .= "</inlinemediaobject>";
+        } elsif ($element{"ref"}) {
+          $element{"a"} = &MarkDownParseSpanElementsInner ($element{"a"}, \@markers_rest);
+          $markup .= "<link linkend=\"" . $element{"ref"} . "\"";
 
-          if '#' in element["#"]:
+          if (defined ($element{"#"})) {
             # title attribute not supported
+          }
 
+          $markup .= ">" . $element{"a"} . "</link>";
+        } else {
+          $element{"a"} = &MarkDownParseSpanElementsInner ($element{"a"}, \@markers_rest);
+          $markup .= "<ulink url=\"" . $element{"»"} . "\"";
 
-            markup += ">" + element["a"] + "</link>"
-        else:
-          element["a"] = MarkDownParseSpanElementsInner(element["a"], markers_rest)
-          markup += '<ulink url="' + element['»'] + '"'
-
-          if '#' in element:
+          if (defined ($element{"#"})) {
             # title attribute not supported
-            markup += ">" + element["a"] + "</ulink>"
-
-      else:
-        markup += closest_marker
-        if closest_marker == "![":
-          offset = 2
-        else:
-          offset = 1
-
-
-    elif closest_marker == "<":
-      m4 = re.search(r'^<(https?:[\/]{2}[^\s]+?)>', text)
-      m5 = re.search(r'^<([A-Za-z0-9._-]+?@[A-Za-z0-9._-]+?)>', text)
-      m6 = re.search(r'^<[^>]+?>', text)
-      if m4:
-        element_url = m4.group(1).replace('&', '&amp;').replace('<', '&lt;')
-
-        markup += '<ulink url="' + element_url + '">' + element_url + '</ulink>'
-        offset = len(m4.group(0))
-      elif m5:
-        markup += "<ulink url=\"mailto:"; + m5.group(1) + "\">" + m5.group(1) + "</ulink>"
-        offset = len(m5.group(0))
-      elif m6:
-        markup += m6.group(0)
-        offset = len(m6.group(0))
-      else:
-        markup += "&lt;"
-        offset = 1
-
-    elif closest_marker == "\\":
-      special_char = text[1]
-      if MD_ESCAPABLE_CHARS[special_char] or \
-          MD_GTK_ESCAPABLE_CHARS[special_char]:
-        markup += special_char
-        offset = 2
-      else:
-        markup += "\\"
-        offset = 1
-
-    elif closest_marker == "`":
-      m7 = re.search(r'^(`+)([^`]+?)\1(?!`)', text)
-      if m7:
-        element_text = m7.group(2)
-        markup += "<literal>" + element_text + "</literal>"
-        offset = len(m7.group(0))
-      else:
-        markup += "`"
-        offset = 1
-
-    elif closest_marker == "@":
+          }
+
+          $markup .= ">" . $element{"a"} . "</ulink>";
+        }
+      } else {
+        $markup .= $closest_marker;
+        if ($closest_marker eq "![") {
+          $offset = 2;
+        } else {
+          $offset = 1;
+        }
+      }
+    } elsif ($closest_marker eq "<") {
+      if ($text =~ /^<(https?:[\/]{2}[^\s]+?)>/i) {
+        my $element_url = $1;
+        $element_url =~ s/&/&amp;/g;
+        $element_url =~ s/</&lt;/g;
+
+        $markup .= "<ulink url=\"" . $element_url . "\">" . $element_url . "</ulink>";
+        $offset = length ($&);
+      } elsif ($text =~ /^<([A-Za-z0-9._-]+?@[A-Za-z0-9._-]+?)>/) {
+        $markup .= "<ulink url=\"mailto:"; . $1 . "\">" . $1 . "</ulink>";
+        $offset = length ($&);
+      } elsif ($text =~ /^<[^>]+?>/) {
+        $markup .= $&;
+        $offset = length ($&);
+      } else {
+        $markup .= "&lt;";
+        $offset = 1;
+      }
+    } elsif ($closest_marker eq "\\") {
+      my $special_char = substr ($text, 1, 1);
+      if ($MD_ESCAPABLE_CHARS{$special_char} ||
+          $MD_GTK_ESCAPABLE_CHARS{$special_char}) {
+        $markup .= $special_char;
+        $offset = 2;
+      } else {
+        $markup .= "\\";
+        $offset = 1;
+      }
+    } elsif ($closest_marker eq "`") {
+      if ($text =~ /^(`+)([^`]+?)\1(?!`)/) {
+        my $element_text = $2;
+        $markup .= "<literal>" . $element_text . "</literal>";
+        $offset = length ($&);
+      } else {
+        $markup .= "`";
+        $offset = 1;
+      }
+    } elsif ($closest_marker eq "@") {
       # Convert '@param()'
       # FIXME: we could make those also links ($symbol.$2), but that would be less
       # useful as the link target is a few lines up or down
-      m7 = re.search(r'^(\A|[^\\])\@(\w+((\.|->)\w+)*)\s*\(\)', text)
-      m8 = re.search(r'^(\A|[^\\])\@(\w+((\.|->)\w+)*)', text)
-      m9 = re.search(r'^\\\@', text)
-      if m7:
-        markup += m7.group(1) + "<parameter>" + m7.group(2) + "()</parameter>\n"
-        offset = len(m7.group(0))
-      elif m8:
+      if ($text =~ /^(\A|[^\\])\@(\w+((\.|->)\w+)*)\s*\(\)/) {
+        $markup .= $1 . "<parameter>" . $2 . "()</parameter>\n";
+        $offset = length ($&);
+      } elsif ($text =~ /^(\A|[^\\])\@(\w+((\.|->)\w+)*)/) {
         # Convert '@param', but not '\@param'.
-        markup += m8.group(1) + "<parameter>" + m8.group(2) + "</parameter>\n"
-        offset = len(m8.group(0))
-      elif m9:
-        markup += r"\@"
-        offset = len(m9.group(0))
-      else:
-        markup += "@"
-        offset = 1
-
-    elif closest_marker == "#":
-      m10 = re.search(r'^(\A|[^\\])#([\w\-:\.]+[\w]+)\s*\(\)', text)
-      m11 = re.search(r'^(\A|[^\\])#([\w\-:\.]+[\w]+)', text)
-      m12 = re.search(r'^\\#', text)
-      if m10:
+        $markup .= $1 . "<parameter>" . $2 . "</parameter>\n";
+        $offset = length ($&);
+      } elsif ($text =~ /^\\\@/) {
+        $markup .= "\@";
+        $offset = length ($&);
+      } else {
+        $markup .= "@";
+        $offset = 1;
+      }
+    } elsif ($closest_marker eq "#") {
+      if ($text =~ /^(\A|[^\\])#([\w\-:\.]+[\w]+)\s*\(\)/) {
         # handle #Object.func()
-        markup += m10.group(1) + MakeXRef(m10.group(2), tagify(m10.group(2) + "()", "function"))
-        offset = len(m10.group(0))
-      elif m11:
+        $markup .= $1 . &MakeXRef ($2, &tagify ($2 . "()", "function"));
+        $offset = length ($&);
+      } elsif ($text =~ /^(\A|[^\\])#([\w\-:\.]+[\w]+)/) {
         # Convert '#symbol', but not '\#symbol'.
-        markup += m11.group(1) + MakeHashXRef(m11.group(2), "type")
-        offset = len(m11.group(0))
-      elif m12:
-        markup += "#"
-        offset = len(m12.group(0))
-      else:
-        markup += "#"
-        offset = 1
-
-    elif closest_marker == "%":
-      m12 = re.search(r'^(\A|[^\\])\%(-?\w+)', text)
-      m13 = re.search(r'^\\%', text)
-      if m12:
+        $markup .= $1 . &MakeHashXRef ($2, "type");
+        $offset = length ($&);
+      } elsif ($text =~ /^\\#/) {
+        $markup .= "#";
+        $offset = length ($&);
+      } else {
+        $markup .= "#";
+        $offset = 1;
+      }
+    } elsif ($closest_marker eq "%") {
+      if ($text =~ /^(\A|[^\\])\%(-?\w+)/) {
         # Convert '%constant', but not '\%constant'.
         # Also allow negative numbers, e.g. %-1.
-        markup += m12.group(1) + MakeXRef(m12.group(2), tagify(m12.group(2), "literal"))
-        offset = len(m12.group(0))
-      elif m13:
-        markup += r"\%"
-        offset = len(m13.group(0))
-      else:
-        markup += "%"
-        offset = 1
-
-
-
-    if offset > 0:
-      text = text[offset:]
-
-  return markup
-
-
-def MarkDownParseSpanElements(text):
-    markers = ["\\", "<", "![", "[", "`", "%", "#", "@"]
-
-    text = MarkDownParseSpanElementsInner(text, markers)
-
-    # Convert 'function()' or 'macro()'.
-    # if there is abc_*_def() we don't want to make a link to _def()
-    # FIXME: also handle abc(def(....)) : but that would need to be done recursively :/
-    def f(m):
-        return m.group(1) + MakeXRef(m.group(2), tagify(m.group(2) + "()", "function")) + ';'
-    text = re.sub(r'([^\*.\w])(\w+)\s*\(\)', f, text)
-    return text
-
-
-def ReplaceEntities(text, symbol):
-    entities = [["&lt;", "<"],
-                ["&gt;", ">"],
-                ["&ast;", "*"],
-                ["&num;", "#"],
-                ["&percnt;", "%"],
-                ["&colon;", ":"],
-                ["&quot;", '"'],
-                ["&apos;", "'"],
-                ["&nbsp;", " "],
-                ["&amp;", "&"], # Do this last, or the others get messed up.
-               ]
-
-
-    # Expand entities in <programlisting> even inside CDATA since
-    # we changed the definition of |[ to add CDATA
-    for i in entities:
-        text = re.sub(i[0], i[1], text)
-    return text
-
-
-def MarkDownOutputDocBook(blocksref, symbol, context):
-  output = ''
-  blocks = blocksref
-
-  for block in blocks:
-    #$output += "\n<!-- beg type='" . $block->{"type"} . "'-->\n"
-
-    if block["type"] == "paragraph":
-      text = MarkDownParseSpanElements(block["text"])
-      if context == "li" and output == '':
-        if block["interrupted"]:
-          output += "\n<para>%s</para>\n" % text
-        else:
-          output += "<para>%s</para>" % text
-          if len(blocks) > 0:
-            output += "\n"
-      else:
-        output += "<para>%s</para>\n" % text
-
-    elif block["type"] == "heading":
-
-      title = MarkDownParseSpanElements(block["text"])
-
-      if block["level"] == 1:
-        tag = "refsect2"
-      else:
-        tag = "refsect3"
-
-
-      text = MarkDownParseLines(block["lines"], symbol, "heading")
-      if id in block:
-        output += "<%s id=\"%s\">" % (tag, block["id"])
-      else:
-        output += "<%s>" % tag
-
-
-      output += "<title>%s</title>%s</%s>\n" % (title, text, tag)
-    elif block["type"] == "li":
-      tag = "itemizedlist"
-
-      if block["first"]:
-        if block["ordered"]:
-          tag = "orderedlist"
-
-        output += "<%s>\n" % tag
-
-
-      if block["interrupted"]:
-        block["lines"].append('')
-
-
-      text = MarkDownParseLines(block["lines"], symbol, "li")
-      output += "<listitem>" + text + "</listitem>\n"
-      if block["last"]:
-        if block["ordered"]:
-          tag = "orderedlist"
-        output += "</$tag>\n"
-
-    elif block["type"] == "quote":
-      text = MarkDownParseLines(block["lines"], symbol, "quote")
-      output += "<blockquote>\n%s</blockquote>\n" % text
-    elif block["type"] == "code":
-      tag = "programlisting"
-
-      if block["language"]:
-        if block["language"] == "plain":
-          output += "<informalexample><screen><![CDATA[\n"
-          tag = "screen"
-        else:
-          output += '<informalexample><programlisting language="' + block['language'] + '"><![CDATA[\n'
-
-      else:
-        output += "<informalexample><programlisting><![CDATA[\n"
+        $markup .= $1 . &MakeXRef ($2, &tagify ($2, "literal"));
+        $offset = length ($&);
+      } elsif ($text =~ /^\\%/) {
+        $markup .= "\%";
+        $offset = length ($&);
+      } else {
+        $markup .= "%";
+        $offset = 1;
+      }
+    }
+
+    if ($offset > 0) {
+      $text = substr ($text, $offset);
+    }
+  }
+
+  return $markup;
+}
 
-      for line in block["lines"]:
-        output += ReplaceEntities(line, symbol) + "\n"
+sub MarkDownParseSpanElements {
+  my ($text) = @_;
+  my @markers = ( "\\", "<", "![", "[", "`", "%", "#", "@" );
 
-      output += "]]></$tag></informalexample>\n"
-    elif block["type"] == "markup":
-      text = ExpandAbbreviations(symbol, block["text"])
-      output += text+"\n"
-    else:
-      output += block["text"]+"\n"
+  $text = &MarkDownParseSpanElementsInner ($text, \@markers);
 
-    #$output += "\n<!-- end type='" . $block->{"type"} . "'-->\n"
+  # Convert 'function()' or 'macro()'.
+  # if there is abc_*_def() we don't want to make a link to _def()
+  # FIXME: also handle abc(def(....)) : but that would need to be done recursively :/
+  $text =~ s/([^\*.\w])(\w+)\s*\(\)/$1.&MakeXRef($2, &tagify($2 . "()", "function"));/eg;
 
-  return output
+  return $text;
+}
 
+sub ReplaceEntities {
+  my ($text, $symbol) = @_;
+  my $warn = "";
+  my @entities = ( [ "&lt;", "<" ],
+                   [ "&gt;", ">" ],
+                   [ "&ast;", "*" ],
+                   [ "&num;", "#" ],
+                   [ "&percnt;", "%"],
+                   [ "&colon;", ":" ],
+                   [ "&quot;", "\"" ],
+                   [ "&apos;", "'" ],
+                   [ "&nbsp;", " " ],
+                   [ "&amp;", "&" ] ); # Do this last, or the others get messed up.
+  my $i;
+
+  # Expand entities in <programlisting> even inside CDATA since
+  # we changed the definition of |[ to add CDATA
+  for ($i = 0; $i <= $#entities; $i++) {
+    $text =~ s/$entities[$i][0]/$entities[$i][1]/g;
+  }
+
+  return $text;
+}
 
-def MarkDownParseLines(linesref, symbol, context):
-    lines = linesref
+sub MarkDownOutputDocBook {
+  my ($blocksref, $symbol, $context) = @_;
+  my $output = "";
+  my $block;
+  my @blocks = @$blocksref;
+
+  foreach $block (@blocks) {
+    my $text;
+    my $title;
+
+    #$output .= "\n<!-- beg type='" . $block->{"type"} . "'-->\n";
+
+    if ($block->{"type"} eq "paragraph") {
+      $text = &MarkDownParseSpanElements ($block->{"text"});
+      if ($context eq "li" && $output eq "") {
+        if ($block->{"interrupted"}) {
+          $output .= "\n<para>$text</para>\n";
+        } else {
+          $output .= "<para>$text</para>";
+          if ($#blocks > 0) {
+            $output .= "\n";
+          }
+        }
+      } else {
+        $output .= "<para>$text</para>\n";
+      }
+
+    } elsif ($block->{"type"} eq "heading") {
+      my $tag;
+
+      $title = &MarkDownParseSpanElements ($block->{"text"});
+
+      if ($block->{"level"} == 1) {
+        $tag = "refsect2";
+      } else {
+        $tag = "refsect3";
+      }
+
+      $text = &MarkDownParseLines ($block->{"lines"}, $symbol, "heading");
+      if (defined ($block->{"id"})) {
+        $output .= "<$tag id=\"" . $block->{"id"} . "\">";
+      } else {
+        $output .= "<$tag>";
+      }
+
+      $output .= "<title>$title</title>$text</$tag>\n";
+    } elsif ($block->{"type"} eq "li") {
+      my $tag = "itemizedlist";
+
+      if ($block->{"first"}) {
+        if ($block->{"ordered"}) {
+          $tag = "orderedlist";
+        }
+        $output .= "<$tag>\n";
+      }
+
+      if ($block->{"interrupted"}) {
+        push @{$block->{"lines"}}, "";
+      }
+
+      $text = &MarkDownParseLines ($block->{"lines"}, $symbol, "li");
+      $output .= "<listitem>".$text."</listitem>\n";
+      if ($block->{"last"}) {
+        if ($block->{"ordered"}) {
+          $tag = "orderedlist";
+        }
+        $output .= "</$tag>\n";
+      }
+    } elsif ($block->{"type"} eq "quote") {
+      $text = &MarkDownParseLines ($block->{"lines"}, $symbol, "quote");
+      $output .= "<blockquote>\n$text</blockquote>\n";
+    } elsif ($block->{"type"} eq "code") {
+      my $tag = "programlisting";
+
+      if ($block->{"language"}) {
+        if ($block->{"language"} eq "plain") {
+          $output .= "<informalexample><screen><![CDATA[\n";
+          $tag = "screen";
+        } else {
+          $output .= "<informalexample><programlisting language=\"" . $block->{"language"} . 
"\"><![CDATA[\n";
+        }
+      } else {
+        $output .= "<informalexample><programlisting><![CDATA[\n";
+      }
+      foreach (@{$block->{"lines"}}) {
+        $output .= &ReplaceEntities ($_, $symbol) . "\n";
+      }
+      $output .= "]]></$tag></informalexample>\n";
+    } elsif ($block->{"type"} eq "markup") {
+      $text = &ExpandAbbreviations($symbol, $block->{"text"});
+      $output .= $text."\n";
+    } else {
+      $output .= $block->{"text"}."\n";
+    }
+    #$output .= "\n<!-- end type='" . $block->{"type"} . "'-->\n";
+  }
+
+  return $output;
+}
 
-    blocks = MarkDownParseBlocks(lines, symbol, context)
-    output = MarkDownOutputDocBook(blocks, symbol, context)
+sub MarkDownParseLines {
+  my ($linesref, $symbol, $context) = @_;
+  my $output;
+  my @lines = @$linesref;
+  my @blocks;
 
-    return output
+  @blocks = &MarkDownParseBlocks (\@lines, $symbol, $context);
+  $output = &MarkDownOutputDocBook (\@blocks, $symbol, $context);
 
+  return $output;
+}
 
-def MarkDownParse(text, symbol):
-    # take out some variability in line endings
-    text = re.sub(r'\r\n', '\n', text)
-    text = re.sub(r'\r', '\n', text)
+sub MarkDownParse {
+  my ($text, $symbol) = @_;
+  my @lines;
 
-    # split lines
-    lines = text.split('\n')
-    text = MarkDownParseLines(lines, symbol, '')
+  # take out some variability in line endings
+  $text =~ s%\r\n%\n%g;
+  $text =~ s%\r%\n%g;
 
-    return text
+  # split lines
+  @lines = split("\n", $text);
+  $text = MarkDownParseLines(\@lines, $symbol, "");
 
+  return $text;
+}
 
 #############################################################################
 # Function    : ReadDeclarationsFile
@@ -5314,102 +5734,102 @@ def MarkDownParse(text, symbol):
 #                        any current declaration.
 #############################################################################
 
-def ReadDeclarationsFile(ifile, override):
-
-    if override == 0:
-        global Declarations, DeclarationTypes, DeclarationConditional, DeclarationOutput
-        Declarations = {}
-        DeclarationTypes = {}
-        DeclarationConditional = {}
-        DeclarationOutput = {}
-
-
-    INPUT = open(ifile)
-    declaration_type = ''
-    declaration_name = None
-    declaration = None
-    is_deprecated = 0
-    line_number = 0
-    for line in INPUT:
-        line_number += 1
-        if not declaration_type:
-            m1 = re.search(r'^<([^>]+)>', line)
-            if m1:
-                declaration_type = m1.group(1)
-                declaration_name = ''
-                logging.info("Found declaration: %s", declaration_type)
-                declaration = ''
-
-        else:
-            m2 = re.search(r'^<NAME>(.*)</NAME>', line)
-            m3 = re.search(r'^<DEPRECATED/>', line)
-            m4 = re.search(r'^</$declaration_type>', line)
-            if m2:
-                declaration_name = m2.group(1)
-            elif m3:
-                is_deprecated = True
-            elif m4:
-                logging.info("Found end of declaration: %s", declaration_name)
+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;
+    my $is_deprecated = 0;
+    while (<INPUT>) {
+        if (!$declaration_type) {
+            if (m/^<([^>]+)>/) {
+                $declaration_type = $1;
+                $declaration_name = "";
+                @TRACE@("Found declaration: $declaration_type\n");
+                $declaration = "";
+            }
+        } else {
+            if (m%^<NAME>(.*)</NAME>%) {
+                $declaration_name = $1;
+            } elsif (m%^<DEPRECATED/>%) {
+                $is_deprecated = 1;
+            } elsif (m%^</$declaration_type>%) {
+                @TRACE@("Found end of declaration: $declaration_name\n");
                 # Check that the declaration has a name
-                if declaration_name == '':
-                    common.LogWarning(ifile, line_number, declaration_type + " has no name.\n")
-
+                if ($declaration_name eq "") {
+                    &LogWarning ($file, $., "$declaration_type has no name.\n");
+                }
 
                 # If the declaration is an empty typedef struct _XXX XXX
                 # set the flag to indicate the struct has a typedef.
-                if declaration_type == 'STRUCT' or declaration_type == 'UNION' \
-                    and re.search(r'^\s*$', declaration):
-                    logging.info("Struct has typedef: " + declaration_name)
-                    StructHasTypedef[declaration_name] = 1
-
+                if (($declaration_type eq 'STRUCT' || $declaration_type eq 'UNION')
+                    && $declaration =~ m/^\s*$/) {
+                    @TRACE@("Struct has typedef: $declaration_name\n");
+                    $StructHasTypedef{$declaration_name} = 1;
+                }
 
                 # Check if the symbol is already defined.
-                if declaration_name in Declarations and override == 0:
+                if (defined ($Declarations{$declaration_name})
+                    && $override == 0) {
                     # Function declarations take precedence.
-                    if DeclarationTypes[declaration_name] == 'FUNCTION':
+                    if ($DeclarationTypes{$declaration_name} eq 'FUNCTION') {
                         # Ignore it.
-                        pass
-                    elif declaration_type == 'FUNCTION':
-                        if is_deprecated:
-                            Deprecated[declaration_name] = ''
-
-                        Declarations[declaration_name] = declaration
-                        DeclarationTypes[declaration_name] = declaration_type
-                    elif DeclarationTypes[declaration_name] == declaration_type:
+                    } elsif ($declaration_type eq 'FUNCTION') {
+                        if ($is_deprecated) {
+                            $Deprecated{$declaration_name} = "";
+                        }
+                        $Declarations{$declaration_name} = $declaration;
+                        $DeclarationTypes{$declaration_name} = $declaration_type;
+                    } elsif ($DeclarationTypes{$declaration_name}
+                              eq $declaration_type) {
                         # If the existing declaration is empty, or is just a
                         # forward declaration of a struct, override it.
-                        if declaration_type == 'STRUCT' or declaration_type == 'UNION':
-                            if re.search(r'^\s*((struct|union)\s+\w+\s*;)?\s*$', 
Declarations[declaration_name]):
-                                if is_deprecated:
-                                    Deprecated[declaration_name] = ''
-                                Declarations[declaration_name] = declaration
-                            elif re.search(r'^\s*((struct|union)\s+\w+\s*;)?\s*$', declaration):
+                        if ($declaration_type eq 'STRUCT' || $declaration_type eq 'UNION') {
+                            if ($Declarations{$declaration_name} =~ m/^\s*((struct|union)\s+\w+\s*;)?\s*$/) {
+                                if ($is_deprecated) {
+                                    $Deprecated{$declaration_name} = "";
+                                }
+                                $Declarations{$declaration_name} = $declaration;
+                            } elsif ($declaration =~ m/^\s*((struct|union)\s+\w+\s*;)?\s*$/) {
                                 # Ignore an empty or forward declaration.
-                                pass
-                            else:
-                                common.LogWarning(ifile, line_number, "Structure %s has multiple 
definitions." % declaration_name)
-
-                        else:
+                            } else {
+                                &LogWarning ($file, $., "Structure $declaration_name has multiple 
definitions.");
+                            }
+                        } else {
                             # set flag in %DeclarationConditional hash for
                             # multiply defined macros/typedefs.
-                            DeclarationConditional[declaration_name] = 1
-
-                    else:
-                        common.LogWarning(ifile, line_number, declaration_name + " has multiple 
definitions.")
-
-                else:
-                    if is_deprecated:
-                        Deprecated[declaration_name] = ''
-
-                    Declarations[declaration_name] = declaration
-                    DeclarationTypes[declaration_name] = declaration_type
-
-
-                declaration_type = ''
-                is_deprecated = False
-            else:
-                declaration += line
-    INPUT.close()
+                            $DeclarationConditional{$declaration_name} = 1;
+                        }
+                    } else {
+                        &LogWarning ($file, $., "$declaration_name has multiple definitions.");
+                    }
+                } else {
+                    if ($is_deprecated) {
+                        $Deprecated{$declaration_name} = "";
+                    }
+                    $Declarations{$declaration_name} = $declaration;
+                    $DeclarationTypes{$declaration_name} = $declaration_type;
+                }
+
+                $declaration_type = "";
+                $is_deprecated = 0;
+            } else {
+                $declaration .= $_;
+            }
+        }
+    }
+    close (INPUT);
+}
 
 
 #############################################################################
@@ -5425,68 +5845,68 @@ def ReadDeclarationsFile(ifile, override):
 #                        information.
 #############################################################################
 
-def ReadSignalsFile(ifile):
+sub ReadSignalsFile {
+    my ($file) = @_;
 
-    in_signal = 0
-    signal_object = None
-    signal_name = None
-    signal_returns = None
-    signal_flags = None
-    signal_prototype = None
+    my $in_signal = 0;
+    my $signal_object;
+    my $signal_name;
+    my $signal_returns;
+    my $signal_flags;
+    my $signal_prototype;
 
     # Reset the signal info.
-    global SignalObjects, SignalNames, SignalReturns, SignalFlags, SignalPrototypes
-    SignalObjects = []
-    SignalNames = []
-    SignalReturns = []
-    SignalFlags = []
-    SignalPrototypes = []
-
-    if not os.path.isfile(ifile):
-        return
-
-    INPUT = open(ifile)
-    line_number = 0
-    for line in INPUT:
-        line_number += 1
-        if not in_signal:
-            if re.search(r'^<SIGNAL>', line):
-                in_signal = 1
-                signal_object = ''
-                signal_name = ''
-                signal_returns = ''
-                signal_prototype = ''
-
-        else:
-            m = re.search(r'^<NAME>(.*)<\/NAME>', line)
-            m2 = re.search(r'^<RETURNS>(.*)<\/RETURNS>', line)
-            m3 = re.search(r'^<FLAGS>(.*)<\/FLAGS>', line)
-            if m:
-                signal_name = m.group(1)
-                m1_2 = re.search(r'^(.*)::(.*)$', signal_name)
-                if m1_2:
-                    signal_object = m1_2.group(1)
-                    signal_name = m1_2.group(2).replace('_', '-')
-                    logging.info("Found signal: %s", signal_name)
-                else:
-                    common.LogWarning(ifile, line_number, "Invalid signal name: %s." % signal_name)
-
-            elif m2:
-                signal_returns = m2.group(1)
-            elif m3:
-                signal_flags = m3.group(1)
-            elif re.search(r'^</SIGNAL>', line):
-                logging.info("Found end of signal: %s::%s\nReturns: %s\n%s", signal_object, signal_name, 
signal_returns, signal_prototype)
-                SignalObjects.append(signal_object)
-                SignalNames.append(signal_name)
-                SignalReturns.append(signal_returns)
-                SignalFlags.append(signal_flags)
-                SignalPrototypes.append(signal_prototype)
-                in_signal = False
-            else:
-                signal_prototype += line
-    INPUT.close()
-
+    @SignalObjects = ();
+    @SignalNames = ();
+    @SignalReturns = ();
+    @SignalFlags = ();
+    @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) =~ s/_/-/g;
+                    @TRACE@("Found signal: $signal_name\n");
+                } else {
+                    &LogWarning ($file, $., "Invalid signal name: $signal_name.");
+                }
+            } elsif (m/^<RETURNS>(.*)<\/RETURNS>/) {
+                $signal_returns = $1;
+            } elsif (m/^<FLAGS>(.*)<\/FLAGS>/) {
+                $signal_flags = $1;
+            } elsif (m%^</SIGNAL>%) {
+                @TRACE@("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 (@SignalFlags, $signal_flags);
+                push (@SignalPrototypes, $signal_prototype);
+                $in_signal = 0;
+            } else {
+                $signal_prototype .= $_;
+            }
+        }
+    }
+    close (INPUT);
+}
 
 
 #############################################################################
@@ -5501,173 +5921,179 @@ def ReadSignalsFile(ifile):
 #                 skipped.
 #############################################################################
 
-def ReadTemplateFile(docsfile, skip_unused_params):
-
-    template = docsfile + ".sgml"
-    if not os.path.isfile(template):
-        logging.info("File doesn't exist: " + template)
-        return 0
+sub ReadTemplateFile {
+    my ($docsfile, $skip_unused_params) = @_;
 
+    my $template = "$docsfile.sgml";
+    if (! -f $template) {
+        @TRACE@("File doesn't exist: $template\n");
+        return 0;
+    }
 
     # start with empty hashes, we merge the source comment for each file
     # afterwards
-    global SymbolDocs, SymbolTypes, SymbolParams
-    SymbolDocs = {}
-    SymbolTypes = {}
-    SymbolParams = {}
-
-    current_type = ''        # Type of symbol being read.
-    current_symbol = ''        # Name of symbol being read.
-    symbol_doc = ''                # Description of symbol being read.
-    params = []                        # Parameter names and descriptions of current
+    %SymbolDocs = ();
+    %SymbolTypes = ();
+    %SymbolParams = ();
+
+    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.
-    current_param = -1        # Index of parameter currently being read.
+    my $current_param = -1;        # Index of parameter currently being read.
                                 #   Note that the param array contains pairs
                                 #   of param name & description.
-    in_unused_params = 0        # True if we are reading in the unused params.
-    in_deprecated = 0
-    in_since = 0
-    in_stability = 0
-
-    DOCS = open(template)
-
-    logging.info("reading template " + template)
-
-    line_number = 0
-    for line in DOCS:
-        line_number += 1
-        m1 = re.search(r'^<!-- ##### ([A-Z_]+) (\S+) ##### -->', line)
-        if m1:
-            stype = m1.group(1)
-            symbol = m1.group(2)
-            if symbol == "Title" \
-                or symbol == "Short_Description" \
-                or symbol == "Long_Description" \
-                or symbol == "See_Also" \
-                or symbol == "Stability_Level" \
-                or symbol == "Include" \
-                or symbol == "Image":
-
-                symbol = docsfile + ":" + symbol
-
-
-            logging.info("Found symbol: " + symbol)
+    my $in_unused_params = 0;        # True if we are reading in the unused params.
+    my $in_deprecated = 0;
+    my $in_since = 0;
+    my $in_stability = 0;
+
+    open (DOCS, "$template")
+        || die "Can't open $template: $!";
+
+    @TRACE@("reading template $template");
+
+    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 eq "Stability_Level"
+                || $symbol eq "Include"
+                || $symbol eq "Image") {
+
+                $symbol = $docsfile . ":" . $symbol;
+            }
+
+            @TRACE@("Found symbol: $symbol\n");
             # Remember file and line for the symbol
-            SymbolSourceFile[symbol] = template
-            SymbolSourceLine[symbol] = line_number
+            $SymbolSourceFile{$symbol} = $template;
+            $SymbolSourceLine{$symbol} = $.;
 
             # Store previous symbol, but remove any trailing blank lines.
-            if current_symbol != '':
-                symbol_doc = symbol_doc.rstrip()
-                SymbolTypes[current_symbol] = current_type
-                SymbolDocs[current_symbol] = symbol_doc
+            if ($current_symbol ne "") {
+                $symbol_doc =~ s/\s+$//;
+                $SymbolTypes{$current_symbol} = $current_type;
+                $SymbolDocs{$current_symbol} = $symbol_doc;
 
                 # Check that the stability level is valid.
-                if StabilityLevel[current_symbol]:
-                    StabilityLevel[current_symbol] = ParseStabilityLevel(StabilityLevel[current_symbol], 
template, line_number, "Stability level for " + current_symbol)
+                if ($StabilityLevel{$current_symbol}) {
+                    $StabilityLevel{$current_symbol} = 
&ParseStabilityLevel($StabilityLevel{$current_symbol}, $template, $., "Stability level for $current_symbol");
+                }
 
-                if current_param >= 0:
-                    SymbolParams[current_symbol] = [params]
-                else:
+                if ($current_param >= 0) {
+                    $SymbolParams{$current_symbol} = [ @params ];
+                } else {
                     # Delete any existing params in case we are overriding a
                     # previously read template.
-                    del SymbolParams[current_symbol]
-
-
-            current_type = stype
-            current_symbol = symbol
-            current_param = -1
-            in_unused_params = 0
-            in_deprecated = 0
-            in_since = 0
-            in_stability = 0
-            symbol_doc = ''
-            params = []
-
-        elif re.search(r'^<!-- # Unused Parameters # -->', line):
-            logging.info("Found unused parameters\n")
-            in_unused_params = True
-            continue
-
-        elif in_unused_params and skip_unused_params:
+                    delete $SymbolParams{$current_symbol};
+                }
+            }
+            $current_type = $type;
+            $current_symbol = $symbol;
+            $current_param = -1;
+            $in_unused_params = 0;
+            $in_deprecated = 0;
+            $in_since = 0;
+            $in_stability = 0;
+            $symbol_doc = "";
+            @params = ();
+
+        } elsif (m/^<!-- # Unused Parameters # -->/) {
+            @TRACE@("Found unused parameters\n");
+            $in_unused_params = 1;
+            next;
+
+        } elsif ($in_unused_params && $skip_unused_params) {
             # When outputting the DocBook we skip unused parameters.
-            logging.info("Skipping unused param: " + line)
-            continue
+            @TRACE@("Skipping unused param: $_");
+            next;
 
-        else:
+        } else {
             # Check if param found. Need to handle "..." and "format...".
-            m2 = re.search(r'^\@([\w\.]+):\040?', line)
-            if m2:
-                line = re.sub(r'^\@([\w\.]+):\040?', '', line)
-                param_name = m2.group(1)
-                param_desc = line
+            if (s/^\@([\w\.]+):\040?//) {
+                my $param_name = $1;
+                my $param_desc = $_;
                 # Allow variations of 'Returns'
-                if re.search(r'^[Rr]eturns?$', param_name):
-                    param_name = "Returns"
-
+                if ($param_name =~ m/^[Rr]eturns?$/) {
+                    $param_name = "Returns";
+                }
                 # Allow varargs variations
-                if re.search(r'^.*\.\.\.$', param_name):
-                    param_name = "..."
-
+                if ($param_name =~ m/^.*\.\.\.$/) {
+                    $param_name = "...";
+                }
 
                 # strip trailing whitespaces and blank lines
-                line = re.sub(r'\s+\n$', '\n', line, flags=re.M)
-                line = re.sub(r'\n+$', '\n', line, flags=re.M|re.S)
-                logging.info("Found param for symbol %s : '%s'= '%s'", current_symbol, param_name, line)
-
-                if param_name == "Deprecated":
-                    in_deprecated = True
-                    Deprecated[current_symbol] = line
-                elif param_name == "Since":
-                    in_since = True
-                    Since[current_symbol] = line.strip()
-                elif param_name == "Stability":
-                    in_stability = True
-                    StabilityLevel[current_symbol] = line
-                else:
-                    params.append(param_name)
-                    params.append(param_desc)
-                    current_param += PARAM_FIELD_COUNT
-
-            else:
+                s/\s+\n$/\n/m;
+                s/\n+$/\n/sm;
+                @TRACE@("Found param for symbol $current_symbol : '$param_name'= '$_'");
+
+                if ($param_name eq "Deprecated") {
+                    $in_deprecated = 1;
+                    $Deprecated{$current_symbol} = $_;
+                } elsif ($param_name eq "Since") {
+                    $in_since = 1;
+                    chomp;
+                    $Since{$current_symbol} = $_;
+                } elsif ($param_name eq "Stability") {
+                    $in_stability = 1;
+                    $StabilityLevel{$current_symbol} = $_;
+                } else {
+                    push (@params, $param_name);
+                    push (@params, $param_desc);
+                    $current_param += $PARAM_FIELD_COUNT;
+                }
+            } else {
                 # strip trailing whitespaces and blank lines
-                line = re.sub(r'\s+\n$', '\n', line, flags=re.M)
-                line = re.sub(r'\n+$', '\n', line, flags=re.M|re.S)
-
-                if re.search(r'^\s+$', line):
-                    if in_deprecated:
-                        Deprecated[current_symbol] += line
-                    elif in_since:
-                        common.LogWarning(template, line_number, "multi-line since docs found")
-                        #$Since{$current_symbol} += $_
-                    elif in_stability:
-                        StabilityLevel[current_symbol] += line
-                    elif current_param >= 0:
-                        params[current_param] += line
-                    else:
-                        symbol_doc += line
+                s/\s+\n$/\n/m;
+                s/\n+$/\n/sm;
+
+                if (!m/^\s+$/) {
+                    if ($in_deprecated) {
+                        $Deprecated{$current_symbol} .= $_;
+                    } elsif ($in_since) {
+                        &LogWarning ($template, $., "multi-line since docs found");
+                        #$Since{$current_symbol} .= $_;
+                    } elsif ($in_stability) {
+                        $StabilityLevel{$current_symbol} .= $_;
+                    } elsif ($current_param >= 0) {
+                        $params[$current_param] .= $_;
+                    } else {
+                        $symbol_doc .= $_;
+                    }
+                }
+            }
+        }
+    }
 
     # Remember to finish the current symbol doccs.
-    if current_symbol != '':
+    if ($current_symbol ne "") {
 
-        symbol_doc = re.sub(r'\s+$', '', symbol_doc)
-        SymbolTypes[current_symbol] = current_type
-        SymbolDocs[current_symbol] = symbol_doc
+        $symbol_doc =~ s/\s+$//;
+        $SymbolTypes{$current_symbol} = $current_type;
+        $SymbolDocs{$current_symbol} = $symbol_doc;
 
         # Check that the stability level is valid.
-        if StabilityLevel[current_symbol]:
-            StabilityLevel[current_symbol] = ParseStabilityLevel(StabilityLevel[current_symbol], template, 
line_number, "Stability level for " + current_symbol)
+        if ($StabilityLevel{$current_symbol}) {
+            $StabilityLevel{$current_symbol} = &ParseStabilityLevel($StabilityLevel{$current_symbol}, 
$template, $., "Stability level for $current_symbol");
+        }
 
-        if current_param >= 0:
-            SymbolParams[current_symbol] = [params]
-        else:
+        if ($current_param >= 0) {
+            $SymbolParams{$current_symbol} = [ @params ];
+        } else {
             # Delete any existing params in case we are overriding a
             # previously read template.
-            del SymbolParams[current_symbol]
-
-    DOCS.close()
-    return 1
+            delete $SymbolParams{$current_symbol};
+        }
+    }
 
+    close (DOCS);
+    return 1;
+}
 
 
 #############################################################################
@@ -5684,79 +6110,78 @@ def ReadTemplateFile(docsfile, skip_unused_params):
 # Arguments   : none
 #############################################################################
 
-def ReadObjectHierarchy():
-
-    global Objects, ObjectLevels
-    Objects = []
-    ObjectLevels = []
+sub ReadObjectHierarchy {
+    @Objects = ();
+    @ObjectLevels = ();
 
-    if not os.path.isfile(OBJECT_TREE_FILE):
-        return
-
-    INPUT = open(OBJECT_TREE_FILE)
+    if (! -f $OBJECT_TREE_FILE) {
+        return;
+    }
+    if (!open (INPUT, $OBJECT_TREE_FILE)) {
+        warn "Can't open $OBJECT_TREE_FILE - skipping object tree\n";
+        return;
+    }
 
     # Only emit objects if they are supposed to be documented, or if
     # they have documented children. To implement this, we maintain a
     # stack of pending objects which will be emitted if a documented
     # child turns up.
-    pending_objects = []
-    pending_levels = []
-    root = None
-    tree = []
-    for line in INPUT:
-        m1 = re.search(r'\S+', line)
-        if m1:
-            gobject = m1.group(0)
-            level = len(line[0:m1.start()]) / 2 + 1
-            xref = ''
-
-            if level == 1:
-                root = gobject
-
-
-            while pending_levels and pending_levels[-1] >= level:
-                pending_objects.pop()
-                pending_levels.pop()
-
-
-            pending_objects.append(gobject)
-            pending_levels.append(level)
-
-            if gobject in KnownSymbols:
-                while len(pending_levels) > 0:
-                    gobject = pending_objects[0]
-                    pending_objects = pending_objects[1:]
-                    level = pending_levels[0]
-                    pending_levels = pending_levels[1:]
-                    xref = MakeXRef(gobject)
-
-                    tree.append(' ' * (level * 4) + xref)
-                    Objects.append(gobject)
-                    ObjectLevels.append(level)
-                    ObjectRoots[gobject] = root
-
-
-            #else
-            #    common.LogWarning($OBJECT_TREE_FILE, line_number, "unknown type $object")
-            #
-
-
-    INPUT.close()
+    my @pending_objects = ();
+    my @pending_levels = ();
+    my $root;
+    my @tree = ();
+    while (<INPUT>) {
+        if (m/\S+/) {
+            my $object = $&;
+            my $level = (length($`)) / 2 + 1;
+            my $xref = "";
+
+            if ($level == 1) {
+                $root = $object;
+            }
+
+            while (($#pending_levels >= 0) && ($pending_levels[$#pending_levels] >= $level)) {
+                my $pobject = pop(@pending_objects);
+                my $plevel = pop(@pending_levels);
+            }
+
+            push (@pending_objects, $object);
+            push (@pending_levels, $level);
+
+            if (exists($KnownSymbols{$object})) {
+                while ($#pending_levels >= 0) {
+                    $object = shift @pending_objects;
+                    $level = shift @pending_levels;
+                    $xref = &MakeXRef ($object);
+
+                    push (@tree, ' ' x ($level * 4) . "$xref");
+                    push (@Objects, $object);
+                    push (@ObjectLevels, $level);
+                    $ObjectRoots{$object} = $root;
+                }
+            }
+            #else {
+            #    LogWarning ($OBJECT_TREE_FILE, $., "unknown type $object");
+            #}
+        }
+    }
+    close (INPUT);
 
     # FIXME: use xml
-    # my $old_tree_index = "$DB_OUTPUT_DIR/tree_index.$xml"
-    old_tree_index = os.path.join(DB_OUTPUT_DIR, "tree_index.sgml")
-    new_tree_index = os.path.join(DB_OUTPUT_DIR, "tree_index.new")
-
-    OUTPUT = open(new_tree_index, 'w')
+    # my $old_tree_index = "$DB_OUTPUT_DIR/tree_index.$xml";
+    my $old_tree_index = "$DB_OUTPUT_DIR/tree_index.sgml";
+    my $new_tree_index = "$DB_OUTPUT_DIR/tree_index.new";
 
-    OUTPUT.write(MakeDocHeader("screen") + "\n<screen>\n" + AddTreeLineArt(tree) + "\n</screen>\n")
-    OUTPUT.close()
+    open (OUTPUT, ">$new_tree_index")
+        || die "Can't create $new_tree_index: $!";
 
-    common.UpdateFileIfChanged(old_tree_index, new_tree_index, 0)
+    print (OUTPUT &MakeDocHeader ("screen")."\n<screen>\n".&AddTreeLineArt(\@tree)."\n</screen>\n");
+    close (OUTPUT);
 
-    OutputObjectList()
+    &UpdateFileIfChanged ($old_tree_index, $new_tree_index, 0);
 
+    &OutputObjectList;
+}
 
 #############################################################################
 # Function    : ReadInterfaces
@@ -5765,35 +6190,38 @@ def ReadObjectHierarchy():
 # Arguments   : none
 #############################################################################
 
-def ReadInterfaces():
-    global Interfaces
-    Interfaces = {}
-
-    if not os.path.isfile(INTERFACES_FILE):
-        return
-
-    INPUT = open(INTERFACES_FILE)
-
-    for line in INPUT:
-        line = line.strip()
-        (gobject, ifaces) = line.split()
-        if gobject in KnownSymbols and KnownSymbols[gobject] == 1:
-            knownIfaces = []
-
-            # filter out private interfaces, but leave foreign interfaces
-            for iface in ifaces:
-                if iface not in KnownSymbols or KnownSymbols[iface] == 1:
-                    knownIfaces.append(iface)
-
-
-
-            Interfaces[gobject] = ' '.join(knownIfaces)
-            logging.info("Interfaces for %s: %s\n", gobject, Interfaces[gobject])
-        else:
-            logging.info("skipping interfaces for unknown symbol: %s", gobject)
-
-    INPUT.close()
-
+sub ReadInterfaces {
+    %Interfaces = ();
+
+    if (! -f $INTERFACES_FILE) {
+        return;
+    }
+    if (!open (INPUT, $INTERFACES_FILE)) {
+        warn "Can't open $INTERFACES_FILE - skipping interfaces\n";
+        return;
+    }
+
+    while (<INPUT>) {
+       chomp;
+       my ($object, @ifaces) = split;
+       if (exists($KnownSymbols{$object}) && $KnownSymbols{$object} == 1) {
+           my @knownIfaces = ();
+
+           # filter out private interfaces, but leave foreign interfaces
+           foreach my $iface (@ifaces) {
+               if (!exists($KnownSymbols{$iface}) || $KnownSymbols{$iface} == 1) {
+                   push (@knownIfaces, $iface);
+               }
+             }
+
+           $Interfaces{$object} = join(' ', @knownIfaces);
+           @TRACE@("Interfaces for $object: $Interfaces{$object}\n");
+       } else {
+         @TRACE@("skipping interfaces for unknown symbol: $object\n");
+       }
+    }
+    close (INPUT);
+}
 
 #############################################################################
 # Function    : ReadPrerequisites
@@ -5802,30 +6230,35 @@ def ReadInterfaces():
 # Arguments   : none
 #############################################################################
 
-def ReadPrerequisites():
-    global Prerequisites
-    Prerequisites = {}
-
-    if not os.path.isfile(PREREQUISITES_FILE):
-        return
-
-    INPUT = open(PREREQUISITES_FILE)
-
-    for line in INPUT:
-        line = line.strip()
-        (iface, prereqs) = line.split()
-        if iface in KnownSymbols and KnownSymbols[iface] == 1:
-            knownPrereqs = []
-
-            # filter out private prerequisites, but leave foreign prerequisites
-            for prereq in prereqs:
-                if prereq not in KnownSymbols or KnownSymbols[prereq] == 1:
-                    knownPrereqs.append(prereq)
-
-            Prerequisites[iface] = ' '.join(knownPrereqs)
-
-    INPUT.close()
-
+sub ReadPrerequisites {
+    %Prerequisites = ();
+
+    if (! -f $PREREQUISITES_FILE) {
+        return;
+    }
+    if (!open (INPUT, $PREREQUISITES_FILE)) {
+        warn "Can't open $PREREQUISITES_FILE - skipping prerequisites\n";
+        return;
+    }
+
+    while (<INPUT>) {
+       chomp;
+       my ($iface, @prereqs) = split;
+       if (exists($KnownSymbols{$iface}) && $KnownSymbols{$iface} == 1) {
+           my @knownPrereqs = ();
+
+           # filter out private prerequisites, but leave foreign prerequisites
+           foreach my $prereq (@prereqs) {
+               if (!exists($KnownSymbols{$prereq}) || $KnownSymbols{$prereq} == 1) {
+                  push (@knownPrereqs, $prereq);
+               }
+           }
+
+           $Prerequisites{$iface} = join(' ', @knownPrereqs);
+       }
+    }
+    close (INPUT);
+}
 
 #############################################################################
 # Function    : ReadArgsFile
@@ -5836,95 +6269,91 @@ def ReadPrerequisites():
 # Arguments   : $file - the file containing the arg information.
 #############################################################################
 
-def ReadArgsFile(ifile):
-    in_arg = False
-    arg_object = None
-    arg_name = None
-    arg_type = None
-    arg_flags = None
-    arg_nick = None
-    arg_blurb = None
-    arg_default = None
-    arg_range = None
+sub ReadArgsFile {
+    my ($file) = @_;
 
-    # Reset the args info.
-    global ArgObjects, ArgNames, ArgTypes, ArgFlags, ArgNicks, ArgBlurbs, ArgDefaults, ArgRanges
-    ArgObjects = []
-    ArgNames = []
-    ArgTypes = []
-    ArgFlags = []
-    ArgNicks = []
-    ArgBlurbs = []
-    ArgDefaults = []
-    ArgRanges = []
-
-    if not os.path.isfile(ifile):
-        return
-
-    INPUT = open(ifile)
-    line_number = 0
-    for line in INPUT:
-        line_number += 1
-        if not in_arg:
-            if re.search(r'^<ARG>', line):
-                in_arg = True
-                arg_object = ''
-                arg_name = ''
-                arg_type = ''
-                arg_flags = ''
-                arg_nick = ''
-                arg_blurb = ''
-                arg_default = ''
-                arg_range = ''
-
-        else:
-            m1 = re.search(r'^<NAME>(.*)<\/NAME>', line)
-            m2 = re.search(r'^<TYPE>(.*)<\/TYPE>', line)
-            m3 = re.search(r'^<RANGE>(.*)<\/RANGE>', line)
-            m4 = re.search(r'^<FLAGS>(.*)<\/FLAGS>', line)
-            m5 = re.search(r'^<NICK>(.*)<\/NICK>', line)
-            m6 = re.search(r'^<BLURB>(.*)<\/BLURB>', line)
-            m7 = re.search(r'^<DEFAULT>(.*)<\/DEFAULT>', line)
-            if m1:
-                arg_name = m1.group(1)
-                m1_1 = re.search(r'^(.*)::(.*)$', arg_name)
-                if m1_1:
-                    arg_object = m1_1.group(1)
-                    arg_name = m1_1.group(2).replace('_', '-')
-                    logging.info("Found arg: %s", arg_name)
-                else:
-                    common.LogWarning(ifile, line_number, "Invalid argument name: " + arg_name)
-
-            elif m2:
-                arg_type = m2.group(1)
-            elif m3:
-                arg_range = m3.group(1)
-            elif m4:
-                arg_flags = m4.group(1)
-            elif m5:
-                arg_nick = m5.group(1)
-            elif m6:
-                arg_blurb = m6.group(1)
-                if arg_blurb == "(null)":
-                    arg_blurb = ''
-                    common.LogWarning(ifile, line_number, "Property %s:%s has no documentation." % 
(arg_object, arg_name))
-
-            elif m7:
-                arg_default = m7.group(1)
-            elif re.search(r'^</ARG>', line):
-                logging.info("Found end of arg: %s::%s\n%s : %s\n", arg_object, arg_name, arg_type, 
arg_flags)
-                ArgObjects.append(arg_object)
-                ArgNames.append(arg_name)
-                ArgTypes.append(arg_type)
-                ArgRanges.append(arg_range)
-                ArgFlags.append(arg_flags)
-                ArgNicks.append(arg_nick)
-                ArgBlurbs.append(arg_blurb)
-                ArgDefaults.append(arg_default)
-                in_arg = False
-
-    INPUT.close()
+    my $in_arg = 0;
+    my $arg_object;
+    my $arg_name;
+    my $arg_type;
+    my $arg_flags;
+    my $arg_nick;
+    my $arg_blurb;
+    my $arg_default;
+    my $arg_range;
 
+    # Reset the args info.
+    @ArgObjects = ();
+    @ArgNames = ();
+    @ArgTypes = ();
+    @ArgFlags = ();
+    @ArgNicks = ();
+    @ArgBlurbs = ();
+    @ArgDefaults = ();
+    @ArgRanges = ();
+
+    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 = "";
+                $arg_nick = "";
+                $arg_blurb = "";
+                $arg_default = "";
+                $arg_range = "";
+            }
+        } else {
+            if (m/^<NAME>(.*)<\/NAME>/) {
+                $arg_name = $1;
+                if ($arg_name =~ m/^(.*)::(.*)$/) {
+                    $arg_object = $1;
+                    ($arg_name = $2) =~ s/_/-/g;
+                    @TRACE@("Found arg: $arg_name\n");
+                } else {
+                    &LogWarning ($file, $., "Invalid argument name: $arg_name");
+                }
+            } elsif (m/^<TYPE>(.*)<\/TYPE>/) {
+                $arg_type = $1;
+            } elsif (m/^<RANGE>(.*)<\/RANGE>/) {
+                $arg_range = $1;
+            } elsif (m/^<FLAGS>(.*)<\/FLAGS>/) {
+                $arg_flags = $1;
+            } elsif (m/^<NICK>(.*)<\/NICK>/) {
+                $arg_nick = $1;
+            } elsif (m/^<BLURB>(.*)<\/BLURB>/) {
+                $arg_blurb = $1;
+                if ($arg_blurb eq "(null)") {
+                  $arg_blurb = "";
+                  &LogWarning ($file, $., "Property ${arg_object}:${arg_name} has no documentation.");
+                }
+            } elsif (m/^<DEFAULT>(.*)<\/DEFAULT>/) {
+                $arg_default = $1;
+            } elsif (m%^</ARG>%) {
+                @TRACE@("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 (@ArgRanges, $arg_range);
+                push (@ArgFlags, $arg_flags);
+                push (@ArgNicks, $arg_nick);
+                push (@ArgBlurbs, $arg_blurb);
+                push (@ArgDefaults, $arg_default);
+                $in_arg = 0;
+            }
+        }
+    }
+    close (INPUT);
+}
 
 #############################################################################
 # Function    : AddTreeLineArt
@@ -5933,37 +6362,41 @@ def ReadArgsFile(ifile):
 # Arguments   : @tree - array of indented strings.
 #############################################################################
 
-def AddTreeLineArt(tree):
-    # iterate bottom up over the tree
-    for i in range(len(tree) - 1, -1, -1):
-        # count leading spaces
-        m = re.search(r'^([^<A-Za-z]*)', tree[i])
-        tree[i] = m.group(0)
-        indent = len(m.group(1))
-        # replace with ╰───, if place of ╰ is not space insert ├
-        if indent > 4:
-            if tree[i][indent-4] == " ":
-                tree[i] = tree[i][:indent-4] + "--- " + tree[i][indent:]
-            else:
-                tree[i] = tree[i][:indent-4] + "+-- " + tree[i][indent:]
-
-            # go lines up while space and insert |
-            j = i - 1
-            while j >= 0 and tree[j][indent-4] == ' ':
-                tree[j][indent] = '|'
-                j -= 1
-
-
-    res = "\n".join(tree)
-    # unicode chars for: ╰──
-    res = re.sub(r'---', '<phrase role=\"lineart\">&#9584;&#9472;&#9472;</phrase>', res)
-    # unicde chars for: ├──
-    res = re.sub(r'\+--', '<phrase role=\"lineart\">&#9500;&#9472;&#9472;</phrase>', res)
-    # unicode char for: │
-    res = re.sub(r'\|', '<phrase role=\"lineart\">&#9474;</phrase>', res)
-
-    return res
-
+sub AddTreeLineArt {
+  my @tree = @{$_[0]};
+  my $i;
+  my $j;
+  my $indent;
+
+  # iterate bottom up over the tree
+  for ($i = $#tree; $i >= 0; $i--) {
+    # count leading spaces
+    $tree[$i] =~ /^([^<A-Za-z]*)/;
+    $indent = length( $1 );
+    # replace with ╰───, if place of ╰ is not space insert ├
+    if ($indent > 4) {
+      if (substr($tree[$i],$indent-4,1) eq " ") {
+        substr($tree[$i],$indent-4,4) = "--- ";
+      } else {
+        substr($tree[$i],$indent-4,4) = "+-- ";
+      }
+      # go lines up while space and insert |
+      for ($j = $i - 1; ($j >= 0 && substr($tree[$j],$indent-4,1) eq ' '); $j--) {
+        substr($tree[$j],$indent-4,1) = '|';
+      }
+    }
+  }
+
+  my $res = join("\n", @tree);
+  # unicode chars for: ╰──
+  $res =~ s%---%<phrase role=\"lineart\">&#9584;&#9472;&#9472;</phrase>%g;
+  # unicde chars for: ├──
+  $res =~ s%\+--%<phrase role=\"lineart\">&#9500;&#9472;&#9472;</phrase>%g;
+  # unicode char for: │
+  $res =~ s%\|%<phrase role=\"lineart\">&#9474;</phrase>%g;
+
+  return $res;
+}
 
 
 #############################################################################
@@ -5975,12 +6408,13 @@ def AddTreeLineArt(tree):
 # Arguments   : $name - the name to check.
 #############################################################################
 
-def CheckIsObject(name):
-    root = ObjectRoots[name]
+sub CheckIsObject {
+    my ($name) = @_;
+    my $root = $ObjectRoots{$name};
     # Let GBoxed pass as an object here to get -struct appended to the id
     # and prevent conflicts with sections.
-    return root and root != 'GEnum' and root != 'GFlags'
-
+    return (defined($root) and $root ne 'GEnum' and $root ne 'GFlags');
+}
 
 
 #############################################################################
@@ -5989,10 +6423,11 @@ def CheckIsObject(name):
 # Arguments   : $str - the string to pad.
 #############################################################################
 
-def MakeReturnField(s):
-
-    return str + (' ' * (RETURN_TYPE_FIELD_WIDTH - len(s)))
+sub MakeReturnField {
+    my ($str) = @_;
 
+    return $str . (' ' x ($RETURN_TYPE_FIELD_WIDTH - length ($str)));
+}
 
 #############################################################################
 # Function    : GetSymbolSourceFile
@@ -6000,12 +6435,17 @@ def MakeReturnField(s):
 # Arguments   : $symbol - the symbol name
 #############################################################################
 
-def GetSymbolSourceFile(symbol):
-    if symbol in SourceSymbolSourceFile:
-        return SourceSymbolSourceFile[symbol]
-    if symbol in SymbolSourceFile:
-        return SymbolSourceFile[symbol]
-    return ''
+sub GetSymbolSourceFile {
+    my ($symbol) = @_;
+
+    if (defined($SourceSymbolSourceFile{$symbol})) {
+        return $SourceSymbolSourceFile{$symbol};
+    } elsif (defined($SymbolSourceFile{$symbol})) {
+        return $SymbolSourceFile{$symbol};
+    } else {
+        return "";
+    }
+}
 
 #############################################################################
 # Function    : GetSymbolSourceLine
@@ -6013,13 +6453,15 @@ def GetSymbolSourceFile(symbol):
 # Arguments   : $symbol - the symbol name
 #############################################################################
 
-def GetSymbolSourceLine(symbol):
-    if symbol in SourceSymbolSourceLine:
-        return SourceSymbolSourceLine[symbol]
-    if symbol in SymbolSourceLine[symbol]:
-        return SymbolSourceLine[symbol]
-    return 0
+sub GetSymbolSourceLine {
+    my ($symbol) = @_;
 
+    if (defined($SourceSymbolSourceLine{$symbol})) {
+        return $SourceSymbolSourceLine{$symbol};
+    } elsif (defined($SymbolSourceLine{$symbol})) {
+        return $SymbolSourceLine{$symbol};
+    } else {
+        return 0;
+    }
+}
 
-if __name__ == '__main__':
-    Run()
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 44e1a54..fea2c88 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -5,7 +5,7 @@ SUBDIRS = gobject bugs annotations fail empty program .
 if BUILD_TESTS
 
 TESTS = \
-  gtkdoc-common.t \
+  gtkdoc-common.t gtkdoc-mkdb.t \
   gtkdoc-check.py gtkdoc-common.py \
   tools.sh gobject.sh bugs.sh annotations.sh fail.sh empty.sh sanity.sh \
   program.sh
diff --git a/tests/gtkdoc-mkdb.t b/tests/gtkdoc-mkdb.t
new file mode 100755
index 0000000..0a135af
--- /dev/null
+++ b/tests/gtkdoc-mkdb.t
@@ -0,0 +1,30 @@
+#!/usr/bin/env perl
+# -*- cperl -*-
+#
+# gtk-doc - GTK DocBook documentation generator.
+# Copyright (C) 2015  Stefan Sauer
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+use diagnostics;
+use warnings;
+use strict;
+use Test::More;
+
+require_ok ("gtkdoc-mkdb");
+
+done_testing();
+
diff --git a/tests/tools.sh.in b/tests/tools.sh.in
index ac930e4..309de0b 100644
--- a/tests/tools.sh.in
+++ b/tests/tools.sh.in
@@ -10,7 +10,7 @@ echo "Running suite(s): gtk-doc-$suite";
 # we can use which here as we override the path in TEST_ENVIRONMENT
 
 # test perl scripts
-for file in gtkdoc-check gtkdoc-fixxref gtkdoc-scangobj ; do
+for file in gtkdoc-check gtkdoc-fixxref gtkdoc-mkdb gtkdoc-scangobj ; do
   @PERL@ -cwT `which $file`
   if test $? = 1 ; then failed=`expr $failed + 1`; fi
   tested=`expr $tested + 1`


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]