[gtk-doc] scan: Convert to Python.



commit e6289d068101fa46c62f81602055ef3505b8c852
Author: Jussi Pakkanen <jpakkane gmail com>
Date:   Fri Mar 31 18:59:34 2017 +0300

    scan: Convert to Python.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=780789

 gtkdoc-scan.in      | 1479 ++++++++++++++++++++++++---------------------------
 tests/Makefile.am   |    4 +-
 tests/gtkdoc-scan.t |   30 -
 tests/tools.sh.in   |    2 +-
 4 files changed, 699 insertions(+), 816 deletions(-)
---
diff --git a/gtkdoc-scan.in b/gtkdoc-scan.in
index 672545e..6889293 100755
--- a/gtkdoc-scan.in
+++ b/gtkdoc-scan.in
@@ -1,5 +1,5 @@
-#!@PERL@ -w
-# -*- cperl -*-
+#!@PYTHON@
+# -*- python -*-
 #
 # gtk-doc - GTK DocBook documentation generator.
 # Copyright (C) 1998  Damon Chaplin
@@ -37,173 +37,113 @@
 #                output the SGML pages.
 #############################################################################
 
-use strict;
-use Getopt::Long;
-use Cwd qw(realpath);
-
-push @INC, '@PACKAGE_DATA_DIR@';
-require "gtkdoc-common.pl";
-
-# Options
-
-# name of documentation module
-my $MODULE;
-my $OUTPUT_DIR;
-my @SOURCE_DIRS;
-my $IGNORE_HEADERS = "";
-my $REBUILD_TYPES;
-my $REBUILD_SECTIONS;
-my $PRINT_VERSION;
-my $PRINT_HELP;
-# regexp matching cpp symbols which surround deprecated stuff
-# e.g. 'GTK_ENABLE_BROKEN|GTK_DISABLE_DEPRECATED'
-# these are detected if they are used as #if FOO, #ifndef FOO, or #ifdef FOO
-my $DEPRECATED_GUARDS;
-# regexp matching decorators that should be ignored
-my $IGNORE_DECORATORS;
-
-my @get_types = ();
+from __future__ import print_function
+
+import os, sys, argparse, re
+import logging
+sys.path.append('@PYTHON_PACKAGE_DIR@')
+
+from gtkdoc import common, config
 
 # do not read files twice; checking it here permits to give both srcdir and
 # builddir as --source-dir without fear of duplicities
-my %seen_headers;
-
-
-Run() unless caller; # Run program unless loaded as a module
-
-
-sub Run {
-    my %optctl = (module => \$MODULE,
-                  'source-dir' => \@SOURCE_DIRS,
-                  'ignore-headers' => \$IGNORE_HEADERS,
-                  'output-dir' => \$OUTPUT_DIR,
-                  'rebuild-types' => \$REBUILD_TYPES,
-                  'rebuild-sections' => \$REBUILD_SECTIONS,
-                  'version' => \$PRINT_VERSION,
-                  'help' => \$PRINT_HELP,
-                  'deprecated-guards' => \$DEPRECATED_GUARDS,
-                  'ignore-decorators' => \$IGNORE_DECORATORS);
-    GetOptions(\%optctl, "module=s", "source-dir:s", "ignore-headers:s",
-               "output-dir:s", "rebuild-types", "rebuild-sections", "version",
-               "help", "deprecated-guards:s", "ignore-decorators:s");
-
-    if ($PRINT_VERSION) {
-        print "@VERSION@\n";
-        exit 0;
-    }
-
-    if (!$MODULE) {
-        $PRINT_HELP = 1;
-    }
-
-    if ($PRINT_HELP) {
-        print <<EOF;
-gtkdoc-scan version @VERSION@ - scan header files for public symbols
-
---module=MODULE_NAME       Name of the doc module being parsed
---source-dir=DIRNAME       Directories containing the source files to scan
---ignore-headers=FILES     A space-separated list of header files/dirs not to
-                           scan
---output-dir=DIRNAME       The directory where the results are stored
---deprecated-guards=GUARDS A |-separated list of symbols used as deprecation
-                           guards
---ignore-decorators=DECS   A |-separated list of addition decorators in
-                           declarations that should be ignored
---rebuild-sections         Rebuild (overwrite) the MODULE-sections.txt file
---rebuild-types            Automatically recreate the MODULE.types file using
-                           all the *_get_type() functions found
---version                  Print the version of this program
---help                     Print this help
-EOF
-        exit 0;
-    }
-
-    $DEPRECATED_GUARDS = $DEPRECATED_GUARDS ? $DEPRECATED_GUARDS : 
"does_not_match_any_cpp_symbols_at_all_nope";
-
-    $IGNORE_DECORATORS = $IGNORE_DECORATORS || "(?=no)match";
-
-    $OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
-
-    if (!-d ${OUTPUT_DIR}) {
-        mkdir($OUTPUT_DIR, 0755) || die "Cannot create $OUTPUT_DIR: $!";
-    }
-
-    my $old_decl_list = "${OUTPUT_DIR}/$MODULE-decl-list.txt";
-    my $new_decl_list = "${OUTPUT_DIR}/$MODULE-decl-list.new";
-    my $old_decl = "${OUTPUT_DIR}/$MODULE-decl.txt";
-    my $new_decl = "${OUTPUT_DIR}/$MODULE-decl.new";
-    my $old_types = "${OUTPUT_DIR}/$MODULE.types";
-    my $new_types = "${OUTPUT_DIR}/$MODULE.types.new";
-    my $sections_file = "${OUTPUT_DIR}/$MODULE-sections.txt";
+seen_headers = {}
+
+parser = argparse.ArgumentParser(
+    description='gtkdoc-scan version %s - scan header files for public symbols' % config.version)
+parser.add_argument('--version', action='version', version=config.version)
+parser.add_argument('--module', default='', help='Name of the doc module being parsed.')
+parser.add_argument('--source-dir', action='append', default=[],
+                    help='Directories containing the source files to scan')
+parser.add_argument('--ignore-headers', default='',
+                    help='A space-separated list of header files/dirs not to scan')
+parser.add_argument('--output-dir', default='.',
+                    help='The directory where the results are stored')
+parser.add_argument('--deprecated-guards', default='',
+                    help='A |-separated list of symbols used as deprecation guards')
+parser.add_argument('--ignore-decorators', default='',
+                    help='A |-separated list of additional decorators in'
+                    'declarations that should be ignored')
+parser.add_argument('--rebuild-sections', action='store_true', default=False,
+                    help='Rebuild (overwrite) the MODULE-sections.txt file')
+parser.add_argument('--rebuild-types', action='store_true', default=False,
+                    help='Automatically recreate the MODULE.types file using'
+                    'all the *_get_type() functions found')
+parser.add_argument('headers', nargs='*')
+
+def Run():
+    options = parser.parse_args()
+    if options.module == '':
+        print('Error, missing module.')
+        sys.exit(1)
+
+    if options.deprecated_guards == '':
+        options.deprecated_guards =  'does_not_match_any_cpp_symbols_at_all_nope'
+
+    if options.ignore_decorators == '':
+        options.ignore_decorators = '(?=no)match'
+
+    if not os.path.isdir(options.output_dir):
+        os.mkdir(options.output_dir)
+
+    base_filename = os.path.join(options.output_dir, options.module)
+    old_decl_list = base_filename + '-decl-list.txt'
+    new_decl_list = base_filename + '-decl-list.new'
+    old_decl = base_filename + '-decl.txt'
+    new_decl = base_filename + '-decl.new'
+    old_types = base_filename + '.types'
+    new_types = base_filename + '.types.new'
+    sections_file = base_filename + '-sections.txt'
 
     # If this is the very first run then we create the .types file automatically.
-    if (! -e $sections_file && ! -e $old_types) {
-        $REBUILD_TYPES = 1;
-    }
-
-    open (DECLLIST, ">$new_decl_list")
-        || die "Can't open $new_decl_list";
-    open (DECL, ">$new_decl")
-        || die "Can't open $new_decl";
-    if ($REBUILD_TYPES) {
-        open (TYPES, ">$new_types")
-            || die "Can't open $new_types";
-    }
-
-    my %section_list = ();
-    my $file;
-
-    # The header files to scan are passed in as command-line args.
-    for $file (@ARGV) {
-        &ScanHeader ($file, \%section_list);
-    }
-
-    for my $dir (@SOURCE_DIRS) {
-        &ScanHeaders ($dir, \%section_list);
-    }
-
-    ## FIXME: sort by key and output
-    #print DECLLIST $section_list;
-    my $section;
-    foreach $section (sort(keys %section_list)) {
-        print DECLLIST "$section_list{$section}";
-    }
-
-    close (DECLLIST);
-    close (DECL);
-
-    if ($REBUILD_TYPES) {
-        my $func;
-
-        foreach $func (sort(@get_types)) {
-           print TYPES "$func\n";
-        }
-        close (TYPES);
-        &UpdateFileIfChanged ($old_types, $new_types, 1);
+    if not os.path.exists(sections_file) and not os.path.exists(old_types):
+        options.rebuild_types = True
+
+    section_list = {}
+    decl_list = []
+    get_types = []
+
+    for file in options.headers:
+        ScanHeader(file, section_list, decl_list, get_types, options)
+
+    for dir in options.source_dir:
+        ScanHeaders(dir, section_list, decl_list, get_types, options)
+
+    with open(new_decl_list, 'w') as f:
+        for section in sorted(section_list.keys()):
+            f.write(section_list[section])
+
+    with open(new_decl, 'w') as f:
+        for decl in decl_list:
+            f.write(decl)
+
+    if options.rebuild_types:
+        with open(new_types, 'w') as f:
+            for func in sorted(get_types):
+                f.write(func + '\n')
 
         # remove the file if empty
-        if (scalar (@get_types) == 0) {
-            unlink ("$new_types");
-        }
-    }
+        if len(get_types) == 0:
+            os.unlink(new_types)
+            if os.path.exists(old_types):
+                os.rename(old_types, old_types + '.bak')
+        else:
+            common.UpdateFileIfChanged(old_types, new_types, True)
 
-    &UpdateFileIfChanged ($old_decl_list, $new_decl_list, 1);
-    &UpdateFileIfChanged ($old_decl, $new_decl, 1);
+    common.UpdateFileIfChanged(old_decl_list, new_decl_list, True)
+    common.UpdateFileIfChanged(old_decl, new_decl, True)
 
     # If there is no MODULE-sections.txt file yet or we are asked to rebuild it,
     # we copy the MODULE-decl-list.txt file into its place. The user can tweak it
     # later if they want.
-    if ($REBUILD_SECTIONS || ! -e $sections_file) {
-      &UpdateFileIfChanged ($sections_file, $old_decl_list, 0);
-    }
+    if options.rebuild_sections or not os.path.exists(sections_file):
+        common.UpdateFileIfChanged(sections_file, old_decl_list, False)
 
     # If there is no MODULE-overrides.txt file we create an empty one
     # because EXTRA_DIST in gtk-doc.make requires it.
-    my $overrides_file = "${OUTPUT_DIR}/$MODULE-overrides.txt";
-    if (! -e $overrides_file) {
-      `touch $overrides_file`;
-    }
-}
+    overrides_file = base_filename + '-overrides.txt'
+    if not os.path.exists(overrides_file):
+        open(overrides_file, 'w').close()
 
 
 #############################################################################
@@ -214,762 +154,736 @@ EOF
 #               $section_list - a reference to the hashmap of sections.
 #############################################################################
 
-sub ScanHeaders {
-    my ($source_dir, $section_list) = @_;
-    @TRACE@("Scanning source directory: $source_dir");
+def ScanHeaders(source_dir, section_list, decl_list, get_types, options):
+    logging.info('Scanning source directory: %s', source_dir)
 
     # This array holds any subdirectories found.
-    my (@subdirs) = ();
-
-    opendir (SRCDIR, $source_dir)
-        || die "Can't open source directory $source_dir: $!";
-    my $file;
-    foreach $file (readdir (SRCDIR)) {
-        if ($file eq '.' || $file eq '..' || $file =~ /^\./) {
-            next;
-        } elsif (-d "$source_dir/$file") {
-            push (@subdirs, $file);
-        } elsif ($file =~ m/\.h$/) {
-            &ScanHeader ("$source_dir/$file", $section_list);
-        }
-    }
-    closedir (SRCDIR);
+    subdirs = []
+
+    for file in os.listdir(source_dir):
+        if file.startswith('.'):
+            continue
+        fullname = os.path.join(source_dir, file)
+        if os.path.isdir(fullname):
+            subdirs.append(file)
+        elif file.endswith('.h'):
+            ScanHeader(fullname, section_list, decl_list, get_types, options)
 
     # Now recursively scan the subdirectories.
-    my $dir;
-    foreach $dir (@subdirs) {
-        next if ($IGNORE_HEADERS =~ m/(\s|^)\Q${dir}\E(\s|$)/);
-        &ScanHeaders ("$source_dir/$dir", $section_list);
-    }
-}
+    for dir in subdirs:
+        matchstr = r'(\s|^)' + re.escape(dir) + r'(\s|$)'
+        if re.search(matchstr, options.ignore_headers):
+            continue
+        ScanHeaders(os.path.join(source_dir, dir), section_list, decl_list,
+                    get_types, options)
 
 
 #############################################################################
 # Function    : ScanHeader
 # Description : This scans a header file, looking for declarations of
 #                functions, macros, typedefs, structs and unions, which it
-#                outputs to the DECL file.
+#                outputs to the decl_list.
 # Arguments   : $input_file - the header file to scan.
-#               $section_list - a reference to the hashmap of sections.
+#               $section_list - a map of sections.
+#               $decl_list - a list of declarations
 # Returns     : it adds declarations to the appropriate list.
 #############################################################################
 
-sub ScanHeader {
-    my ($input_file, $section_list) = @_;
-
-    my $list = "";                  # Holds the resulting list of declarations.
-    my $title = "";                 # Holds the title of the section
-    my ($in_comment) = 0;                  # True if we are in a comment.
-    my ($in_declaration) = "";          # The type of declaration we are in, e.g.
-                                  #   'function' or 'macro'.
-    my ($skip_block) = 0;                  # True if we should skip a block.
-    my ($symbol);                  # The current symbol being declared.
-    my ($decl);                          # Holds the declaration of the current symbol.
-    my ($ret_type);                  # For functions and function typedefs this
-                                  #   holds the function's return type.
-    my ($pre_previous_line) = "";   # The pre-previous line read in - some Gnome
-                                  #   functions have the return type on one
-                                  #   line, the function name on the next,
-                                  #   and the rest of the declaration after.
-    my ($previous_line) = "";          # The previous line read in - some Gnome
-                                  #   functions have the return type on one line
-                                  #   and the rest of the declaration after.
-    my ($first_macro) = 1;          # Used to try to skip the standard #ifdef XXX
-                                  #   #define XXX at the start of headers.
-    my ($level);                          # Used to handle structs/unions which contain
-                                  #   nested structs or unions.
-    my @objects = ();                  # Holds declarations that look like GtkObject
-                                  #   subclasses, which we remove from the list.
-    my ($internal) = 0;             # Set to 1 for internal symbols, we need to
-                                    #   fully parse, but don't add them to docs
-    my %forward_decls = ();         # hashtable of forward declarations, we skip
-                                    #   them if we find the real declaration
-                                    #   later.
-    my %doc_comments = ();          # hastable of doc-comment we found. We can
-                                    # use that to put element to the right
-                                    # sction in the generated section-file
-
-    my $file_basename;
-
-    my $deprecated_conditional_nest = 0;
-    my $ignore_conditional_nest = 0;
-
-    my $deprecated = "";
-    my $doc_comment = "";
+def ScanHeader(input_file, section_list, decl_list, get_types, options):
+    global seen_headers
+    slist = []                  # Holds the resulting list of declarations.
+    title = ''                 # Holds the title of the section
+    in_comment = 0                  # True if we are in a comment.
+    in_declaration = ''          # The type of declaration we are in, e.g.
+                              #   'function' or 'macro'.
+    skip_block = 0                  # True if we should skip a block.
+    symbol=None                  # The current symbol being declared.
+    decl=''                          # Holds the declaration of the current symbol.
+    ret_type=None                  # For functions and function typedefs this
+                              #   holds the function's return type.
+    pre_previous_line = ''   # The pre-previous line read in - some Gnome
+                              #   functions have the return type on one
+                              #   line, the function name on the next,
+                              #   and the rest of the declaration after.
+    previous_line = ''          # The previous line read in - some Gnome
+                              #   functions have the return type on one line
+                              #   and the rest of the declaration after.
+    first_macro = 1          # Used to try to skip the standard #ifdef XXX
+                              #   #define XXX at the start of headers.
+    level = None                          # Used to handle structs/unions which contain
+                              #   nested structs or unions.
+    internal = 0             # Set to 1 for internal symbols, we need to
+                                #   fully parse, but don't add them to docs
+    forward_decls = {}         # hashtable of forward declarations, we skip
+                                #   them if we find the real declaration
+                                #   later.
+    doc_comments = {}          # hastable of doc-comment we found. We can
+                                # use that to put element to the right
+                                # sction in the generated section-file
+
+    file_basename = None
+
+    deprecated_conditional_nest = 0
+    ignore_conditional_nest = 0
+
+    deprecated = ''
+    doc_comment = ''
 
     # Don't scan headers twice
-    my $canonical_input_file = realpath $input_file;
-    if (exists $seen_headers{$canonical_input_file}) {
-        @TRACE@("File already scanned: $input_file");
-        return;
-    }
-    $seen_headers{$canonical_input_file} = 1;
-
-    if ($input_file =~ m/^.*[\/\\](.*)\.h+$/) {
-        $file_basename = $1;
-    } else {
-        LogWarning(__FILE__,__LINE__,"Can't find basename of file $input_file");
-        $file_basename = $input_file;
-    }
+    canonical_input_file = os.path.realpath(input_file)
+    if canonical_input_file in seen_headers:
+        logging.info('File already scanned: %s', input_file)
+        return
+
+    seen_headers[canonical_input_file] = 1
+
+    file_basename = os.path.split(input_file)[1][:-2] # filename ends in .h
 
     # Check if the basename is in the list of headers to ignore.
-    if ($IGNORE_HEADERS =~ m/(\s|^)\Q${file_basename}\E\.h(\s|$)/) {
-        @TRACE@("File ignored: $input_file");
-        return;
-    }
+    matchstr = r'(\s|^)' + re.escape(file_basename) + r'\.h(\s|$)'
+    if re.search(matchstr, options.ignore_headers):
+        logging.info('File ignored: %s', input_file)
+        return
+
     # Check if the full name is in the list of headers to ignore.
-    if ($IGNORE_HEADERS =~ m/(\s|^)\Q${input_file}\E(\s|$)/) {
-        @TRACE@("File ignored: $input_file");
-        return;
-    }
+    matchstr = r'(\s|^)' + re.escape(input_file) + r'(\s|$)'
+    if re.search(matchstr, options.ignore_headers):
+        logging.info('File ignored: %s', input_file)
+        return
 
-    if (! -f $input_file) {
-        LogWarning(__FILE__,__LINE__,"File doesn't exist: $input_file");
-        return;
-    }
+    if not os.path.exists(input_file):
+        logging.warning('File does not exist: %s', input_file)
+        return
 
-    @TRACE@("Scanning $input_file");
+    logging.info('Scanning %s', input_file)
 
-    open(INPUT, $input_file)
-        || die "Can't open $input_file: $!";
-    while(<INPUT>) {
+    for line in open(input_file):
         # If this is a private header, skip it.
-        if (m%^\s*/\*\s*<\s*private_header\s*>\s*\*/%) {
-            close(INPUT);
-            return;
-        }
+        if re.search(r'%^\s*/\*\s*<\s*private_header\s*>\s*\*/', line):
+            return
 
         # Skip to the end of the current comment.
-        if ($in_comment) {
-            @TRACE@("Comment: $_");
-            $doc_comment .= $_;
-            if (m%\*/%) {
-                if ($doc_comment =~ m/\* ([a-zA-Z][a-zA-Z0-9_]+):/) {
-                  $doc_comments{lc($1)} = 1;
-                }
-                $in_comment = 0;
-                $doc_comment = "";
-            }
-            next;
-        }
+        if in_comment:
+            logging.info('Comment: %s', line)
+            doc_comment += line
+            if re.search(r'\*/', line):
+                m = re.search(r'\* ([a-zA-Z][a-zA-Z0-9_]+):/', doc_comment)
+                if m:
+                  doc_comments[m.group(1).lower()] = 1
+                in_comment = 0
+                doc_comment = ''
+            continue
 
         # Keep a count of #if, #ifdef, #ifndef nesting,
         # and if we enter a deprecation-symbol-bracketed
         # zone, take note.
-        if (m/^\s*#\s*if(?:n?def\b|\s+!?\s*defined\s*\()\s*(\w+)/) {
-            my $define_name = $1;
-            if ($deprecated_conditional_nest < 1 and $define_name =~ /$DEPRECATED_GUARDS/) {
-                 $deprecated_conditional_nest = 1;
-            } elsif ($deprecated_conditional_nest >= 1) {
-                 $deprecated_conditional_nest += 1;
-            }
-            if ($ignore_conditional_nest == 0 and $define_name =~ /__GTK_DOC_IGNORE__/) {
-                 $ignore_conditional_nest = 1;
-            } elsif ($ignore_conditional_nest > 0) {
-                 $ignore_conditional_nest += 1;
-            }
-        } elsif (m/^\s*#\sif/) {
-            if ($deprecated_conditional_nest >= 1) {
-                 $deprecated_conditional_nest += 1;
-            }
-            if ($ignore_conditional_nest > 0) {
-                 $ignore_conditional_nest += 1;
-            }
-        } elsif (m/^\s*#endif/) {
-            if ($deprecated_conditional_nest >= 1) {
-                $deprecated_conditional_nest -= 1;
-            }
-            if ($ignore_conditional_nest > 0) {
-                $ignore_conditional_nest -= 1;
-            }
-        }
+        m = re.search(r'^\s*#\s*if(?:n?def\b|\s+!?\s*defined\s*\()\s*(\w+)', line)
+        if m:
+            define_name = m.group(1)
+            if deprecated_conditional_nest < 1 and re.search(options.deprecated_guards, define_name):
+                deprecated_conditional_nest = 1
+            elif deprecated_conditional_nest >= 1:
+                deprecated_conditional_nest += 1
+            if ignore_conditional_nest == 0 and '__GTK_DOC_IGNORE__' in define_name:
+                ignore_conditional_nest = 1
+            elif ignore_conditional_nest > 0:
+                ignore_conditional_nest = 1
+
+        elif re.search(r'^\s*#\sif', line):
+            if deprecated_conditional_nest >= 1:
+                 deprecated_conditional_nest += 1
+
+            if ignore_conditional_nest > 0:
+                 ignore_conditional_nest += 1
+        elif re.search(r'^\s*#endif', line):
+            if deprecated_conditional_nest >= 1:
+                deprecated_conditional_nest -= 1
+
+            if ignore_conditional_nest > 0:
+                ignore_conditional_nest -= 1
 
         # If we find a line containing _DEPRECATED, we hope that this is
         # attribute based deprecation and also treat this as a deprecation
         # guard, unless it's a macro definition.
-        if ($deprecated_conditional_nest == 0 and m/_DEPRECATED/) {
-            unless (m/^\s*#\s*(if*|define)/ or $in_declaration eq "enum") {
-                @TRACE@("Found deprecation annotation (decl: '$in_declaration'): $_");
-                $deprecated_conditional_nest += 0.1;
-            }
-        }
-
-        # set global that is used later when we do AddSymbolToList
-        if ($deprecated_conditional_nest > 0) {
-            $deprecated = "<DEPRECATED/>\n";
-        } else {
-            $deprecated = "";
-        }
-
-        if($ignore_conditional_nest) {
-            next;
-        }
-
-        if (!$in_declaration) {
+        if deprecated_conditional_nest == 0 and '_DEPRECATED' in line:
+            m = re.search(r'^\s*#\s*(if*|define)', line)
+            if not (m or in_declaration == 'enum'):
+                logging.info('Found deprecation annotation (decl: "%s"): "%s"', in_declaration, line)
+                deprecated_conditional_nest += 0.1
+
+        # set flag that is used later when we do AddSymbolToList
+        if deprecated_conditional_nest > 0:
+            deprecated = '<DEPRECATED/>\n'
+        else:
+            deprecated = ''
+
+        if ignore_conditional_nest:
+            continue
+
+        if not in_declaration:
             # Skip top-level comments.
-            if (s%^\s*/\*%%) {
-                if (m%\*/%) {
-                    @TRACE@("Found one-line comment: $_");
-                } else {
-                    $in_comment = 1;
-                    $doc_comment = $_;
-                    @TRACE@("Found start of comment: $_");
-                }
-                next;
-            }
-
-            @TRACE@("0: $_");
+            m = re.search(r'^\s*/\*', line)
+            if m:
+                re.sub(r'^\s*/\*', '', line)
+                if re.search(r'\*/', line):
+                    logging.info('Found one-line comment: %s', line)
+                else:
+                    in_comment = 1
+                    doc_comment = line
+                    logging.info('Found start of comment: %s', line)
+                continue
+
+            logging.info('no decl: %s', line.strip())
+
+            m = re.search(r'^\s*#\s*define\s+(\w+)', line)
+            #                                $1                                $3            $4             
$5
+            m2 = 
re.search(r'^\s*typedef\s+((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*(\**)\s*\(\*\s*(\w+)\)\s*\(', line)
+            #                      $1                                $3            $4             $5
+            m3 = 
re.search(r'^\s*((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*(\**)\s*\(\*\s*(\w+)\)\s*\(', line)
+            #                    $1            $2
+            m4 = re.search(r'^\s*(\**)\s*\(\*\s*(\w+)\)\s*\(', line)
+            #                              $1                                $3
+            m5 = re.search(r'^\s*typedef\s*((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*', previous_line)
+            #                                                                           $1                   
             $3            $4             $5
+            m6 = 
re.search(r'^\s*(?:\b(?:extern|G_INLINE_FUNC|%s)\s*)*((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*(\**)\s*\(\*\s*(\w+)\)\s*\('
 % options.ignore_decorators, line)
+            m7 = re.search(r'^\s*enum\s+_?(\w+)\s+\{', line)
+            m8 = re.search(r'^\s*typedef\s+enum', line)
+            m9 = re.search(r'^\s*typedef\s+(struct|union)\s+_(\w+)\s+\2\s*;', line)
+            m10 = re.search(r'^\s*(struct|union)\s+(\w+)\s*;', line)
+            m11 = re.search(r'^\s*typedef\s+(struct|union)\s*\w*\s*{', line)
+            m12 = re.search(r'^\s*typedef\s+(?:struct|union)\s+\w+[\s\*]+(\w+)\s*;', line)
+            m13 = re.search(r'^\s*(G_GNUC_EXTENSION\s+)?typedef\s+(.+[\s\*])(\w+)(\s*\[[^\]]+\])*\s*;', line)
+            m14 = 
re.search(r'^\s*(extern|[A-Za-z_]+VAR|%s)\s+((const\s+|signed\s+|unsigned\s+|long\s+|short\s+)*\w+)(\s+\*+|\*+|\s)\s*(const\s+)*([A-Za-z]\w*)\s*;'
 % options.ignore_decorators, line)
+            m15 = 
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*\=',
 line)
+            m16 = re.search(r'.*G_DECLARE_(FINAL_TYPE|DERIVABLE_TYPE|INTERFACE)\s*\(', line)
+            #                                                          $1                                    
                                                                $2                                            
              $3
+            m17 = 
re.search(r'^\s*(?:\b(?:extern|G_INLINE_FUNC|%s)\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s+|\*)+(?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*(_[A-Za-z]\w*)\s*\('
 % options.ignore_decorators, line)
+            #                                                          $1                                    
                                                                $2                                            
              $3
+            m18 = 
re.search(r'^\s*(?:\b(?:extern|G_INLINE_FUNC|%s)\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s+|\*)+(?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*([A-Za-z]\w*)\s*\('
 % options.ignore_decorators, line)
+            m19 = re.search(r'^\s*([A-Za-z]\w*)\s*\(', line)
+            m20 = re.search(r'^\s*\(', line)
+            m21 = re.search(r'^\s*struct\s+_?(\w+)', line)
+            m22 = re.search(r'^\s*union\s+_(\w+)', line)
 
             # MACROS
 
-            if (m/^\s*#\s*define\s+(\w+)/) {
-                $symbol = $1;
-                $decl = $_;
+            if m:
+                symbol = m.group(1)
+                decl = line
                 # We assume all macros which start with '_' are private.
                 # We also try to skip the first macro if it looks like the
                 # standard #ifndef HEADER_FILE #define HEADER_FILE etc.
                 # And we only want TRUE & FALSE defined in GLib.
-                if ($symbol !~ m/^_/
-                     && ($previous_line !~ m/#ifndef\s+$symbol/
-                         || $first_macro == 0)
-                     && (($symbol ne 'TRUE' && $symbol ne 'FALSE')
-                         || $MODULE eq 'glib')) {
-                    $in_declaration = "macro";
-                    @TRACE@("Macro: $symbol");
-                } else {
-                    @TRACE@("skipping Macro: $symbol");
-                    $in_declaration = "macro";
-                    $internal = 1;
-                }
-                $first_macro = 0;
+                if not symbol.startswith('_') \
+                     and (not re.search(r'#ifndef\s+' + symbol, previous_line)
+                         or first_macro == 0) \
+                     and ((symbol != 'TRUE' and symbol != 'FALSE')
+                         or options.module == 'glib'):
+                    in_declaration = 'macro'
+                    logging.info('Macro: "%s"', symbol)
+                else:
+                    logging.info('skipping Macro: "%s"', symbol)
+                    in_declaration = 'macro'
+                    internal = 1
+                first_macro = 0
 
 
             # TYPEDEF'D FUNCTIONS (i.e. user functions)
 
-            #                        $1                                $3            $4             $5
-            } elsif 
(m/^\s*typedef\s+((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/) {
-                my $p3 = defined($3) ? $3 : "";
-                $ret_type = "$1$p3 $4";
-                $symbol = $5;
-                $decl = $';
-                $in_declaration = "user_function";
-                @TRACE@("user function (1): $symbol, Returns: $ret_type");
-
-            #                                                       $1                                $3     
       $4             $5
-            } elsif (($previous_line =~ m/^\s*typedef\s*/) && 
m/^\s*((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/) {
-                my $p3 = defined($3) ? $3 : "";
-                $ret_type = "$1$p3 $4";
-                $symbol = $5;
-                $decl = $';
-                $in_declaration = "user_function";
-                @TRACE@("user function (2): $symbol, Returns: $ret_type");
-
-            #                                                       $1            $2
-            } elsif (($previous_line =~ m/^\s*typedef\s*/) && m/^\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/) {
-                $ret_type = $1;
-                $symbol = $2;
-                $decl = $';
-                #                                     $1                                $3
-                if ($previous_line =~ m/^\s*typedef\s*((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*/) {
-                    my $p3 = defined($3) ? $3 : "";
-                    $ret_type = "$1$p3 ".$ret_type;
-                    $in_declaration = "user_function";
-                    @TRACE@("user function (3): $symbol, Returns: $ret_type");
-
-                }
+            elif m2:
+                p3 = m2.group(3) or ''
+                ret_type = "%s%s %s" % (m2.group(1), p3, m2.group(4))
+                symbol = m2.group(5)
+                decl = line[m2.end():]
+                in_declaration = 'user_function'
+                logging.info('user function (1): "%s", Returns: "%s"', symbol, ret_type)
+
+            elif re.search(r'^\s*typedef\s*', previous_line) and m3:
+                p3 = m3.group(3) or ''
+                ret_type = '%s%s %s' % (m3.group(1), p3, m3.group(4))
+                symbol = m3.group(5)
+                decl = line[m3.end():]
+                in_declaration = 'user_function'
+                logging.info('user function (2): "%s", Returns: "%s"', symbol, ret_type)
+
+            elif re.search(r'^\s*typedef\s*', previous_line) and m4:
+                ret_type = m4.group(1)
+                symbol = m4.group(2)
+                decl = line[m4.end():]
+                if m5:
+                    p3 = m5.group(3) or ''
+                    ret_type = "%s%s %s" % (m5.group(1), p3, ret_type)
+                    in_declaration = 'user_function'
+                    logging.info('user function (3): "%s", Returns: "%s"', symbol, ret_type)
+
             # FUNCTION POINTER VARIABLES
-            #                                                                     $1                         
       $3            $4             $5
-            } elsif 
(m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\s*)*((const\s+|G_CONST_RETURN\s+)?\w+)(\s+const)?\s*(\**)\s*\(\*\s*(\w+)\)\s*\(/o)
 {
-                my $p3 = defined($3) ? $3 : "";
-                $ret_type = "$1$p3 $4";
-                $symbol = $5;
-                $decl = $';
-                $in_declaration = "user_function";
-                @TRACE@("function pointer variable: $symbol, Returns: $ret_type");
+            elif m6:
+                p3 = m6.group(3) or ''
+                ret_type = '%s%s %s' % (m6.group(1), p3, m6.group(4))
+                symbol = m6.group(5)
+                decl = line[m6.end():]
+                in_declaration = 'user_function'
+                logging.info('function pointer variable: "%s", Returns: "%s"', symbol, ret_type)
 
             # ENUMS
 
-            } elsif (s/^\s*enum\s+_?(\w+)\s+\{/enum $1 {/) {
+            elif m7:
+                re.sub(r'^\s*enum\s+_?(\w+)\s+\{', r'enum \1 {',line)
                 # We assume that 'enum _<enum_name> {' is really the
                 # declaration of enum <enum_name>.
-                $symbol = $1;
-                @TRACE@("plain enum: $symbol");
-                $decl = $_;
-                $in_declaration = "enum";
+                symbol = m7.group(1)
+                decl = line
+                in_declaration = 'enum'
+                logging.info('plain enum: "%s"', symbol)
 
-            } elsif (m/^\s*typedef\s+enum\s+_?(\w+)\s+\1\s*;/) {
+            elif re.search(r'^\s*typedef\s+enum\s+_?(\w+)\s+\1\s*;', line):
                 # We skip 'typedef enum <enum_name> _<enum_name>;' as the enum will
                 # be declared elsewhere.
-                @TRACE@("skipping enum typedef: $1");
-
-            } elsif (m/^\s*typedef\s+enum/) {
-                $symbol = "";
-                @TRACE@("typedef enum: -");
-                $decl = $_;
-                $in_declaration = "enum";
-
+                logging.info('skipping enum typedef: "%s"', line)
+            elif m8:
+                symbol = ''
+                decl = line
+                in_declaration = 'enum'
+                logging.info('typedef enum: -')
 
             # STRUCTS AND UNIONS
 
-            } elsif (m/^\s*typedef\s+(struct|union)\s+_(\w+)\s+\2\s*;/) {
+            elif m9:
                 # We've found a 'typedef struct _<name> <name>;'
                 # This could be an opaque data structure, so we output an
                 # empty declaration. If the structure is actually found that
                 # will override this.
-                my $structsym = uc $1;
-                @TRACE@("$structsym typedef: $2");
-                $forward_decls{$2} = "<$structsym>\n<NAME>$2</NAME>\n$deprecated</$structsym>\n"
+                structsym = m9.group(1).upper()
+                logging.info('%s typedef: "%s"', structsym, m9.group(2))
+                forward_decls[m9.group(2)] = '<%s>\n<NAME>%s</NAME>\n%s</%s>\n' % (structsym, m9.group(2), 
deprecated, structsym)
 
-            } elsif (m/^\s*(?:struct|union)\s+_(\w+)\s*;/) {
+            elif re.search(r'^\s*(?:struct|union)\s+_(\w+)\s*;', line):
                 # Skip private structs/unions.
-                @TRACE@("private struct/union");
+                logging.info('private struct/union')
 
-            } elsif (m/^\s*(struct|union)\s+(\w+)\s*;/) {
+            elif m10:
                 # Do a similar thing for normal structs as for typedefs above.
                 # But we output the declaration as well in this case, so we
                 # can differentiate it from a typedef.
-                my $structsym = uc $1;
-                @TRACE@("$structsym: $2");
-                $forward_decls{$2} = "<$structsym>\n<NAME>$2</NAME>\n$_$deprecated</$structsym>\n";
+                structsym = m10.group(1).upper()
+                logging.info('%s:%s', structsym, m10.group(2))
+                forward_decls[m10.group(2)] = '<%s>\n<NAME>%s</NAME>\n%s%s</%s>\n' % (structsym, 
m10.group(2), line, deprecated, structsym)
 
-            } elsif (m/^\s*typedef\s+(struct|union)\s*\w*\s*{/) {
-                $symbol = "";
-                $decl = $_;
-                $level = 0;
-                $in_declaration = $1;
-                @TRACE@("typedef struct/union $1");
+            elif m11:
+                symbol = ''
+                decl = line
+                level = 0
+                in_declaration = m11.group(1)
+                logging.info('typedef struct/union "%s"', in_declaration)
 
             # OTHER TYPEDEFS
 
-            } elsif (m/^\s*typedef\s+(?:struct|union)\s+\w+[\s\*]+(\w+)\s*;/) {
-                @TRACE@("Found struct/union(*) typedef $1: $_");
-                if (&AddSymbolToList (\$list, $1)) {
-                    print DECL "<TYPEDEF>\n<NAME>$1</NAME>\n$deprecated$_</TYPEDEF>\n";
-                }
-
-            } elsif (m/^\s*(G_GNUC_EXTENSION\s+)?typedef\s+(.+[\s\*])(\w+)(\s*\[[^\]]+\])*\s*;/) {
-                if ($2 !~ m/^struct\s/ && $2 !~ m/^union\s/) {
-                    @TRACE@("Found typedef: $_");
-                    if (&AddSymbolToList (\$list, $3)) {
-                        print DECL "<TYPEDEF>\n<NAME>$3</NAME>\n$deprecated$_</TYPEDEF>\n";
-                    }
-                }
-            } elsif (m/^\s*typedef\s+/) {
-                @TRACE@("Skipping typedef: $_");
+            elif m12:
+                logging.info('Found struct/union(*) typedef "%s": "%s"', m12.group(1), line)
+                if AddSymbolToList(slist, m12.group(1)):
+                    decl_list.append('<TYPEDEF>\n<NAME>%s</NAME>\n%s%s</TYPEDEF>\n' % (m12.group(1), 
deprecated, line))
 
+            elif m13:
+                if m13.group(2).split()[0] not in ('struct', 'union'):
+                    logging.info('Found typedef: "%s"', line)
+                    if AddSymbolToList(slist, m13.group(3)):
+                        decl_list.append('<TYPEDEF>\n<NAME>%s</NAME>\n%s%s</TYPEDEF>\n' % (m13.group(3), 
deprecated, line))
+            elif re.search(r'^\s*typedef\s+', line):
+                logging.info('Skipping typedef: "%s"', line)
 
             # VARIABLES (extern'ed variables)
 
-            } elsif 
(m/^\s*(extern|[A-Za-z_]+VAR|${IGNORE_DECORATORS})\s+((const\s+|signed\s+|unsigned\s+|long\s+|short\s+)*\w+)(\s+\*+|\*+|\s)\s*(const\s+)*([A-Za-z]\w*)\s*;/o)
 {
-                $symbol = $6;
-                s/^\s*([A-Za-z_]+VAR)\b/extern/;
-                $decl = $_;
-                @TRACE@("Possible extern var $symbol: $decl");
-                if (&AddSymbolToList (\$list, $symbol)) {
-                    print DECL "<VARIABLE>\n<NAME>$symbol</NAME>\n$deprecated$decl</VARIABLE>\n";
-                }
-
+            elif m14:
+                symbol = m14.group(6)
+                line = re.sub(r'^\s*([A-Za-z_]+VAR)\b', r'extern', line)
+                decl = line
+                logging.info('Possible extern var "%s": "%s"', symbol, decl)
+                if AddSymbolToList(slist, symbol):
+                    decl_list.append('<VARIABLE>\n<NAME>%s</NAME>\n%s%s</VARIABLE>\n' % (symbol, deprecated, 
decl))
 
             # VARIABLES
 
-            } elsif 
(m/^\s*((const\s+|signed\s+|unsigned\s+|long\s+|short\s+)*\w+)(\s+\*+|\*+|\s)\s*(const\s+)*([A-Za-z]\w*)\s*\=/)
 {
-                $symbol = $5;
-                $decl = $_;
-                @TRACE@("Possible global var $symbol: $decl");
-                if (&AddSymbolToList (\$list, $symbol)) {
-                    print DECL "<VARIABLE>\n<NAME>$symbol</NAME>\n$deprecated$decl</VARIABLE>\n";
-                }
+            elif m15:
+                symbol = m15.group(5)
+                decl = line
+                logging.info('Possible global var" %s": "%s"', symbol, decl)
+                if AddSymbolToList(slist, symbol):
+                    decl_list.append('<VARIABLE>\n<NAME>%s</NAME>\n%s%s</VARIABLE>\n' % (symbol, deprecated, 
decl))
 
             # G_DECLARE_*
 
-            } elsif (m/.*G_DECLARE_(FINAL_TYPE|DERIVABLE_TYPE|INTERFACE)\s*\(/) {
-                $in_declaration = "g-declare";
-                $symbol = "G_DECLARE_$1";
-                $decl = $';
+            elif m16:
+                in_declaration = 'g-declare'
+                symbol = 'G_DECLARE_' + m16.group(1)
+                decl = line[m16.end():]
 
             # FUNCTIONS
 
             # We assume that functions which start with '_' are private, so
             # we skip them.
-            #                                                                     $1                         
                                                                           $2                                 
                         $3
-            } elsif 
(m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s+|\*)+(?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*(_[A-Za-z]\w*)\s*\(/o)
 {
-                $ret_type = $1;
-                if (defined ($2)) { $ret_type .= " $2"; }
-                $symbol = $3;
-                $decl = $';
-                @TRACE@("internal Function: $symbol, Returns: [$1][$2]");
-                $in_declaration = "function";
-                $internal = 1;
-                if (m/^\s*G_INLINE_FUNC/) {
-                    @TRACE@("skip block after inline function");
+            elif m17:
+                ret_type = m17.group(1)
+                if m17.group(2):
+                    ret_type += ' ' + m17.group(2)
+                symbol = m17.group(3)
+                decl = line[m17.end():]
+                logging.info('internal Function: "%s", Returns: "%s""%s"', symbol, m17.group(1), 
m17.group(2))
+                in_declaration = 'function'
+                internal = 1
+                if line.strip().startswith('G_INLINE_FUNC'):
+                    logging.info('skip block after inline function')
                     # now we we need to skip a whole { } block
-                    $skip_block = 1;
-                }
-
-            #                                                                     $1                         
                                                                           $2                                 
                         $3
-            } elsif 
(m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s+|\*)+(?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*([A-Za-z]\w*)\s*\(/o)
 {
-                $ret_type = $1;
-                if (defined ($2)) { $ret_type .= " $2"; }
-                $symbol = $3;
-                $decl = $';
-                @TRACE@("Function (1): $symbol, Returns: [$1][$2]");
-                $in_declaration = "function";
-                if (m/^\s*G_INLINE_FUNC/) {
-                    @TRACE@("skip block after inline function");
+                    skip_block = 1
+
+            elif m18:
+                ret_type = m18.group(1)
+                if m18.group(2):
+                    ret_type += ' ' + m18.group(2)
+                symbol = m18.group(3)
+                decl = line[m18.end():]
+                logging.info('Function (1): "%s", Returns: "%s""%s"', symbol, m18.group(1), m18.group(2))
+                in_declaration = 'function'
+                if line.strip().startswith('G_INLINE_FUNC'):
+                    logging.info('skip block after inline function')
                     # now we we need to skip a whole { } block
-                    $skip_block = 1;
-                }
+                    skip_block = 1
 
             # Try to catch function declarations which have the return type on
             # the previous line. But we don't want to catch complete functions
             # which have been declared G_INLINE_FUNC, e.g. g_bit_nth_lsf in
             # glib, or 'static inline' functions.
-            } elsif (m/^\s*([A-Za-z]\w*)\s*\(/) {
-                $symbol = $1;
-                $decl = $';
-
-                if ($previous_line !~ m/^\s*G_INLINE_FUNC/) {
-                    if ($previous_line !~ m/^\s*static\s+/) {
-                        #                                                                     $1             
                                                                                      $2
-                        if ($previous_line =~ 
m/^\s*(?:\b(?:extern|${IGNORE_DECORATORS})\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*$/o)
 {
-                            $ret_type = $1;
-                            if (defined ($2)) { $ret_type .= " $2"; }
-                            @TRACE@("Function  (2): $symbol, Returns: $ret_type");
-                            $in_declaration = "function";
-                        }
-                    } else {
-                        @TRACE@("skip block after inline function");
+            elif m19:
+                symbol = m19.group(1)
+                decl = line[m19.end():]
+
+                previous_line_words = previous_line.strip().split()
+
+                if not previous_line.strip().startswith('G_INLINE_FUNC'):
+                    if not previous_line_words or previous_line_words[0] != 'static':
+                        #                                           $1                                       
                                                            $2
+                        pm = 
re.search(r'^\s*(?:\b(?:extern|%s)\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*$'
 % options.ignore_decorators, previous_line)
+                        if pm:
+                            ret_type = pm.group(1)
+                            if pm.group(2):
+                                ret_type += ' ' + pm.group(2)
+                            logging.info('Function  (2): "%s", Returns: "%s"', symbol, ret_type)
+                            in_declaration = 'function'
+                    else:
+                        logging.info('skip block after inline function')
                         # now we we need to skip a whole { } block
-                        $skip_block = 1;
+                        skip_block = 1
                         #                                                                                  
$1                                                                                                    $2
-                        if ($previous_line =~ 
m/^\s*(?:\b(?:extern|static|inline|${IGNORE_DECORATORS})\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*$/o)
 {
-                            $ret_type = $1;
-                            if (defined ($2)) { $ret_type .= " $2"; }
-                            @TRACE@("Function  (3): $symbol, Returns: $ret_type");
-                            $in_declaration = "function";
-                        }
-                    }
-                }
-                else {
-                    if ($previous_line !~ m/^\s*static\s+/) {
-                        @TRACE@("skip block after inline function");
+                        pm = 
re.search(r'^\s*(?:\b(?:extern|static|inline|%s)\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*$'
 % options.ignore_decorators, previous_line)
+                        if pm:
+                            ret_type = pm.group(1)
+                            if pm.group(2):
+                                ret_type += ' ' + pm.group(2)
+                            logging.info('Function  (3): "%s", Returns: "%s"', symbol, ret_type)
+                            in_declaration = 'function'
+                else:
+                    if not previous_line_words or previous_line_words[0] != 'static':
+                        logging.info('skip block after inline function')
                         # now we we need to skip a whole { } block
-                        $skip_block = 1;
+                        skip_block = 1
                         #                                                                                  
$1                                                                                                    $2
-                        if ($previous_line =~ 
m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*$/o)
 {
-                            $ret_type = $1;
-                            if (defined ($2)) { $ret_type .= " $2"; }
-                            @TRACE@("Function (4): $symbol, Returns: $ret_type");
-                            $in_declaration = "function";
-                        }
-                    }
-                }
+                        pm = 
re.search(r'^\s*(?:\b(?:extern|G_INLINE_FUNC|%s)\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|long\s+|short\s+|struct\s+|union\s+|enum\s+)*\w+)((?:\s*(?:\*+|\bconst\b|\bG_CONST_RETURN\b))*)\s*$'
 % options.ignore_decorators, previous_line)
+                        if pm:
+                            ret_type = pm.group(1)
+                            if pm.group(2):
+                                ret_type += ' ' + pm.group(2)
+                            logging.info('Function (4): "%s", Returns: "%s"', symbol, ret_type)
+                            in_declaration = 'function'
 
             # Try to catch function declarations with the return type and name
             # on the previous line(s), and the start of the parameters on this.
-            } elsif (m/^\s*\(/) {
-                $decl = $';
-                if ($previous_line =~ 
m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|enum\s+)*\w+)(\s+\*+|\*+|\s)\s*([A-Za-z]\w*)\s*$/o)
 {
-                    $ret_type = "$1 $2";
-                    $symbol = $3;
-                    @TRACE@("Function (5): $symbol, Returns: $ret_type");
-                    $in_declaration = "function";
-
-                } elsif ($previous_line =~ m/^\s*\w+\s*$/
-                         && $pre_previous_line =~ 
m/^\s*(?:\b(?:extern|G_INLINE_FUNC|${IGNORE_DECORATORS})\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|struct\s+|union\s+|enum\s+)*\w+(?:\**\s+\**(?:const|G_CONST_RETURN))?(?:\s+|\s*\*+))\s*$/o)
 {
-                    $ret_type = $1;
-                    $ret_type =~ s/\s*\n//;
-                    $in_declaration = "function";
-
-                    $symbol = $previous_line;
-                    $symbol =~ s/^\s+//;
-                    $symbol =~ s/\s*\n//;
-                    @TRACE@("Function (6): $symbol, Returns: $ret_type");
-                }
+            elif m20:
+                decl = line[m20.end():]
+                pm = 
re.search(r'^\s*(?:\b(?:extern|G_INLINE_FUNC|%s)\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|enum\s+)*\w+)(\s+\*+|\*+|\s)\s*([A-Za-z]\w*)\s*$'
 % options.ignore_decorators, previous_line)
+                ppm = 
re.search(r'^\s*(?:\b(?:extern|G_INLINE_FUNC|%s)\s*)*((?:const\s+|G_CONST_RETURN\s+|signed\s+|unsigned\s+|struct\s+|union\s+|enum\s+)*\w+(?:\**\s+\**(?:const|G_CONST_RETURN))?(?:\s+|\s*\*+))\s*$'
 % options.ignore_decorators, pre_previous_line)
+                if pm:
+                    ret_type = pm.group(1) + ' ' + pm.group(2)
+                    symbol = pm.group(3)
+                    in_declaration = 'function'
+                    logging.info('Function (5): "%s", Returns: "%s"', symbol, ret_type)
+
+                elif re.search(r'^\s*\w+\s*$', previous_line) and ppm:
+                    ret_type = ppm.group(1)
+                    ret_type = re.sub(r'\s*\n', '', ret_type, flags=re.MULTILINE)
+                    in_declaration = 'function'
+
+                    symbol = previous_line
+                    symbol = re.sub(r'^\s+', '', symbol)
+                    symbol = re.sub(r'\s*\n', '', symbol, flags=re.MULTILINE)
+                    logging.info('Function (6): "%s", Returns: "%s"', symbol, ret_type)
 
             #} elsif (m/^extern\s+/) {
-                #print "DEBUG: Skipping extern: $_";
+                #print "DEBUG: Skipping extern: $_"
 
 
             # STRUCTS
 
-            } elsif (m/^\s*struct\s+_?(\w+)\s*\*/) {
+            elif re.search(r'^\s*struct\s+_?(\w+)\s*\*', line):
                 # Skip 'struct _<struct_name> *', since it could be a
                 # return type on its own line.
-
-            } elsif (m/^\s*struct\s+_?(\w+)/) {
+                pass
+            elif m21:
                 # We assume that 'struct _<struct_name>' is really the
                 # declaration of struct <struct_name>.
-                $symbol = $1;
-                $decl = $_;
-                 # we will find the correct level as below we do $level += tr/{//;
-                $level = 0;
-                $in_declaration = "struct";
-                @TRACE@("Struct(_): $symbol");
+                symbol = m21.group(1)
+                decl = line
+                 # we will find the correct level as below we do $level += tr/{//
+                level = 0
+                in_declaration = 'struct'
+                logging.info('Struct(_): "%s"', symbol)
 
 
             # UNIONS
 
-            } elsif (m/^\s*union\s+_(\w+)\s*\*/) {
-                    # Skip 'union _<union_name> *' (see above)
-            } elsif (m/^\s*union\s+_(\w+)/) {
-                $symbol = $1;
-                $decl = $_;
-                $level = 0;
-                $in_declaration = "union";
-                @TRACE@("Union(_): $symbol");
-            }
-
-        } else {
-            @TRACE@("1: [$skip_block] $_");
+            elif re.search(r'^\s*union\s+_(\w+)\s*\*', line):
+                # Skip 'union _<union_name> *' (see above)
+                pass
+            elif m22:
+                symbol = m22.group(1)
+                decl = line
+                level = 0
+                in_declaration = 'union'
+                logging.info('Union(_): "%s"', symbol)
+        else:
+            logging.info('in decl: skip=%s %s', skip_block, line.strip())
             # If we were already in the middle of a declaration, we simply add
             # the current line onto the end of it.
-            if ($skip_block == 0) {
-                $decl .= $_;
-            } else {
+            if skip_block == 0:
+                decl += line
+            else:
                 # Remove all nested pairs of curly braces.
-                while ($_ =~ s/{[^{]*}//g) { }
+                brace_remover = r'{[^{]*}'
+                bm = re.search(brace_remover, line)
+                while bm:
+                    line = re.sub(brace_remover, '', line)
+                    bm = re.search(brace_remover, line)
                 # Then hope at most one remains in the line...
-                if (m%(.*?){%) {
-                    if ($skip_block == 1) {
-                        $decl .= $1;
-                    }
-                    $skip_block += 1;
-                } elsif (m%}%) {
-                    $skip_block -= 1;
-                    if ($skip_block == 1) {
+                bm = re.search(r'(.*?){', line)
+                if bm:
+                    if skip_block == 1:
+                        decl += bm.group(1)
+                    skip_block += 1
+                elif '}' in line:
+                    skip_block -= 1
+                    if skip_block == 1:
                         # this is a hack to detect the end of declaration
-                        $decl .= ";";
-                        $skip_block = 0;
-                        @TRACE@("2: ---");
-                    }
-                } else {
-                    if ($skip_block == 1) {
-                        $decl .= $_;
-                    }
-                }
-            }
-        }
-
-        #if ($in_declaration ne '') {
-        #    print "$in_declaration = $decl\n";
-        #}
-
-        if ($in_declaration eq "g-declare") {
-            if ($decl =~ s/\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\).*$//) {
-                my $ModuleObjName = $1;
-                my $module_obj_name = $2;
-                if ($REBUILD_TYPES) {
-                    push (@get_types, "${module_obj_name}_get_type");
-                }
-                $forward_decls{$ModuleObjName} = 
"<STRUCT>\n<NAME>$ModuleObjName</NAME>\n$deprecated</STRUCT>\n";
-                if ($symbol =~ /^G_DECLARE_DERIVABLE/) {
-                    $forward_decls{"${ModuleObjName}Class"} = 
"<STRUCT>\n<NAME>${ModuleObjName}Class</NAME>\n$deprecated</STRUCT>\n";
-                }
-                if ($symbol =~ /^G_DECLARE_INTERFACE/) {
-                    $forward_decls{"${ModuleObjName}Interface"} = 
"<STRUCT>\n<NAME>${ModuleObjName}Interface</NAME>\n$deprecated</STRUCT>\n";
-                }
-                $in_declaration = "";
-            }
-        }
+                        decl += ';'
+                        skip_block = 0
+                        logging.info('2: ---')
+
+                else:
+                    if skip_block == 1:
+                        decl += line
+
+        if in_declaration == "g-declare":
+            dm = re.search(r'\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\).*$', decl)
+            # FIXME the original code does s// stuff here and we don't. Is it necessary?
+            if dm:
+                ModuleObjName = dm.group(1)
+                module_obj_name = dm.group(2)
+                if options.rebuild_types:
+                    get_types.append(module_obj_name + '_get_type')
+                forward_decls[ModuleObjName] = '<STRUCT>\n<NAME>%s</NAME>\n%s</STRUCT>\n' % (ModuleObjName, 
deprecated)
+                if symbol.startswith('G_DECLARE_DERIVABLE'):
+                    forward_decls[ModuleObjName + 'Class'] = '<STRUCT>\n<NAME>%sClass</NAME>\n%s</STRUCT>\n' 
% (ModuleObjName, deprecated)
+                if symbol.startswith('G_DECLARE_INTERFACE'):
+                    forward_decls[ModuleObjName + 'Interface'] = 
'<STRUCT>\n<NAME>%sInterface</NAME>\n%s</STRUCT>\n' % (ModuleObjName, deprecated)
+                in_declaration = ''
 
         # Note that sometimes functions end in ') G_GNUC_PRINTF (2, 3);' or
         # ') __attribute__ (...);'.
-        if ($in_declaration eq 'function') {
-            if ($decl =~ 
s/\)\s*(G_GNUC_.*|.*DEPRECATED.*|${IGNORE_DECORATORS}\s*|__attribute__\s*\(.*\)\s*)*;.*$//s) {
-                if ($internal == 0) {
-                     $decl =~ s%/\*.*?\*/%%gs;        # remove comments.
-                     #$decl =~ s/^\s+//;                # remove leading whitespace.
-                     #$decl =~ s/\s+$//;                # remove trailing whitespace.
-                     $decl =~ s/\s*\n\s*/ /gs;        # consolidate whitespace at start
-                                                   # and end of lines.
-                     $ret_type =~ s%/\*.*?\*/%%g;        # remove comments in ret type.
-                     if (&AddSymbolToList (\$list, $symbol)) {
-                         print DECL 
"<FUNCTION>\n<NAME>$symbol</NAME>\n$deprecated<RETURNS>$ret_type</RETURNS>\n$decl\n</FUNCTION>\n";
-                         if ($REBUILD_TYPES) {
+        if in_declaration == 'function':
+            regex = r'\)\s*(G_GNUC_.*|.*DEPRECATED.*|%s\s*|__attribute__\s*\(.*\)\s*)*;.*$' % 
options.ignore_decorators
+            pm = re.search(regex, decl, flags=re.MULTILINE)
+            if pm:
+                logging.info('scrubbing:[%s]', decl)
+                decl = re.sub(regex, '', decl, flags=re.MULTILINE)
+                logging.info('scrubbed:[%s]', decl)
+                if internal == 0:
+                     decl = re.sub(r'/\*.*?\*/', '', decl, flags=re.MULTILINE)   # remove comments.
+                     decl = re.sub(r'\s*\n\s*(?!$)', ' ', decl, flags=re.MULTILINE)  # consolidate 
whitespace at start/end of lines.
+                     decl = decl.strip()
+                     ret_type = re.sub(r'/\*.*?\*/', '', ret_type)               # remove comments in ret 
type.
+                     if AddSymbolToList(slist, symbol):
+                         
decl_list.append('<FUNCTION>\n<NAME>%s</NAME>\n%s<RETURNS>%s</RETURNS>\n%s\n</FUNCTION>\n' % (symbol, 
deprecated, ret_type, decl))
+                         if options.rebuild_types:
                              # check if this looks like a get_type function and if so remember
-                             if (($symbol =~ m/_get_type$/) && ($ret_type =~ m/GType/) && ($decl =~ 
m/^(void|)$/)) {
-                                 @TRACE@("Adding get-type: [$ret_type] [$symbol] [$decl]\tfrom $input_file");
-                                 push (@get_types, $symbol);
-                             }
-                         }
-                     }
-                } else {
-                     $internal = 0;
-                }
-                $deprecated_conditional_nest = int($deprecated_conditional_nest);
-                $in_declaration = "";
-                $skip_block = 0;
-            }
-        }
-
-        if ($in_declaration eq 'user_function') {
-            if ($decl =~ s/\).*$//) {
-                if (&AddSymbolToList (\$list, $symbol)) {
-                    print DECL 
"<USER_FUNCTION>\n<NAME>$symbol</NAME>\n$deprecated<RETURNS>$ret_type</RETURNS>\n$decl</USER_FUNCTION>\n";
-                }
-                $deprecated_conditional_nest = int($deprecated_conditional_nest);
-                $in_declaration = "";
-            }
-        }
-
-        if ($in_declaration eq 'macro') {
-            if ($decl !~ m/\\\s*$/) {
-                if ($internal == 0) {
-                    if (&AddSymbolToList (\$list, $symbol)) {
-                        print DECL "<MACRO>\n<NAME>$symbol</NAME>\n$deprecated$decl</MACRO>\n";
-                    }
-                } else {
-                    $internal = 0;
-                }
-                $deprecated_conditional_nest = int($deprecated_conditional_nest);
-                $in_declaration = "";
-            }
-        }
-
-        if ($in_declaration eq 'enum') {
-            if ($decl =~ m/\}\s*(\w+)?;\s*$/) {
-                if ($symbol eq "") {
-                    $symbol = $1;
-                }
-                if (&AddSymbolToList (\$list, $symbol)) {
-                    print DECL "<ENUM>\n<NAME>$symbol</NAME>\n$deprecated$decl</ENUM>\n";
-                }
-                $deprecated_conditional_nest = int($deprecated_conditional_nest);
-                $in_declaration = "";
-            }
-        }
+                             if symbol.endswith('_get_type') and 'GType' in ret_type and 
re.search(r'^(void|)$', decl):
+                                 logging.info("Adding get-type: [%s] [%s] [%s]\tfrom %s", ret_type, symbol, 
decl, input_file)
+                                 get_types.append(symbol)
+                else:
+                     internal = 0
+                deprecated_conditional_nest = int(deprecated_conditional_nest)
+                in_declaration = ''
+                skip_block = 0
+
+        if in_declaration == 'user_function':
+            if re.search(r'\).*$', decl):
+                decl = re.sub(r'\).*$', '', decl)
+                if AddSymbolToList(slist, symbol):
+                    
decl_list.append('<USER_FUNCTION>\n<NAME>%s</NAME>\n%s<RETURNS>%s</RETURNS>\n%s</USER_FUNCTION>\n' % (symbol, 
deprecated, ret_type, decl))
+                deprecated_conditional_nest = int(deprecated_conditional_nest)
+                in_declaration = ''
+
+        if in_declaration == 'macro':
+            if not re.search(r'\\\s*$', decl):
+                if internal == 0:
+                    if AddSymbolToList(slist, symbol):
+                        decl_list.append('<MACRO>\n<NAME>%s</NAME>\n%s%s</MACRO>\n' % (symbol, deprecated, 
decl))
+                else:
+                    internal = 0
+                deprecated_conditional_nest = int(deprecated_conditional_nest)
+                in_declaration = ''
+
+        if in_declaration == 'enum':
+            em = re.search(r'\}\s*(\w+)?;\s*$', decl)
+            if em:
+                if symbol == '':
+                    symbol = em.group(1)
+                if AddSymbolToList(slist, symbol):
+                    decl_list.append('<ENUM>\n<NAME>%s</NAME>\n%s%s</ENUM>\n' % (symbol, deprecated, decl))
+                deprecated_conditional_nest = int(deprecated_conditional_nest)
+                in_declaration = ''
 
         # We try to handle nested stucts/unions, but unmatched brackets in
         # comments will cause problems.
-        if ($in_declaration eq 'struct' or $in_declaration eq 'union') {
-            if (($level <= 1) && ($decl =~ m/\n\}\s*(\w*);\s*$/)) {
-                if ($symbol eq "") {
-                    $symbol = $1;
-                }
-
-                if ($symbol =~ m/^(\S+)(Class|Iface|Interface)\b/) {
-                    my $objectname = $1;
-                    @TRACE@("Found object: $1");
-                    $title = "<TITLE>$objectname</TITLE>\n";
-                    push (@objects, $objectname);
-                }
-                @TRACE@("Store struct: $symbol");
-                if (&AddSymbolToList (\$list, $symbol)) {
-                    my $structsym = uc $in_declaration;
-                    print DECL "<$structsym>\n<NAME>$symbol</NAME>\n$deprecated$decl</$structsym>\n";
-                    if (defined($forward_decls{$symbol})) {
-                        undef($forward_decls{$symbol});
-                    }
-                }
-                $deprecated_conditional_nest = int($deprecated_conditional_nest);
-                $in_declaration = "";
-            } else {
+        if in_declaration == 'struct' or in_declaration == 'union':
+            sm = re.search(r'\n\}\s*(\w*);\s*$', decl)
+            if level <= 1 and sm:
+                if symbol == '':
+                    symbol = sm.group(1)
+
+                bm = re.search(r'^(\S+)(Class|Iface|Interface)\b', symbol)
+                if bm:
+                    objectname = bm.group(1)
+                    logging.info('Found object: "%s"', objectname)
+                    title = '<TITLE>%s</TITLE>' % objectname
+
+                logging.info('Store struct: "%s"', symbol)
+                if AddSymbolToList(slist, symbol):
+                    structsym = in_declaration.upper()
+                    decl_list.append('<%s>\n<NAME>%s</NAME>\n%s%s</%s>\n' % (structsym, symbol, deprecated, 
decl, structsym))
+                    if symbol in forward_decls:
+                        del forward_decls[symbol]
+                deprecated_conditional_nest = int(deprecated_conditional_nest)
+                in_declaration = ''
+            else:
                 # We use tr to count the brackets in the line, and adjust
                 # $level accordingly.
-                $level += tr/{//;
-                $level -= tr/}//;
-                @TRACE@("struct/union level : $level");
-            }
-        }
+                level += line.count('{')
+                level -= line.count('}')
+                logging.info('struct/union level : %d', level)
 
-        $pre_previous_line = $previous_line;
-        $previous_line = $_;
-    }
-    close(INPUT);
+        pre_previous_line = previous_line
+        previous_line = line
 
     # print remaining forward declarations
-    foreach $symbol (sort(keys %forward_decls)) {
-        if (defined($forward_decls{$symbol})) {
-            &AddSymbolToList (\$list, $symbol);
-            print DECL $forward_decls{$symbol};
-        }
-    }
+    for symbol in sorted(forward_decls.keys()):
+        if forward_decls[symbol]:
+            AddSymbolToList(slist, symbol)
+            decl_list.append(forward_decls[symbol])
 
     # add title
-    $list = "$title$list";
+    slist = [title] + slist
 
-    @TRACE@("Scanning $input_file done\n");
+    logging.info("Scanning %s done", input_file)
 
     # Try to separate the standard macros and functions, placing them at the
     # end of the current section, in a subsection named 'Standard'.
     # do this in a loop to catch object, enums and flags
-    my ($class,$lclass,$prefix,$lprefix);
-    my ($standard_decl) = "";
-    do {
-        if ($list =~ m/^(\S+)_IS_(\S*)_CLASS\n/m) {
-            $prefix = $1;
-            $lprefix = lc($prefix);
-            $class = $2;
-            $lclass = lc($class);
-            @TRACE@("Found gobject type '${prefix}_$class' from is_class macro\n");
-        } elsif ($list =~ m/^(\S+)_IS_(\S*)\n/m) {
-            $prefix = $1;
-            $lprefix = lc($prefix);
-            $class = $2;
-            $lclass = lc($class);
-            @TRACE@("Found gobject type '${prefix}_$class' from is_ macro\n");
-        } elsif ($list =~ m/^(\S+?)_(\S*)_get_type\n/m) {
-            $lprefix = $1;
-            $prefix = uc($lprefix);
-            $lclass = $2;
-            $class = uc($lclass);
-            @TRACE@("Found gobject type '${prefix}_$class' from get_type function\n");
-        } else {
-          $class = $lclass = "";
-        }
-
-        if ($class ne "") {
-            my ($cclass) = $lclass;
-            $cclass =~ s/_//g;
-            my ($type) = $lprefix.$cclass;
-
-            if ($list =~ s/^${type}Private\n//im)               { $standard_decl .= $&; }
-
-            # We only leave XxYy* in the normal section if they have docs
-            if (! defined($doc_comments{$type})) {
-              @TRACE@("  Hide instance docs for $type");
-              if ($list =~ s/^${type}\n//im)                    { $standard_decl .= $&; }
-            }
-            if (! defined($doc_comments{$type."class"})) {
-              @TRACE@("  Hide class docs for $type");
-              if ($list =~ s/^${type}Class\n//im)               { $standard_decl .= $&; }
-            }
-            if (! defined($doc_comments{$type."interface"})) {
-              @TRACE@("  Hide iface docs for $type");
-              if ($list =~ s/^$type}Interface\n//im)            { $standard_decl .= $&; }
-            }
-            if (! defined($doc_comments{$type."iface"})) {
-              @TRACE@("  Hide iface docs for $type");
-              if ($list =~ s/${type}Iface\n//im)                { $standard_decl .= $&; }
-            }
-
-            while ($list =~ s/^\S+_IS_$class\n//m)              { $standard_decl .= $&; }
-            while ($list =~ s/^\S+_TYPE_$class\n//m)            { $standard_decl .= $&; }
-            while ($list =~ s/^\S+_${lclass}_get_type\n//m)     { $standard_decl .= $&; }
-            while ($list =~ s/^\S+_${class}_CLASS\n//m)         { $standard_decl .= $&; }
-            while ($list =~ s/^\S+_IS_${class}_CLASS\n//m)      { $standard_decl .= $&; }
-            while ($list =~ s/^\S+_${class}_GET_CLASS\n//m)     { $standard_decl .= $&; }
-            while ($list =~ s/^\S+_${class}_GET_IFACE\n//m)     { $standard_decl .= $&; }
-            while ($list =~ s/^\S+_${class}_GET_INTERFACE\n//m) { $standard_decl .= $&; }
-
-            # We do this one last, otherwise it tends to be caught by the IS_$class macro
-            while ($list =~ s/^\S+_$class\n//m)                 { $standard_decl .= $&; }
-
-            @TRACE@("Decl '".join(",",split("\n",$list))."'\n");
-            @TRACE@("Std  '".join(",",split("\n",$standard_decl))."'\n");
-        }
-    } while ($class ne "");
-    if ($standard_decl ne "") {
+    klass = lclass = prefix = lprefix = None
+    standard_decl = []
+    liststr = '\n'.join(s for s in slist if s) + '\n'
+    while True:
+        m = re.search(r'^(\S+)_IS_(\S*)_CLASS\n', liststr, flags=re.MULTILINE)
+        m2 = re.search(r'^(\S+)_IS_(\S*)\n', liststr, flags=re.MULTILINE)
+        m3 = re.search(r'^(\S+?)_(\S*)_get_type\n', liststr, flags=re.MULTILINE)
+        if m:
+            prefix = m.group(1)
+            lprefix = prefix.lower()
+            klass = m.group(2)
+            lclass = klass.lower()
+            logging.info("Found gobject type '%s_%s' from is_class macro", prefix, klass)
+        elif m2:
+            prefix = m2.group(1)
+            lprefix = prefix.lower()
+            klass = m2.group(2)
+            lclass = klass.lower()
+            logging.info("Found gobject type '%s_%s' from is_ macro", prefix, klass)
+        elif m3:
+            lprefix = m3.group(1)
+            prefix = lprefix.upper()
+            lclass = m3.group(2)
+            klass = lclass.upper()
+            logging.info("Found gobject type '%s_%s' from get_type function", prefix, klass)
+        else:
+            break
+
+        cclass = lclass
+        cclass = cclass.replace('_', '')
+        mtype = lprefix + cclass
+
+        liststr, standard_decl = replace_once(liststr, standard_decl, r'^%sPrivate\n' % mtype)
+
+        # We only leave XxYy* in the normal section if they have docs
+        if mtype not in doc_comments:
+            logging.info("  Hide instance docs for %s", mtype)
+            liststr, standard_decl = replace_once(liststr, standard_decl, r'^%s\n' % mtype)
+
+        if mtype + 'class' not in doc_comments:
+            logging.info("  Hide class docs for %s", mtype)
+            liststr, standard_decl = replace_once(liststr, standard_decl, r'^%sClass\n' % mtype)
+
+        if mtype + 'interface' not in doc_comments:
+            logging.info("  Hide iface docs for %s", mtype)
+            liststr, standard_decl = replace_once(liststr, standard_decl, r'%sInterface\n' % mtype)
+
+        if mtype + 'iface' not in doc_comments:
+            logging.info("  Hide iface docs for " + mtype)
+            liststr, standard_decl = replace_once(liststr, standard_decl, r'%sIface\n' % mtype)
+
+        liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_IS_%s\n' % klass)
+        liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_TYPE_%s\n' % klass)
+        liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_%s_get_type\n' % lclass)
+        liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_%s_CLASS\n' % klass)
+        liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_IS_%s_CLASS\n' % klass)
+        liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_%s_GET_CLASS\n' % klass)
+        liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_%s_GET_IFACE\n' % klass)
+        liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_%s_GET_INTERFACE\n' % klass)
+        # We do this one last, otherwise it tends to be caught by the IS_$class macro
+        liststr, standard_decl = replace_all(liststr, standard_decl, r'^\S+_%s\n' % klass)
+
+    logging.info('Decl:%s---', liststr)
+    logging.info('Std :%s---', ''.join(sorted(standard_decl)))
+    if len(standard_decl):
       # sort the symbols
-      $standard_decl=join("\n",sort(split("\n",$standard_decl)))."\n";
-      $list .= "<SUBSECTION Standard>\n$standard_decl";
-    }
-    if ($list ne "") {
-        $$section_list{$file_basename} .= "<SECTION>\n<FILE>$file_basename</FILE>\n$list</SECTION>\n\n";
-    }
-}
+      liststr += '<SUBSECTION Standard>\n' + ''.join(sorted(standard_decl))
+
+    if liststr != '':
+        if file_basename not in section_list:
+            section_list[file_basename] = ''
+        section_list[file_basename] += "<SECTION>\n<FILE>%s</FILE>\n%s</SECTION>\n\n" % (file_basename, 
liststr)
+
+
+def replace_once(liststr, standard_decl, regex):
+    mre = re.search(regex, liststr,  flags=re.IGNORECASE|re.MULTILINE)
+    if mre:
+        standard_decl.append(mre.group(0))
+        liststr = re.sub(regex, '', liststr, flags=re.IGNORECASE|re.MULTILINE)
+    return liststr, standard_decl
+
 
+def replace_all(liststr, standard_decl, regex):
+    mre = re.search(regex, liststr, flags=re.MULTILINE)
+    while mre:
+        standard_decl.append(mre.group(0))
+        liststr = re.sub(regex, '', liststr, flags=re.MULTILINE)
+        mre = re.search(regex, liststr, flags=re.MULTILINE)
+    return liststr, standard_decl
 
 #############################################################################
 # Function    : AddSymbolToList
@@ -979,16 +893,15 @@ sub ScanHeader {
 #                $symbol - the symbol to add to the list.
 #############################################################################
 
-sub AddSymbolToList {
-    my ($list, $symbol) = @_;
-
-    if ($$list =~ m/\b\Q$symbol\E\b/) {
-         #print "Symbol $symbol already in list. skipping\n";
-         # we return 0 to skip outputting another entry to -decl.txt
-         # this is to avoid redeclarations (e.g. in conditional
-         # sections).
-        return 0;
-    }
-    $$list .= "$symbol\n";
-    return 1;
-}
+def AddSymbolToList(slist, symbol):
+    if symbol in slist:
+         #logging.info('Symbol %s already in list. skipping', symbol)
+         # we return False to skip outputting another entry to -decl.txt
+         # this is to avoid redeclarations (e.g. in conditional sections).
+        return False
+    slist.append(symbol)
+    return True
+
+if __name__ == '__main__':
+    #logging.basicConfig(level=logging.INFO)
+    Run()
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 1a7b303..904e19a 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-fixxref.t gtkdoc-mkdb.t gtkdoc-scan.t \
+  gtkdoc-common.t gtkdoc-fixxref.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
@@ -23,7 +23,7 @@ endif
 
 EXTRA_DIST = gtkdoctest.sh tools.sh sanity.sh \
        gobject.sh bugs.sh annotations.sh fail.sh empty.sh \
-       gtkdoc-common.t gtkdoc-fixxref.t gtkdoc-mkdb.t gtkdoc-scan.t
+       gtkdoc-common.t gtkdoc-fixxref.t gtkdoc-mkdb.t
 
 
 # run any given test by running make <test>.check
diff --git a/tests/tools.sh.in b/tests/tools.sh.in
index 9661421..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-mkdb gtkdoc-scan 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]