[glibmm] Add h2defs.py and docextract_to_xml.py, removed from pygboject.



commit be04a6c229efb204f96dbf9b50359ffe1b5e7d17
Author: Murray Cumming <murrayc murrayc com>
Date:   Tue Jul 19 10:58:59 2011 +0200

    Add h2defs.py and docextract_to_xml.py, removed from pygboject.
    
    * tools/defs_gen/definitions.py:
    * tools/defs_gen/defsparser.py:
    * tools/defs_gen/docextract.py:
    * tools/defs_gen/docextract_to_xml.py:
    * tools/defs_gen/h2def.py:
    * tools/defs_gen/scmexpr.py: Add h2def.py and docextract_to_xml.py,
    and any .py files that they use, because they were removed from pygobject.
    * tools/Makefile.am: Add these to EXTRA_DIST.

 ChangeLog                           |   13 +
 tools/Makefile.am                   |    7 +
 tools/defs_gen/definitions.py       |  575 +++++++++++++++++++++++++++++++
 tools/defs_gen/defsparser.py        |  153 +++++++++
 tools/defs_gen/docextract.py        |  461 +++++++++++++++++++++++++
 tools/defs_gen/docextract_to_xml.py |  142 ++++++++
 tools/defs_gen/h2def.py             |  631 +++++++++++++++++++++++++++++++++++
 tools/defs_gen/scmexpr.py           |  143 ++++++++
 8 files changed, 2125 insertions(+), 0 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 2686864..81813ce 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2011-07-19  Murray Cumming  <murrayc murrayc com>
+
+	Add h2defs.py and docextract_to_xml.py, removed from pygboject.
+
+	* tools/defs_gen/definitions.py:
+	* tools/defs_gen/defsparser.py:
+	* tools/defs_gen/docextract.py:
+	* tools/defs_gen/docextract_to_xml.py:
+	* tools/defs_gen/h2def.py:
+	* tools/defs_gen/scmexpr.py: Add h2def.py and docextract_to_xml.py, 
+	and any .py files that they use, because they were removed from pygobject.
+	* tools/Makefile.am: Add these to EXTRA_DIST.
+	
 2011-07-18  Josà Alburquerque  <jaalburqu svn gnome org>
 
 	gmmproc: _STRUCT_NOT_HIDDEN: Make macro local to class only.
diff --git a/tools/Makefile.am b/tools/Makefile.am
index d3ada48..d5d0dc4 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -54,6 +54,13 @@ extra_defs_gen_generate_defs_gio_LDADD   = $(GIOMM_LIBS) $(lib_LTLIBRARIES)
 AM_CPPFLAGS = -I$(top_builddir) $(GTHREAD_CFLAGS) $(GIOMM_CFLAGS)
 AM_CXXFLAGS = $(GLIBMM_WXXFLAGS)
 
+EXTRA_DIST = defs_gen/definitions.py \
+  defs_gen/defsparser.py \
+  defs_gen/h2def.py \
+  defs_gen/scmexpr.py \
+  defs_gen/docextract.py \
+  defs_gen/docextract_to_xml.py
+
 # Instruct GNU make to delete the targets of a rule after it failed, in
 # order to avoid the complication of handling that situation manually.
 .DELETE_ON_ERROR:
diff --git a/tools/defs_gen/definitions.py b/tools/defs_gen/definitions.py
new file mode 100644
index 0000000..bfb6faf
--- /dev/null
+++ b/tools/defs_gen/definitions.py
@@ -0,0 +1,575 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+import copy
+import sys
+
+def get_valid_scheme_definitions(defs):
+    return [x for x in defs if isinstance(x, tuple) and len(x) >= 2]
+
+def unescape(s):
+    s = s.replace('\r\n', '\\r\\n').replace('\t', '\\t')
+    return s.replace('\r', '\\r').replace('\n', '\\n')
+
+def make_docstring(lines):
+    return "(char *) " + '\n'.join(['"%s"' % unescape(s) for s in lines])
+
+# New Parameter class, wich emulates a tuple for compatibility reasons
+class Parameter(object):
+    def __init__(self, ptype, pname, pdflt, pnull, pdir=None):
+        self.ptype = ptype
+        self.pname = pname
+        self.pdflt = pdflt
+        self.pnull = pnull
+        self.pdir = pdir
+
+    def __len__(self): return 4
+    def __getitem__(self, i):
+        return (self.ptype, self.pname, self.pdflt, self.pnull)[i]
+
+    def merge(self, old):
+        if old.pdflt is not None:
+            self.pdflt = old.pdflt
+        if old.pnull is not None:
+            self.pnull = old.pnull
+
+# We currently subclass 'str' to make impact on the rest of codegen as
+# little as possible.  Later we can subclass 'object' instead, but
+# then we must find and adapt all places which expect return types to
+# be strings.
+class ReturnType(str):
+    def __new__(cls, *args, **kwds):
+        return str.__new__(cls, *args[:1])
+    def __init__(self, type_name, optional=False):
+        str.__init__(self)
+        self.optional = optional
+
+# Parameter for property based constructors
+class Property(object):
+    def __init__(self, pname, optional, argname):
+        self.pname = pname
+        self.optional = optional
+        self.argname = argname
+
+    def __len__(self): return 4
+    def __getitem__(self, i):
+        return ('', self.pname, self.optional, self.argname)[i]
+
+    def merge(self, old):
+        if old.optional is not None:
+            self.optional = old.optional
+        if old.argname is not None:
+            self.argname = old.argname
+
+
+class Definition(object):
+    docstring = "NULL"
+
+    def py_name(self):
+        return '%s.%s' % (self.module, self.name)
+
+    py_name = property(py_name)
+
+    def __init__(self, *args):
+        """Create a new defs object of this type.  The arguments are the
+        components of the definition"""
+        raise RuntimeError("this is an abstract class")
+
+    def merge(self, old):
+        """Merge in customisations from older version of definition"""
+        raise RuntimeError("this is an abstract class")
+
+    def write_defs(self, fp=sys.stdout):
+        """write out this definition in defs file format"""
+        raise RuntimeError("this is an abstract class")
+
+    def guess_return_value_ownership(self):
+        "return 1 if caller owns return value"
+        if getattr(self, 'is_constructor_of', False):
+            self.caller_owns_return = True
+        elif self.ret in ('char*', 'gchar*', 'string'):
+            self.caller_owns_return = True
+        else:
+            self.caller_owns_return = False
+
+
+class ObjectDef(Definition):
+    def __init__(self, name, *args):
+        self.name = name
+        self.module = None
+        self.parent = None
+        self.c_name = None
+        self.typecode = None
+        self.fields = []
+        self.implements = []
+        self.class_init_func = None
+        self.has_new_constructor_api = False
+        for arg in get_valid_scheme_definitions(args):
+            if arg[0] == 'in-module':
+                self.module = arg[1]
+            elif arg[0] == 'docstring':
+                self.docstring = make_docstring(arg[1:])
+            elif arg[0] == 'parent':
+                self.parent = arg[1]
+            elif arg[0] == 'c-name':
+                self.c_name = arg[1]
+            elif arg[0] == 'gtype-id':
+                self.typecode = arg[1]
+            elif arg[0] == 'fields':
+                for parg in arg[1:]:
+                    self.fields.append((parg[0], parg[1]))
+            elif arg[0] == 'implements':
+                self.implements.append(arg[1])
+    def merge(self, old):
+        # currently the .h parser doesn't try to work out what fields of
+        # an object structure should be public, so we just copy the list
+        # from the old version ...
+        self.fields = old.fields
+        self.implements = old.implements
+    def write_defs(self, fp=sys.stdout):
+        fp.write('(define-object ' + self.name + '\n')
+        if self.module:
+            fp.write('  (in-module "' + self.module + '")\n')
+        if self.parent != (None, None):
+            fp.write('  (parent "' + self.parent + '")\n')
+        for interface in self.implements:
+            fp.write('  (implements "' + interface + '")\n')
+        if self.c_name:
+            fp.write('  (c-name "' + self.c_name + '")\n')
+        if self.typecode:
+            fp.write('  (gtype-id "' + self.typecode + '")\n')
+        if self.fields:
+            fp.write('  (fields\n')
+            for (ftype, fname) in self.fields:
+                fp.write('    \'("' + ftype + '" "' + fname + '")\n')
+            fp.write('  )\n')
+        fp.write(')\n\n')
+
+class InterfaceDef(Definition):
+    def __init__(self, name, *args):
+        self.name = name
+        self.module = None
+        self.c_name = None
+        self.typecode = None
+        self.vtable = None
+        self.fields = []
+        self.interface_info = None
+        for arg in get_valid_scheme_definitions(args):
+            if arg[0] == 'in-module':
+                self.module = arg[1]
+            elif arg[0] == 'docstring':
+                self.docstring = make_docstring(arg[1:])
+            elif arg[0] == 'c-name':
+                self.c_name = arg[1]
+            elif arg[0] == 'gtype-id':
+                self.typecode = arg[1]
+            elif arg[0] == 'vtable':
+                self.vtable = arg[1]
+        if self.vtable is None:
+            self.vtable = self.c_name + "Iface"
+    def write_defs(self, fp=sys.stdout):
+        fp.write('(define-interface ' + self.name + '\n')
+        if self.module:
+            fp.write('  (in-module "' + self.module + '")\n')
+        if self.c_name:
+            fp.write('  (c-name "' + self.c_name + '")\n')
+        if self.typecode:
+            fp.write('  (gtype-id "' + self.typecode + '")\n')
+        fp.write(')\n\n')
+
+class EnumDef(Definition):
+    def __init__(self, name, *args):
+        self.deftype = 'enum'
+        self.name = name
+        self.in_module = None
+        self.c_name = None
+        self.typecode = None
+        self.values = []
+        for arg in get_valid_scheme_definitions(args):
+            if arg[0] == 'in-module':
+                self.in_module = arg[1]
+            elif arg[0] == 'c-name':
+                self.c_name = arg[1]
+            elif arg[0] == 'gtype-id':
+                self.typecode = arg[1]
+            elif arg[0] == 'values':
+                for varg in arg[1:]:
+                    self.values.append((varg[0], varg[1]))
+    def merge(self, old):
+        pass
+    def write_defs(self, fp=sys.stdout):
+        fp.write('(define-' + self.deftype + ' ' + self.name + '\n')
+        if self.in_module:
+            fp.write('  (in-module "' + self.in_module + '")\n')
+        fp.write('  (c-name "' + self.c_name + '")\n')
+        fp.write('  (gtype-id "' + self.typecode + '")\n')
+        if self.values:
+            fp.write('  (values\n')
+            for name, val in self.values:
+                fp.write('    \'("' + name + '" "' + val + '")\n')
+            fp.write('  )\n')
+        fp.write(')\n\n')
+
+class FlagsDef(EnumDef):
+    def __init__(self, *args):
+        apply(EnumDef.__init__, (self,) + args)
+        self.deftype = 'flags'
+
+class BoxedDef(Definition):
+    def __init__(self, name, *args):
+        self.name = name
+        self.module = None
+        self.c_name = None
+        self.typecode = None
+        self.copy = None
+        self.release = None
+        self.fields = []
+        for arg in get_valid_scheme_definitions(args):
+            if arg[0] == 'in-module':
+                self.module = arg[1]
+            elif arg[0] == 'c-name':
+                self.c_name = arg[1]
+            elif arg[0] == 'gtype-id':
+                self.typecode = arg[1]
+            elif arg[0] == 'copy-func':
+                self.copy = arg[1]
+            elif arg[0] == 'release-func':
+                self.release = arg[1]
+            elif arg[0] == 'fields':
+                for parg in arg[1:]:
+                    self.fields.append((parg[0], parg[1]))
+    def merge(self, old):
+        # currently the .h parser doesn't try to work out what fields of
+        # an object structure should be public, so we just copy the list
+        # from the old version ...
+        self.fields = old.fields
+    def write_defs(self, fp=sys.stdout):
+        fp.write('(define-boxed ' + self.name + '\n')
+        if self.module:
+            fp.write('  (in-module "' + self.module + '")\n')
+        if self.c_name:
+            fp.write('  (c-name "' + self.c_name + '")\n')
+        if self.typecode:
+            fp.write('  (gtype-id "' + self.typecode + '")\n')
+        if self.copy:
+            fp.write('  (copy-func "' + self.copy + '")\n')
+        if self.release:
+            fp.write('  (release-func "' + self.release + '")\n')
+        if self.fields:
+            fp.write('  (fields\n')
+            for (ftype, fname) in self.fields:
+                fp.write('    \'("' + ftype + '" "' + fname + '")\n')
+            fp.write('  )\n')
+        fp.write(')\n\n')
+
+class PointerDef(Definition):
+    def __init__(self, name, *args):
+        self.name = name
+        self.module = None
+        self.c_name = None
+        self.typecode = None
+        self.fields = []
+        for arg in get_valid_scheme_definitions(args):
+            if arg[0] == 'in-module':
+                self.module = arg[1]
+            elif arg[0] == 'c-name':
+                self.c_name = arg[1]
+            elif arg[0] == 'gtype-id':
+                self.typecode = arg[1]
+            elif arg[0] == 'fields':
+                for parg in arg[1:]:
+                    self.fields.append((parg[0], parg[1]))
+    def merge(self, old):
+        # currently the .h parser doesn't try to work out what fields of
+        # an object structure should be public, so we just copy the list
+        # from the old version ...
+        self.fields = old.fields
+    def write_defs(self, fp=sys.stdout):
+        fp.write('(define-pointer ' + self.name + '\n')
+        if self.module:
+            fp.write('  (in-module "' + self.module + '")\n')
+        if self.c_name:
+            fp.write('  (c-name "' + self.c_name + '")\n')
+        if self.typecode:
+            fp.write('  (gtype-id "' + self.typecode + '")\n')
+        if self.fields:
+            fp.write('  (fields\n')
+            for (ftype, fname) in self.fields:
+                fp.write('    \'("' + ftype + '" "' + fname + '")\n')
+            fp.write('  )\n')
+        fp.write(')\n\n')
+
+class MethodDefBase(Definition):
+    def __init__(self, name, *args):
+        dump = 0
+        self.name = name
+        self.ret = None
+        self.caller_owns_return = None
+        self.unblock_threads = None
+        self.c_name = None
+        self.typecode = None
+        self.of_object = None
+        self.params = [] # of form (type, name, default, nullok)
+        self.varargs = 0
+        self.deprecated = None
+        for arg in get_valid_scheme_definitions(args):
+            if arg[0] == 'of-object':
+                self.of_object = arg[1]
+            elif arg[0] == 'docstring':
+                self.docstring = make_docstring(arg[1:])
+            elif arg[0] == 'c-name':
+                self.c_name = arg[1]
+            elif arg[0] == 'gtype-id':
+                self.typecode = arg[1]
+            elif arg[0] == 'return-type':
+                type_name = arg[1]
+                optional = False
+                for prop in arg[2:]:
+                    if prop[0] == 'optional':
+                        optional = True
+                self.ret = ReturnType(type_name, optional)
+            elif arg[0] == 'caller-owns-return':
+                self.caller_owns_return = arg[1] in ('t', '#t')
+            elif arg[0] == 'unblock-threads':
+                self.unblock_threads = arg[1] in ('t', '#t')
+            elif arg[0] == 'parameters':
+                for parg in arg[1:]:
+                    ptype = parg[0]
+                    pname = parg[1]
+                    pdflt = None
+                    pnull = 0
+                    pdir = None
+                    for farg in parg[2:]:
+                        assert isinstance(farg, tuple)
+                        if farg[0] == 'default':
+                            pdflt = farg[1]
+                        elif farg[0] == 'null-ok':
+                            pnull = 1
+                        elif farg[0] == 'direction':
+                            pdir = farg[1]
+                    self.params.append(Parameter(ptype, pname, pdflt, pnull, pdir))
+            elif arg[0] == 'varargs':
+                self.varargs = arg[1] in ('t', '#t')
+            elif arg[0] == 'deprecated':
+                self.deprecated = arg[1]
+            else:
+                sys.stderr.write("Warning: %s argument unsupported.\n"
+                                 % (arg[0]))
+                dump = 1
+        if dump:
+            self.write_defs(sys.stderr)
+
+        if self.caller_owns_return is None and self.ret is not None:
+            self.guess_return_value_ownership()
+
+    def merge(self, old, parmerge):
+        self.caller_owns_return = old.caller_owns_return
+        self.varargs = old.varargs
+        # here we merge extra parameter flags accross to the new object.
+        if not parmerge:
+            self.params = copy.deepcopy(old.params)
+            return
+        for i in range(len(self.params)):
+            ptype, pname, pdflt, pnull = self.params[i]
+            for p2 in old.params:
+                if p2[1] == pname:
+                    self.params[i] = (ptype, pname, p2[2], p2[3])
+                    break
+    def _write_defs(self, fp=sys.stdout):
+        if self.of_object != (None, None):
+            fp.write('  (of-object "' + self.of_object + '")\n')
+        if self.c_name:
+            fp.write('  (c-name "' + self.c_name + '")\n')
+        if self.typecode:
+            fp.write('  (gtype-id "' + self.typecode + '")\n')
+        if self.caller_owns_return:
+            fp.write('  (caller-owns-return #t)\n')
+        if self.unblock_threads:
+            fp.write('  (unblock_threads #t)\n')
+        if self.ret:
+            fp.write('  (return-type "' + self.ret + '")\n')
+        if self.deprecated:
+            fp.write('  (deprecated "' + self.deprecated + '")\n')
+        if self.params:
+            fp.write('  (parameters\n')
+            for ptype, pname, pdflt, pnull in self.params:
+                fp.write('    \'("' + ptype + '" "' + pname +'"')
+                if pdflt: fp.write(' (default "' + pdflt + '")')
+                if pnull: fp.write(' (null-ok)')
+                fp.write(')\n')
+            fp.write('  )\n')
+        if self.varargs:
+            fp.write('  (varargs #t)\n')
+        fp.write(')\n\n')
+
+
+class MethodDef(MethodDefBase):
+    def __init__(self, name, *args):
+        MethodDefBase.__init__(self, name, *args)
+        for item in ('c_name', 'of_object'):
+            if self.__dict__[item] == None:
+                self.write_defs(sys.stderr)
+                raise RuntimeError("definition missing required %s" % (item,))
+
+    def write_defs(self, fp=sys.stdout):
+        fp.write('(define-method ' + self.name + '\n')
+        self._write_defs(fp)
+
+class VirtualDef(MethodDefBase):
+    def write_defs(self, fp=sys.stdout):
+        fp.write('(define-virtual ' + self.name + '\n')
+        self._write_defs(fp)
+
+class FunctionDef(Definition):
+    def __init__(self, name, *args):
+        dump = 0
+        self.name = name
+        self.in_module = None
+        self.is_constructor_of = None
+        self.ret = None
+        self.caller_owns_return = None
+        self.unblock_threads = None
+        self.c_name = None
+        self.typecode = None
+        self.params = [] # of form (type, name, default, nullok)
+        self.varargs = 0
+        self.deprecated = None
+        for arg in get_valid_scheme_definitions(args):
+            if arg[0] == 'in-module':
+                self.in_module = arg[1]
+            elif arg[0] == 'docstring':
+                self.docstring = make_docstring(arg[1:])
+            elif arg[0] == 'is-constructor-of':
+                self.is_constructor_of = arg[1]
+            elif arg[0] == 'c-name':
+                self.c_name = arg[1]
+            elif arg[0] == 'gtype-id':
+                self.typecode = arg[1]
+            elif arg[0] == 'return-type':
+                self.ret = arg[1]
+            elif arg[0] == 'caller-owns-return':
+                self.caller_owns_return = arg[1] in ('t', '#t')
+            elif arg[0] == 'unblock-threads':
+                self.unblock_threads = arg[1] in ('t', '#t')
+            elif arg[0] == 'parameters':
+                for parg in arg[1:]:
+                    ptype = parg[0]
+                    pname = parg[1]
+                    pdflt = None
+                    pnull = 0
+                    for farg in parg[2:]:
+                        if farg[0] == 'default':
+                            pdflt = farg[1]
+                        elif farg[0] == 'null-ok':
+                            pnull = 1
+                    self.params.append(Parameter(ptype, pname, pdflt, pnull))
+            elif arg[0] == 'properties':
+                if self.is_constructor_of is None:
+                    print >> sys.stderr, "Warning: (properties ...) "\
+                          "is only valid for constructors"
+                for prop in arg[1:]:
+                    pname = prop[0]
+                    optional = False
+                    argname = pname
+                    for farg in prop[1:]:
+                        if farg[0] == 'optional':
+                            optional = True
+                        elif farg[0] == 'argname':
+                            argname = farg[1]
+                    self.params.append(Property(pname, optional, argname))
+            elif arg[0] == 'varargs':
+                self.varargs = arg[1] in ('t', '#t')
+            elif arg[0] == 'deprecated':
+                self.deprecated = arg[1]
+            else:
+                sys.stderr.write("Warning: %s argument unsupported\n"
+                                 % (arg[0],))
+                dump = 1
+        if dump:
+            self.write_defs(sys.stderr)
+
+        if self.caller_owns_return is None and self.ret is not None:
+            self.guess_return_value_ownership()
+        for item in ('c_name',):
+            if self.__dict__[item] == None:
+                self.write_defs(sys.stderr)
+                raise RuntimeError("definition missing required %s" % (item,))
+
+    _method_write_defs = MethodDef.__dict__['write_defs']
+
+    def merge(self, old, parmerge):
+        self.caller_owns_return = old.caller_owns_return
+        self.varargs = old.varargs
+        if not parmerge:
+            self.params = copy.deepcopy(old.params)
+            return
+        # here we merge extra parameter flags accross to the new object.
+        def merge_param(param):
+            for old_param in old.params:
+                if old_param.pname == param.pname:
+                    if isinstance(old_param, Property):
+                        # h2def never scans Property's, therefore if
+                        # we have one it was manually written, so we
+                        # keep it.
+                        return copy.deepcopy(old_param)
+                    else:
+                        param.merge(old_param)
+                        return param
+            raise RuntimeError("could not find %s in old_parameters %r" % (
+                param.pname, [p.pname for p in old.params]))
+        try:
+            self.params = map(merge_param, self.params)
+        except RuntimeError:
+            # parameter names changed and we can't find a match; it's
+            # safer to keep the old parameter list untouched.
+            self.params = copy.deepcopy(old.params)
+
+        if not self.is_constructor_of:
+            try:
+                self.is_constructor_of = old.is_constructor_of
+            except AttributeError:
+                pass
+        if isinstance(old, MethodDef):
+            self.name = old.name
+            # transmogrify from function into method ...
+            self.write_defs = self._method_write_defs
+            self.of_object = old.of_object
+            del self.params[0]
+    def write_defs(self, fp=sys.stdout):
+        fp.write('(define-function ' + self.name + '\n')
+        if self.in_module:
+            fp.write('  (in-module "' + self.in_module + '")\n')
+        if self.is_constructor_of:
+            fp.write('  (is-constructor-of "' + self.is_constructor_of +'")\n')
+        if self.c_name:
+            fp.write('  (c-name "' + self.c_name + '")\n')
+        if self.typecode:
+            fp.write('  (gtype-id "' + self.typecode + '")\n')
+        if self.caller_owns_return:
+            fp.write('  (caller-owns-return #t)\n')
+        if self.unblock_threads:
+            fp.write('  (unblock-threads #t)\n')
+        if self.ret:
+            fp.write('  (return-type "' + self.ret + '")\n')
+        if self.deprecated:
+            fp.write('  (deprecated "' + self.deprecated + '")\n')
+        if self.params:
+            if isinstance(self.params[0], Parameter):
+                fp.write('  (parameters\n')
+                for ptype, pname, pdflt, pnull in self.params:
+                    fp.write('    \'("' + ptype + '" "' + pname +'"')
+                    if pdflt: fp.write(' (default "' + pdflt + '")')
+                    if pnull: fp.write(' (null-ok)')
+                    fp.write(')\n')
+                fp.write('  )\n')
+            elif isinstance(self.params[0], Property):
+                fp.write('  (properties\n')
+                for prop in self.params:
+                    fp.write('    \'("' + prop.pname +'"')
+                    if prop.optional: fp.write(' (optional)')
+                    fp.write(')\n')
+                fp.write('  )\n')
+            else:
+                assert False, "strange parameter list %r" % self.params[0]
+        if self.varargs:
+            fp.write('  (varargs #t)\n')
+
+        fp.write(')\n\n')
diff --git a/tools/defs_gen/defsparser.py b/tools/defs_gen/defsparser.py
new file mode 100644
index 0000000..37ba0a2
--- /dev/null
+++ b/tools/defs_gen/defsparser.py
@@ -0,0 +1,153 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+import os, sys
+import scmexpr
+from definitions import BoxedDef, EnumDef, FlagsDef, FunctionDef, \
+     InterfaceDef, MethodDef, ObjectDef, PointerDef, VirtualDef
+
+include_path = ['.']
+
+class IncludeParser(scmexpr.Parser):
+    """A simple parser that follows include statements automatically"""
+    def include(self, input_filename):
+        global include_path
+        if os.path.isabs(input_filename):
+            filename = input_filename
+            # set self.filename to the include name, to handle recursive includes
+            oldfile = self.filename
+            self.filename = filename
+            self.startParsing()
+            self.filename = oldfile
+        else:
+            inc_path = [os.path.dirname(self.filename)] + include_path
+            for filename in [os.path.join(path_entry, input_filename)
+                             for path_entry in inc_path]:
+                if not os.path.exists(filename):
+                    continue
+                # set self.filename to the include name, to handle recursive includes
+                oldfile = self.filename
+                self.filename = filename
+                self.startParsing()
+                self.filename = oldfile
+                break
+            else:
+                raise IOError("%s not found in include path %s" % (input_filename, inc_path))
+
+class DefsParser(IncludeParser):
+    def __init__(self, arg, defines={}):
+        IncludeParser.__init__(self, arg)
+        self.objects = []
+        self.interfaces = []
+        self.enums = []      # enums and flags
+        self.boxes = []      # boxed types
+        self.pointers = []   # pointer types
+        self.functions = []  # functions and methods
+        self.virtuals = []   # virtual methods
+        self.c_name = {}     # hash of c names of functions
+        self.methods = {}    # hash of methods of particular objects
+        self.defines = defines      # -Dfoo=bar options, as dictionary
+
+    def define_object(self, *args):
+        odef = apply(ObjectDef, args)
+        self.objects.append(odef)
+        self.c_name[odef.c_name] = odef
+    def define_interface(self, *args):
+        idef = apply(InterfaceDef, args)
+        self.interfaces.append(idef)
+        self.c_name[idef.c_name] = idef
+    def define_enum(self, *args):
+        edef = apply(EnumDef, args)
+        self.enums.append(edef)
+        self.c_name[edef.c_name] = edef
+    def define_flags(self, *args):
+        fdef = apply(FlagsDef, args)
+        self.enums.append(fdef)
+        self.c_name[fdef.c_name] = fdef
+    def define_boxed(self, *args):
+        bdef = apply(BoxedDef, args)
+        self.boxes.append(bdef)
+        self.c_name[bdef.c_name] = bdef
+    def define_pointer(self, *args):
+        pdef = apply(PointerDef, args)
+        self.pointers.append(pdef)
+        self.c_name[pdef.c_name] = pdef
+    def define_function(self, *args):
+        fdef = apply(FunctionDef, args)
+        self.functions.append(fdef)
+        self.c_name[fdef.c_name] = fdef
+    def define_method(self, *args):
+        mdef = apply(MethodDef, args)
+        self.functions.append(mdef)
+        self.c_name[mdef.c_name] = mdef
+    def define_virtual(self, *args):
+        vdef = apply(VirtualDef, args)
+        self.virtuals.append(vdef)
+    def merge(self, old, parmerge):
+        for obj in self.objects:
+            if old.c_name.has_key(obj.c_name):
+                obj.merge(old.c_name[obj.c_name])
+        for f in self.functions:
+            if old.c_name.has_key(f.c_name):
+                f.merge(old.c_name[f.c_name], parmerge)
+
+    def printMissing(self, old):
+        for obj in self.objects:
+            if not old.c_name.has_key(obj.c_name):
+                obj.write_defs()
+        for f in self.functions:
+            if not old.c_name.has_key(f.c_name):
+                f.write_defs()
+
+    def write_defs(self, fp=sys.stdout):
+        for obj in self.objects:
+            obj.write_defs(fp)
+        for enum in self.enums:
+            enum.write_defs(fp)
+        for boxed in self.boxes:
+            boxed.write_defs(fp)
+        for pointer in self.pointers:
+            pointer.write_defs(fp)
+        for func in self.functions:
+            func.write_defs(fp)
+
+    def find_object(self, c_name):
+        for obj in self.objects:
+            if obj.c_name == c_name:
+                return obj
+        else:
+            raise ValueError('object %r not found' % c_name)
+
+    def find_constructor(self, obj, overrides):
+        for func in self.functions:
+            if isinstance(func, FunctionDef) and \
+               func.is_constructor_of == obj.c_name and \
+               not overrides.is_ignored(func.c_name):
+                return func
+
+    def find_methods(self, obj):
+        objname = obj.c_name
+        return filter(lambda func, on=objname: isinstance(func, MethodDef) and
+                      func.of_object == on, self.functions)
+
+    def find_virtuals(self, obj):
+        objname = obj.c_name
+        retval = filter(lambda func, on=objname: isinstance(func, VirtualDef) and
+                        func.of_object == on, self.virtuals)
+        return retval
+
+    def find_functions(self):
+        return filter(lambda func: isinstance(func, FunctionDef) and
+                      not func.is_constructor_of, self.functions)
+
+    def ifdef(self, *args):
+        if args[0] in self.defines:
+            for arg in args[1:]:
+                #print >> sys.stderr, "-----> Handling conditional definition (%s): %s" % (args[0], arg)
+                self.handle(arg)
+        else:
+            pass
+            #print >> sys.stderr, "-----> Conditional %s is not true" % (args[0],)
+
+    def ifndef(self, *args):
+        if args[0] not in self.defines:
+            for arg in args[1:]:
+                self.handle(arg)
diff --git a/tools/defs_gen/docextract.py b/tools/defs_gen/docextract.py
new file mode 100644
index 0000000..13beeff
--- /dev/null
+++ b/tools/defs_gen/docextract.py
@@ -0,0 +1,461 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+'''Simple module for extracting GNOME style doc comments from C
+sources, so I can use them for other purposes.'''
+
+import sys, os, string, re
+
+# Used to tell if the "Since: ..." portion of the gtkdoc function description
+# should be omitted.  This is useful for some C++ modules such as gstreamermm
+# that wrap C API which is still unstable and including this information would
+# not be useful.
+# This variable is modified from docextract_to_xml based on the --no-since
+# option being specified.
+no_since = False
+
+__all__ = ['extract']
+
+class GtkDoc:
+    def __init__(self):
+        self.name = None
+        self.block_type = '' # The block type ('function', 'signal', 'property')
+        self.params = []
+        self.annotations = []
+        self.description = ''
+        self.ret = ('', []) # (return, annotations)
+    def set_name(self, name):
+        self.name = name
+    def set_type(self, block_type):
+        self.block_type = block_type
+    def get_type(self):
+        return self.block_type
+    def add_param(self, name, description, annotations=[]):
+        if name == '...':
+            name = 'Varargs'
+        self.params.append((name, description, annotations))
+    def append_to_last_param(self, extra):
+        self.params[-1] = (self.params[-1][0], self.params[-1][1] + extra,
+            self.params[-1][2])
+    def append_to_named_param(self, name, extra):
+        for i in range(len(self.params)):
+            if self.params[i][0] == name:
+                self.params[i] = (name, self.params[i][1] + extra,
+                    self.params[i][2])
+                return
+        # fall through to adding extra parameter ...
+        self.add_param(name, extra)
+    def add_annotation(self, annotation):
+        self.annotations.append(annotation)
+    def get_annotations(self):
+        return self.annotations
+    def append_to_description(self, extra):
+        self.description = self.description + extra
+    def get_description(self):
+        return self.description
+    def add_return(self, first_line, annotations=[]):
+        self.ret = (first_line, annotations)
+    def append_to_return(self, extra):
+        self.ret = (self.ret[0] + extra, self.ret[1])
+
+comment_start_pattern = re.compile(r'^\s*/\*\*\s')
+comment_end_pattern = re.compile(r'^\s*\*+/')
+comment_line_lead_pattern = re.compile(r'^\s*\*\s*')
+comment_empty_line_pattern = re.compile(r'^\s*\**\s*$')
+function_name_pattern = re.compile(r'^([a-z]\w*)\s*:?(\s*\(.*\)\s*){0,2}\s*$')
+signal_name_pattern = re.compile(r'^([A-Z]\w+::[a-z0-9-]+)\s*:?(\s*\(.*\)\s*){0,2}\s*$')
+property_name_pattern = re.compile(r'^([A-Z]\w+:[a-z0-9-]+)\s*:?(\s*\(.*\)\s*){0,2}\s*$')
+return_pattern = re.compile(r'^ ?(returns:|return\s+value:)(.*\n?)$', re.IGNORECASE)
+deprecated_pattern = re.compile(r'^(deprecated\s*:\s*.*\n?)$', re.IGNORECASE)
+rename_to_pattern = re.compile(r'^(rename\s+to)\s*:\s*(.*\n?)$', re.IGNORECASE)
+param_pattern = re.compile(r'^@(\S+)\s*:(.*\n?)$')
+# Used to extract the annotations in the parameter and return descriptions
+# extracted using above [param|return]_pattern patterns.
+annotations_pattern = re.compile(r'^(?:(\s*\(.*\)\s*)*:)')
+# Used to construct the annotation lists.
+annotation_lead_pattern = re.compile(r'^\s*\(\s*(.*?)\s*\)\s*')
+
+# These patterns determine the identifier of the current comment block.  They
+# are grouped in a list for easy determination of block identifiers (in
+# skip_to_identifier).  The function_name_pattern should be tested for last
+# because it always matches signal and property identifiers.
+identifier_patterns = [ signal_name_pattern, property_name_pattern, function_name_pattern ]
+
+# This pattern is to match return sections that forget to have a colon (':')
+# after the initial 'Return' phrase.  It is not included by default in the list
+# of final sections below because a lot of function descriptions begin with
+# 'Returns ...' and the process_description() function would stop right at that
+# first line, thinking it is a return section.
+no_colon_return_pattern = re.compile(r'^ ?(returns|return\s+value)\s*(.*\n?)$', re.IGNORECASE)
+since_pattern = re.compile(r'^(since\s*:\s*.*\n?)$', re.IGNORECASE)
+
+# These patterns normally will be encountered after the description.  Knowing
+# the order of their appearance is difficult so this list is used to test when
+# one begins and the other ends when processing the rest of the sections after
+# the description.
+final_section_patterns = [ return_pattern, since_pattern, deprecated_pattern, rename_to_pattern ]
+
+def parse_file(fp, doc_dict):
+    line = fp.readline()
+    while line:
+        cur_doc = GtkDoc()
+        line = skip_to_comment_block(fp, line)
+        line = skip_to_identifier(fp, line, cur_doc)
+        # See if the identifier is found (stored in the current GtkDoc by
+        # skip_to_identifier).  If so, continue reading the rest of the comment
+        # block.
+        if cur_doc.name:
+            line = process_params(fp, line, cur_doc)
+            line = process_description(fp, line, cur_doc)
+            line = process_final_sections(fp, line, cur_doc)
+            # Add the current doc block to the dictionary of doc blocks.
+            doc_dict[cur_doc.name] = cur_doc
+
+# Given a list of annotations as string of the form 
+# '(annotation1) (annotation2) ...' return a list of annotations of the form
+# [ (name1, value1), (name2, value2) ... ].  Not all annotations have values so
+# the values in the list of tuples could be empty ('').
+def get_annotation_list(annotations):
+    annotation_list = []
+    while annotations:
+        match = annotation_lead_pattern.match(annotations)
+        if match:
+            annotation_contents = match.group(1)
+            name, split, value = annotation_contents.strip().partition(' ')
+            annotation_list.append((name, value))
+            # Remove first occurrence to continue processing.
+            annotations = annotation_lead_pattern.sub('', annotations)
+        else:
+            break
+    return annotation_list
+
+# Given a currently read line, test that line and continue reading until the
+# beginning of a comment block is found or eof is reached.  Return the last
+# read line.
+def skip_to_comment_block(fp, line):
+    while line:
+        if comment_start_pattern.match(line):
+            break
+        line = fp.readline()
+    return line
+
+# Given the current line in a comment block, continue skipping lines until a
+# non-blank line in the comment block is found or until the end of the block
+# (or eof) is reached.  Returns the line where reading stopped.
+def skip_to_nonblank(fp, line):
+    while line:
+        if not comment_empty_line_pattern.match(line):
+            break
+        line = fp.readline()
+        # Stop processing if eof or end of comment block is reached.
+        if not line or comment_end_pattern.match(line):
+            break
+    return line
+
+# Given the first line of a comment block (the '/**'), see if the next
+# non-blank line is the identifier of the comment block.  Stop processing if
+# the end of the block or eof is reached.  Store the identifier (if there is
+# one) and its type ('function', 'signal' or 'property') in the given GtkDoc.
+# Return the line where the identifier is found or the line that stops the
+# processing (if eof or the end of the comment block is found first).
+def skip_to_identifier(fp, line, cur_doc):
+    # Skip the initial comment block line ('/**') if not eof.
+    if line: line = fp.readline()
+
+    # Now skip empty lines.
+    line = skip_to_nonblank(fp, line)
+
+    # See if the first non-blank line is the identifier.
+    if line and not comment_end_pattern.match(line):
+        # Remove the initial ' * ' in comment block line and see if there is an
+        # identifier.
+        line = comment_line_lead_pattern.sub('', line)
+        for pattern in identifier_patterns:
+            match = pattern.match(line)
+            if match:
+                # Set the GtkDoc name.
+                cur_doc.set_name(match.group(1))
+                # Get annotations and add them to the GtkDoc.
+                annotations = get_annotation_list(match.group(2))
+                for annotation in annotations:
+                    cur_doc.add_annotation(annotation)
+                # Set the GtkDoc type.
+                if pattern == signal_name_pattern:
+                    cur_doc.set_type('signal')
+                elif pattern == property_name_pattern:
+                    cur_doc.set_type('property')
+                elif pattern == function_name_pattern:
+                    cur_doc.set_type('function')
+                return line
+    return line
+
+# Given a currently read line (presumably the identifier line), read the next
+# lines, testing to see if the lines are part of parameter descriptions.  If
+# so, store the parameter descriptions in the given doc block.  Stop on eof and
+# return the last line that stops the processing.
+def process_params(fp, line, cur_doc):
+    # Skip the identifier line if not eof.  Also skip any blank lines in the
+    # comment block.  Return if eof or the end of the comment block are
+    # encountered.
+    if line: line = fp.readline()
+    line = skip_to_nonblank(fp, line)
+    if not line or comment_end_pattern.match(line):
+        return line
+
+    # Remove initial ' * ' in first non-empty comment block line.
+    line = comment_line_lead_pattern.sub('', line)
+
+    # Now process possible parameters as long as no eof or the end of the
+    # param section is not reached (which could be triggered by anything that
+    # doesn't match a '@param:..." line, even the end of the comment block).
+    match = param_pattern.match(line)
+    while line and match:
+        description = match.group(2)
+
+        # First extract the annotations from the description and save them.
+        annotations = []
+        annotation_match = annotations_pattern.match(description)
+        if annotation_match:
+            annotations = get_annotation_list(annotation_match.group(1))
+            # Remove the annotations from the description
+            description = annotations_pattern.sub('', description)
+
+        # Default to appending lines to current parameter.
+        append_func = cur_doc.append_to_last_param
+
+        # See if the return has been included as part of the parameter
+        # section and make sure that lines are added to the GtkDoc return if
+        # so.
+        if match.group(1).lower() == "returns":
+            cur_doc.add_return(description, annotations)
+            append_func = cur_doc.append_to_return
+        # If not, just add it as a regular parameter.
+        else:
+            cur_doc.add_param(match.group(1), description, annotations)
+
+        # Now read lines and append them until next parameter, beginning of
+        # description (an empty line), the end of the comment block or eof.
+        line = fp.readline()
+        while line:
+            # Stop processing if end of comment block or a blank comment line
+            # is encountered.
+            if comment_empty_line_pattern.match(line) or \
+                    comment_end_pattern.match(line):
+                break
+
+            # Remove initial ' * ' in comment block line.
+            line = comment_line_lead_pattern.sub('', line)
+
+            # Break from current param processing if a new one is
+            # encountered.
+            if param_pattern.match(line): break;
+
+            # Otherwise, just append the current line and get the next line.
+            append_func(line)
+            line = fp.readline()
+
+        # Re-evaluate match for while condition
+        match = param_pattern.match(line)
+
+    # End by returning the current line.
+    return line
+
+# Having processed parameters, read the following lines into the description of
+# the current doc block until the end of the comment block, the end of file or
+# a return section is encountered.
+def process_description(fp, line, cur_doc):
+    # First skip empty lines returning on eof or end of comment block.
+    line = skip_to_nonblank(fp, line)
+    if not line or comment_end_pattern.match(line):
+        return line
+
+    # Remove initial ' * ' in non-empty comment block line.
+    line = comment_line_lead_pattern.sub('', line)
+
+    # Also remove possible 'Description:' prefix.
+    if line[:12] == 'Description:': line = line[12:]
+
+    # Used to tell if the previous line was blank and a return section
+    # uncommonly marked with 'Returns ...' instead of 'Returns: ...'  has
+    # started (assume it is non-empty to begin with).
+    prev_line = 'non-empty'
+
+    # Now read lines until a new section (like a return or a since section) is
+    # encountered.
+    while line:
+        # See if the description section has ended (if the line begins with
+        # 'Returns ...' and the previous line was empty -- this loop replaces
+        # empty lines with a newline).
+        if no_colon_return_pattern.match(line) and prev_line == '\n':
+            return line
+        # Or if one of the patterns of the final sections match
+        for pattern in final_section_patterns:
+            if pattern.match(line):
+                return line
+
+        # If not, append lines to description in the doc comment block.
+        cur_doc.append_to_description(line)
+
+        prev_line = line
+        line = fp.readline()
+
+        # Stop processing on eof or at the end of comment block.
+        if not line or comment_end_pattern.match(line):
+            return line
+
+        # Remove initial ' * ' in line so that the text can be appended to the
+        # description of the comment block and make sure that if the line is
+        # empty it be interpreted as a newline.
+        line = comment_line_lead_pattern.sub('', line)
+        if not line: line = '\n'
+
+# Given the line that ended the description (the first line of one of the final
+# sections) process the final sections ('Returns:', 'Since:', etc.) until the
+# end of the comment block or eof.  Return the line that ends the processing.
+def process_final_sections(fp, line, cur_doc):
+    while line and not comment_end_pattern.match(line):
+        # Remove leading ' * ' from current non-empty comment line.
+        line = comment_line_lead_pattern.sub('', line)
+        # Temporarily append the no colon return pattern to the final section
+        # patterns now that the description has been processed.  It will be
+        # removed after the for loop below executes so that future descriptions
+        # that begin with 'Returns ...' are not interpreted as a return
+        # section.
+        final_section_patterns.append(no_colon_return_pattern)
+        for pattern in final_section_patterns:
+            match = pattern.match(line)
+            if match:
+                if pattern == return_pattern or \
+                        pattern == no_colon_return_pattern:
+                    # Dealing with a 'Returns:' so first extract the
+                    # annotations from the description and save them.
+                    description = match.group(2)
+                    annotations = []
+                    annotation_match = \
+                            annotations_pattern.match(description)
+                    if annotation_match:
+                        annotations = \
+                                get_annotation_list(annotation_match.group(1))
+                        # Remove the annotations from the description
+                        description = annotations_pattern.sub('', description)
+
+                    # Now add the return.
+                    cur_doc.add_return(description, annotations)
+                    # In case more lines need to be appended.
+                    append_func = cur_doc.append_to_return
+                elif pattern == rename_to_pattern:
+                    # Dealing with a 'Rename to:' section (GObjectIntrospection
+                    # annotation) so no further lines will be appended but this
+                    # single one (and only to the annotations).
+                    append_func = None
+                    cur_doc.add_annotation((match.group(1),
+                            match.group(2)))
+                else:
+                    # For all others ('Since:' and 'Deprecated:') just append
+                    # the line to the description for now.
+                    # But if --no-since is specified, don't append it.
+                    if no_since and pattern == since_pattern:
+                        pass
+                    else:
+                        cur_doc.append_to_description(line)
+
+                    # In case more lines need to be appended.
+                    append_func = cur_doc.append_to_description
+
+                # Stop final section pattern matching for loop since a match
+                # has already been found.
+                break
+
+        # Remove the no colon return pattern (which was temporarily added in
+        # the just executed loop) from the list of final section patterns.
+        final_section_patterns.pop()
+
+        line = fp.readline()
+
+        # Now continue appending lines to current section until a new one is
+        # found or an eof or the end of the comment block is encountered.
+        finished = False
+        while not finished and line and \
+                not comment_end_pattern.match(line):
+            # Remove leading ' * ' from line and make sure that if it is empty,
+            # it be interpreted as a newline.
+            line = comment_line_lead_pattern.sub('', line)
+            if not line: line = '\n'
+
+            for pattern in final_section_patterns:
+                if pattern.match(line):
+                    finished = True
+                    break
+
+            # Break out of loop if a new section is found (determined in above
+            # inner loop).
+            if finished: break
+
+            # Now it's safe to append line.
+            if append_func: append_func(line)
+
+            # Get the next line to continue processing.
+            line = fp.readline()
+
+    return line
+
+def parse_dir(dir, doc_dict):
+    for file in os.listdir(dir):
+        if file in ('.', '..'): continue
+        path = os.path.join(dir, file)
+        if os.path.isdir(path):
+            parse_dir(path, doc_dict)
+        if len(file) > 2 and file[-2:] == '.c':
+            sys.stderr.write("Processing " + path + '\n')
+            parse_file(open(path, 'r'), doc_dict)
+
+def extract(dirs, doc_dict=None):
+    if not doc_dict: doc_dict = {}
+    for dir in dirs:
+        parse_dir(dir, doc_dict)
+    return doc_dict
+
+tmpl_section_pattern = re.compile(r'^<!-- ##### (\w+) (\w+) ##### -->$')
+def parse_tmpl(fp, doc_dict):
+    cur_doc = None
+
+    line = fp.readline()
+    while line:
+        match = tmpl_section_pattern.match(line)
+        if match:
+            cur_doc = None  # new input shouldn't affect the old doc dict
+            sect_type = match.group(1)
+            sect_name = match.group(2)
+
+            if sect_type == 'FUNCTION':
+                cur_doc = doc_dict.get(sect_name)
+                if not cur_doc:
+                    cur_doc = GtkDoc()
+                    cur_doc.set_name(sect_name)
+                    doc_dict[sect_name] = cur_doc
+        elif line == '<!-- # Unused Parameters # -->\n':
+            cur_doc = None # don't worry about unused params.
+        elif cur_doc:
+            if line[:10] == '@Returns: ':
+                if string.strip(line[10:]):
+                    cur_doc.append_to_return(line[10:])
+            elif line[0] == '@':
+                pos = string.find(line, ':')
+                if pos >= 0:
+                    cur_doc.append_to_named_param(line[1:pos], line[pos+1:])
+                else:
+                    cur_doc.append_to_description(line)
+            else:
+                cur_doc.append_to_description(line)
+
+        line = fp.readline()
+
+def extract_tmpl(dirs, doc_dict=None):
+    if not doc_dict: doc_dict = {}
+    for dir in dirs:
+        for file in os.listdir(dir):
+            if file in ('.', '..'): continue
+            path = os.path.join(dir, file)
+            if os.path.isdir(path):
+                continue
+            if len(file) > 2 and file[-2:] == '.sgml':
+                parse_tmpl(open(path, 'r'), doc_dict)
+    return doc_dict
diff --git a/tools/defs_gen/docextract_to_xml.py b/tools/defs_gen/docextract_to_xml.py
new file mode 100755
index 0000000..94b54b1
--- /dev/null
+++ b/tools/defs_gen/docextract_to_xml.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+#
+# This litte script outputs the C doc comments to an XML format.
+# So far it's only used by gtkmm (The C++ bindings). Murray Cumming.
+# Usage example:
+# # ./docextract_to_xml.py -s /gnome/head/cvs/gtk+/gtk/ -s /gnome/head/cvs/gtk+/docs/reference/gtk/tmpl/ > gtk_docs.xml
+
+import getopt
+import re
+import string
+import sys
+
+import docextract
+
+def usage():
+    sys.stderr.write('usage: docextract_to_xml.py ' +
+        '[-s /src/dir | --source-dir=/src/dir] ' +
+        '[-a | --with-annotations] [-p | --with-properties] ' +
+        '[-i | --with-signals ] [-n | --no-since]\n')
+    sys.exit(1)
+
+# Translates special texts to &... HTML acceptable format.  Also replace
+# occurrences of '/*' and '*/' with '/ *' and '* /' respectively to avoid
+# comment errors (note the spaces).  Some function descriptions include C++
+# multi-line comments which cause errors when the description is included in a
+# C++ Doxygen comment block.
+def escape_text(unescaped_text):
+    # Escape every "&" not part of an entity reference
+    escaped_text = re.sub(r'&(?![A-Za-z]+;)', '&amp;', unescaped_text)
+
+    # These weird entities turn up in the output...
+    escaped_text = string.replace(escaped_text, '&mdash;', '&#8212;')
+    escaped_text = string.replace(escaped_text, '&ast;', '*')
+    escaped_text = string.replace(escaped_text, '&percnt;', '%')
+    escaped_text = string.replace(escaped_text, '&commat;', '@')
+    escaped_text = string.replace(escaped_text, '&num;', '&#35;')
+    escaped_text = string.replace(escaped_text, '&nbsp;', '&#160;')
+    # This represents a '/' before or after an '*' so replace with slash but
+    # with spaces.
+    escaped_text = string.replace(escaped_text, '&sol;', ' / ')
+
+    # Escape for both tag contents and attribute values
+    escaped_text = string.replace(escaped_text, '<', '&lt;')
+    escaped_text = string.replace(escaped_text, '>', '&gt;')
+    escaped_text = string.replace(escaped_text, '"', '&quot;')
+
+    # Replace C++ comment begin and ends to ones that don't affect Doxygen.
+    escaped_text = string.replace(escaped_text, '/*', '/ *')
+    escaped_text = string.replace(escaped_text, '*/', '* /')
+
+    return escaped_text
+
+def print_annotations(annotations):
+    for annotation in annotations:
+        print "<annotation name=" + annotation[0] +  ">" + \
+                escape_text(annotation[1]) + "</annotation>"
+
+if __name__ == '__main__':
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "d:s:o:apin",
+                                   ["source-dir=", "with-annotations",
+                                     "with-properties", "with-signals",
+                                     "no-since"])
+    except getopt.error, e:
+        sys.stderr.write('docextract_to_xml.py: %s\n' % e)
+        usage()
+    source_dirs = []
+    with_annotations = False
+    with_signals = False
+    with_properties = False
+    for opt, arg in opts:
+        if opt in ('-s', '--source-dir'):
+            source_dirs.append(arg)
+        if opt in ('-a', '--with-annotations'):
+            with_annotations = True
+        if opt in ('-p', '--with-properties'):
+            with_properties = True
+        if opt in ('-i', '--with-signals'):
+            with_signals = True
+        if opt in ('-n', '--no-since'):
+            docextract.no_since = True
+    if len(args) != 0:
+        usage()
+
+    docs = docextract.extract(source_dirs);
+    docextract.extract_tmpl(source_dirs, docs); #Try the tmpl sgml files too.
+
+    # print d.docs
+
+    if docs:
+
+        print "<root>"
+
+        for name, value in sorted(docs.items()):
+            # Get the type of comment block ('function', 'signal' or
+            # 'property') (the value is a GtkDoc).
+            block_type = value.get_type()
+
+            # Skip signals if the option was not specified.
+            if block_type == 'signal' and not with_signals:
+                continue
+            # Likewise for properties.
+            elif block_type == 'property' and not with_properties:
+                continue
+
+            print "<" + block_type + " name=\"" + escape_text(name) + "\">"
+
+            print "<description>"
+            print escape_text(value.get_description())
+            print "</description>"
+
+            # Loop through the parameters if not dealing with a property:
+            if block_type != 'property':
+                print "<parameters>"
+                for name, description, annotations in value.params:
+                        print "<parameter name=\"" + escape_text(name) + "\">"
+                        print "<parameter_description>" + escape_text(description) + "</parameter_description>"
+
+                        if with_annotations:
+                            print_annotations(annotations)
+
+                        print "</parameter>"
+
+                print "</parameters>"
+
+                # Show the return-type (also if not dealing with a property):
+                if with_annotations:
+                    print "<return>"
+                    print "<return_description>" + escape_text(value.ret[0]) + \
+                            "</return_description>"
+                    print_annotations(value.ret[1])
+                    print "</return>"
+                else:
+                    print "<return>" + escape_text(value.ret[0]) + "</return>"
+
+            if with_annotations:
+                print_annotations(value.get_annotations())
+
+            print "</" + block_type + ">\n"
+
+        print "</root>"
diff --git a/tools/defs_gen/h2def.py b/tools/defs_gen/h2def.py
new file mode 100755
index 0000000..17617fa
--- /dev/null
+++ b/tools/defs_gen/h2def.py
@@ -0,0 +1,631 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# GPL'ed
+# Toby D. Reeves <toby max rl plh af mil>
+#
+# Modified by James Henstridge <james daa com au> to output stuff in
+# Havoc's new defs format.  Info on this format can be seen at:
+#   http://mail.gnome.org/archives/gtk-devel-list/2000-January/msg00070.html
+# Updated to be PEP-8 compatible and refactored to use OOP
+#
+# Scan the given public .h files of a GTK module (or module using
+# GTK object conventions) and generates a set of scheme defs.
+#
+# h2def searches through a header file looking for function prototypes and
+# generates a scheme style defenition for each prototype.
+# Basically the operation of h2def is:
+#
+# - read each .h file into a buffer which is scrubbed of extraneous data
+# - find all object defenitions:
+#   - find all structures that may represent a GtkObject
+#   - find all structures that might represent a class
+#   - find all structures that may represent a GtkObject subclass
+#   - find all structures that might represent a class/Iface inherited from
+#     GTypeInterface
+# - find all enum defenitions
+# - write out the defs
+#
+# The command line options are:
+#
+#   -s --separate    Create separate files for objects and function/method defs
+#                    using the given name as the base name (optional). If this
+#                    is not specified the combined object and function defs
+#                    will be output to sys.stdout.
+#   -f --defsfilter  Extract defs from the given file to filter the output defs
+#                    that is don't output defs that are defined in the
+#                    defsfile. More than one deffile may be specified.
+#   -m --modulename  The prefix to be stripped from the front of function names
+#                    for the given module
+#   -n --namespace   The module or namespace name to be used, for example
+#                    WebKit where h2def is unable to detect the module name
+#                    automatically. it also sets the gtype-id prefix.
+#   --onlyenums      Only produce defs for enums and flags
+#   --onlyobjdefs    Only produce defs for objects
+#   -v               Verbose output
+#
+# Examples:
+#
+# python h2def.py /usr/local/include/pango-1.0/pango/*.h >/tmp/pango.defs
+#
+# - Outputs all defs for the pango module.
+#
+# python h2def.py -m gdk -s /tmp/gdk-2.10 \
+#            -f /usr/tmp/pygtk/gtk/gdk-base.defs \
+#            /usr/local/include/gtk-2.0/gdk/*.h \
+#            /usr/local/include/gtk-2.0/gdk-pixbuf/*.h
+#
+# - Outputs the gdk module defs that are not contained in the defs file
+#   /usr/tmp/pygtk/gtk/gdk-base.defs. Two output files are created:
+#   /tmp/gdk-2.10-types.defs and /tmp/gdk-2.10.defs.
+#
+# python h2def.py -n WebKit /usr/incude/webkit-1.0/webkit/*.h \
+#            >/tmp/webkit.defs
+#
+# - Outputs all the defs for webkit module, setting the module name to WebKit
+#   and the gtype-id prefix to WEBKIT_ which can't be detected automatically.
+#
+
+import getopt
+import os
+import re
+import string
+import sys
+
+import defsparser
+
+# ------------------ Create typecodes from typenames ---------
+
+_upperstr_pat1 = re.compile(r'([^A-Z])([A-Z])')
+_upperstr_pat2 = re.compile(r'([A-Z][A-Z])([A-Z][0-9a-z])')
+_upperstr_pat3 = re.compile(r'^([A-Z])([A-Z])')
+
+def to_upper_str(name):
+    """Converts a typename to the equivalent upercase and underscores
+    name.  This is used to form the type conversion macros and enum/flag
+    name variables"""
+    name = _upperstr_pat1.sub(r'\1_\2', name)
+    name = _upperstr_pat2.sub(r'\1_\2', name)
+    name = _upperstr_pat3.sub(r'\1_\2', name, count=1)
+    return string.upper(name)
+
+def typecode(typename, namespace=None):
+    """create a typecode (eg. GTK_TYPE_WIDGET) from a typename"""
+    if namespace:
+      return string.replace(string.upper(namespace) + "_" + to_upper_str(typename[len(namespace):]), '_', '_TYPE_', 1)
+
+    return string.replace(to_upper_str(typename), '_', '_TYPE_', 1)
+
+
+# ------------------ Find object definitions -----------------
+# Strips the comments from buffer
+def strip_comments(buf):
+    parts = []
+    lastpos = 0
+    while 1:
+        pos = string.find(buf, '/*', lastpos)
+        if pos >= 0:
+            parts.append(buf[lastpos:pos])
+            pos = string.find(buf, '*/', pos)
+            if pos >= 0:
+                lastpos = pos + 2
+            else:
+                break
+        else:
+            parts.append(buf[lastpos:])
+            break
+    return string.join(parts, '')
+
+# Strips the dll API from buffer, for example WEBKIT_API
+def strip_dll_api(buf):
+    pat = re.compile("[A-Z]*_API ")
+    buf = pat.sub("", buf)
+    return buf
+
+obj_name_pat = "[A-Z][a-z]*[A-Z][A-Za-z0-9]*"
+
+split_prefix_pat = re.compile('([A-Z]+[a-z]*)([A-Za-z0-9]+)')
+
+def find_obj_defs(buf, objdefs=[]):
+    """
+    Try to find object definitions in header files.
+    """
+
+    # filter out comments from buffer.
+    buf = strip_comments(buf)
+
+    # filter out dll api
+    buf = strip_dll_api(buf)
+
+    maybeobjdefs = []  # contains all possible objects from file
+
+    # first find all structures that look like they may represent a GtkObject
+    pat = re.compile("struct\s+_(" + obj_name_pat + ")\s*{\s*" +
+                     "(" + obj_name_pat + ")\s+", re.MULTILINE)
+    pos = 0
+    while pos < len(buf):
+        m = pat.search(buf, pos)
+        if not m: break
+        maybeobjdefs.append((m.group(1), m.group(2)))
+        pos = m.end()
+
+    # handle typedef struct { ... } style struct defs.
+    pat = re.compile("typedef struct\s+[_\w]*\s*{\s*" +
+                     "(" + obj_name_pat + ")\s+[^}]*}\s*" +
+                     "(" + obj_name_pat + ")\s*;", re.MULTILINE)
+    pos = 0
+    while pos < len(buf):
+        m = pat.search(buf, pos)
+        if not m: break
+        maybeobjdefs.append((m.group(2), m.group(1)))
+        pos = m.end()
+
+    # now find all structures that look like they might represent a class:
+    pat = re.compile("struct\s+_(" + obj_name_pat + ")Class\s*{\s*" +
+                     "(" + obj_name_pat + ")Class\s+", re.MULTILINE)
+    pos = 0
+    while pos < len(buf):
+        m = pat.search(buf, pos)
+        if not m: break
+        t = (m.group(1), m.group(2))
+        # if we find an object structure together with a corresponding
+        # class structure, then we have probably found a GtkObject subclass.
+        if t in maybeobjdefs:
+            objdefs.append(t)
+        pos = m.end()
+
+    pat = re.compile("typedef struct\s+[_\w]*\s*{\s*" +
+                     "(" + obj_name_pat + ")Class\s+[^}]*}\s*" +
+                     "(" + obj_name_pat + ")Class\s*;", re.MULTILINE)
+    pos = 0
+    while pos < len(buf):
+        m = pat.search(buf, pos)
+        if not m: break
+        t = (m.group(2), m.group(1))
+        # if we find an object structure together with a corresponding
+        # class structure, then we have probably found a GtkObject subclass.
+        if t in maybeobjdefs:
+            objdefs.append(t)
+        pos = m.end()
+
+    # now find all structures that look like they might represent
+    # a class inherited from GTypeInterface:
+    pat = re.compile("struct\s+_(" + obj_name_pat + ")Class\s*{\s*" +
+                     "GTypeInterface\s+", re.MULTILINE)
+    pos = 0
+    while pos < len(buf):
+        m = pat.search(buf, pos)
+        if not m: break
+        t = (m.group(1), '')
+        t2 = (m.group(1)+'Class', 'GTypeInterface')
+        # if we find an object structure together with a corresponding
+        # class structure, then we have probably found a GtkObject subclass.
+        if t2 in maybeobjdefs:
+            objdefs.append(t)
+        pos = m.end()
+
+    # now find all structures that look like they might represent
+    # an Iface inherited from GTypeInterface:
+    pat = re.compile("struct\s+_(" + obj_name_pat + ")Iface\s*{\s*" +
+                     "GTypeInterface\s+", re.MULTILINE)
+    pos = 0
+    while pos < len(buf):
+        m = pat.search(buf, pos)
+        if not m: break
+        t = (m.group(1), '')
+        t2 = (m.group(1)+'Iface', 'GTypeInterface')
+        # if we find an object structure together with a corresponding
+        # class structure, then we have probably found a GtkObject subclass.
+        if t2 in maybeobjdefs:
+            objdefs.append(t)
+        pos = m.end()
+
+def sort_obj_defs(objdefs):
+    objdefs.sort()  # not strictly needed, but looks nice
+    pos = 0
+    while pos < len(objdefs):
+        klass,parent = objdefs[pos]
+        for i in range(pos+1, len(objdefs)):
+            # parent below subclass ... reorder
+            if objdefs[i][0] == parent:
+                objdefs.insert(i+1, objdefs[pos])
+                del objdefs[pos]
+                break
+        else:
+            pos = pos + 1
+    return objdefs
+
+# ------------------ Find enum definitions -----------------
+
+def find_enum_defs(buf, enums=[]):
+    # strip comments
+    # bulk comments
+    buf = strip_comments(buf)
+
+    # strip dll api macros
+    buf = strip_dll_api(buf)
+
+    # strip # directives
+    pat = re.compile(r"""^[#].*?$""", re.MULTILINE)
+    buf = pat.sub('', buf)
+
+    buf = re.sub('\n', ' ', buf)
+
+    enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)')
+    splitter = re.compile(r'\s*,\s', re.MULTILINE)
+    pos = 0
+    while pos < len(buf):
+        m = enum_pat.search(buf, pos)
+        if not m: break
+
+        name = m.group(2)
+        vals = m.group(1)
+        isflags = string.find(vals, '<<') >= 0
+        entries = []
+        for val in splitter.split(vals):
+            if not string.strip(val): continue
+            entries.append(string.split(val)[0])
+        if name != 'GdkCursorType':
+            enums.append((name, isflags, entries))
+
+        pos = m.end()
+
+# ------------------ Find function definitions -----------------
+
+def clean_func(buf):
+    """
+    Ideally would make buf have a single prototype on each line.
+    Actually just cuts out a good deal of junk, but leaves lines
+    where a regex can figure prototypes out.
+    """
+    # bulk comments
+    buf = strip_comments(buf)
+
+    # dll api
+    buf = strip_dll_api(buf)
+
+    # compact continued lines
+    pat = re.compile(r"""\\\n""", re.MULTILINE)
+    buf = pat.sub('', buf)
+
+    # Preprocess directives
+    pat = re.compile(r"""^[#].*?$""", re.MULTILINE)
+    buf = pat.sub('', buf)
+
+    #typedefs, stucts, and enums
+    pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""",
+                     re.MULTILINE)
+    buf = pat.sub('', buf)
+
+    #strip DECLS macros
+    pat = re.compile(r"""G_BEGIN_DECLS|BEGIN_LIBGTOP_DECLS""", re.MULTILINE)
+    buf = pat.sub('', buf)
+
+    #extern "C"
+    pat = re.compile(r"""^\s*(extern)\s+\"C\"\s+{""", re.MULTILINE)
+    buf = pat.sub('', buf)
+
+    #multiple whitespace
+    pat = re.compile(r"""\s+""", re.MULTILINE)
+    buf = pat.sub(' ', buf)
+
+    #clean up line ends
+    pat = re.compile(r""";\s*""", re.MULTILINE)
+    buf = pat.sub('\n', buf)
+    buf = buf.lstrip()
+
+    #associate *, &, and [] with type instead of variable
+    #pat = re.compile(r'\s+([*|&]+)\s*(\w+)')
+    pat = re.compile(r' \s* ([*|&]+) \s* (\w+)', re.VERBOSE)
+    buf = pat.sub(r'\1 \2', buf)
+    pat = re.compile(r'\s+ (\w+) \[ \s* \]', re.VERBOSE)
+    buf = pat.sub(r'[] \1', buf)
+
+    # make return types that are const work.
+    buf = re.sub(r'\s*\*\s*G_CONST_RETURN\s*\*\s*', '** ', buf)
+    buf = string.replace(buf, 'G_CONST_RETURN ', 'const-')
+    buf = string.replace(buf, 'const ', 'const-')
+
+    #strip GSEAL macros from the middle of function declarations:
+    pat = re.compile(r"""GSEAL""", re.VERBOSE)
+    buf = pat.sub('', buf)
+
+    return buf
+
+proto_pat=re.compile(r"""
+(?P<ret>(-|\w|\&|\*)+\s*)  # return type
+\s+                   # skip whitespace
+(?P<func>\w+)\s*[(]   # match the function name until the opening (
+\s*(?P<args>.*?)\s*[)]     # group the function arguments
+""", re.IGNORECASE|re.VERBOSE)
+#"""
+arg_split_pat = re.compile("\s*,\s*")
+
+get_type_pat = re.compile(r'(const-)?([A-Za-z0-9]+)\*?\s+')
+pointer_pat = re.compile('.*\*$')
+func_new_pat = re.compile('(\w+)_new$')
+
+class DefsWriter:
+    def __init__(self, fp=None, prefix=None, ns=None, verbose=False,
+                 defsfilter=None):
+        if not fp:
+            fp = sys.stdout
+
+        self.fp = fp
+        self.prefix = prefix
+        self.namespace = ns
+        self.verbose = verbose
+
+        self._enums = {}
+        self._objects = {}
+        self._functions = {}
+        if defsfilter:
+            filter = defsparser.DefsParser(defsfilter)
+            filter.startParsing()
+            for func in filter.functions + filter.methods.values():
+                self._functions[func.c_name] = func
+            for obj in filter.objects + filter.boxes + filter.interfaces:
+                self._objects[obj.c_name] = obj
+            for obj in filter.enums:
+                self._enums[obj.c_name] = obj
+
+    def write_def(self, deffile):
+        buf = open(deffile).read()
+
+        self.fp.write('\n;; From %s\n\n' % os.path.basename(deffile))
+        self._define_func(buf)
+        self.fp.write('\n')
+
+    def write_enum_defs(self, enums, fp=None):
+        if not fp:
+            fp = self.fp
+
+        fp.write(';; Enumerations and flags ...\n\n')
+        trans = string.maketrans(string.uppercase + '_',
+                                 string.lowercase + '-')
+        filter = self._enums
+        for cname, isflags, entries in enums:
+            if filter:
+                if cname in filter:
+                    continue
+            name = cname
+            module = None
+            if self.namespace:
+                module = self.namespace
+                name = cname[len(self.namespace):]
+            else:
+                m = split_prefix_pat.match(cname)
+                if m:
+                    module = m.group(1)
+                    name = m.group(2)
+            if isflags:
+                fp.write('(define-flags ' + name + '\n')
+            else:
+                fp.write('(define-enum ' + name + '\n')
+            if module:
+                fp.write('  (in-module "' + module + '")\n')
+            fp.write('  (c-name "' + cname + '")\n')
+            fp.write('  (gtype-id "' + typecode(cname, self.namespace) + '")\n')
+            prefix = entries[0]
+            for ent in entries:
+                # shorten prefix til we get a match ...
+                # and handle GDK_FONT_FONT, GDK_FONT_FONTSET case
+                while ((len(prefix) and prefix[-1] != '_') or ent[:len(prefix)] != prefix
+                       or len(prefix) >= len(ent)):
+                    prefix = prefix[:-1]
+            prefix_len = len(prefix)
+            fp.write('  (values\n')
+            for ent in entries:
+                fp.write('    \'("%s" "%s")\n' %
+                         (string.translate(ent[prefix_len:], trans), ent))
+            fp.write('  )\n')
+            fp.write(')\n\n')
+
+    def write_obj_defs(self, objdefs, fp=None):
+        if not fp:
+            fp = self.fp
+
+        fp.write(';; -*- scheme -*-\n')
+        fp.write('; object definitions ...\n')
+
+        filter = self._objects
+        for klass, parent in objdefs:
+            if filter:
+                if klass in filter:
+                    continue
+            if self.namespace:
+                cname = klass[len(self.namespace):]
+                cmodule = self.namespace
+            else:
+                m = split_prefix_pat.match(klass)
+                cname = klass
+                cmodule = None
+                if m:
+                    cmodule = m.group(1)
+                    cname = m.group(2)
+            fp.write('(define-object ' + cname + '\n')
+            if cmodule:
+                fp.write('  (in-module "' + cmodule + '")\n')
+            if parent:
+                fp.write('  (parent "' + parent + '")\n')
+            fp.write('  (c-name "' + klass + '")\n')
+            fp.write('  (gtype-id "' + typecode(klass, self.namespace) + '")\n')
+            # should do something about accessible fields
+            fp.write(')\n\n')
+
+    def _define_func(self, buf):
+        buf = clean_func(buf)
+        buf = string.split(buf,'\n')
+        filter = self._functions
+        for p in buf:
+            if not p:
+                continue
+            m = proto_pat.match(p)
+            if m == None:
+                if self.verbose:
+                    sys.stderr.write('No match:|%s|\n' % p)
+                continue
+            func = m.group('func')
+            if func[0] == '_':
+                continue
+            if filter:
+                if func in filter:
+                    continue
+            ret = m.group('ret')
+            args = m.group('args')
+            args = arg_split_pat.split(args)
+            for i in range(len(args)):
+                spaces = string.count(args[i], ' ')
+                if spaces > 1:
+                    args[i] = string.replace(args[i], ' ', '-', spaces - 1)
+
+            self._write_func(func, ret, args)
+
+    def _write_func(self, name, ret, args):
+        if len(args) >= 1:
+            # methods must have at least one argument
+            munged_name = name.replace('_', '')
+            m = get_type_pat.match(args[0])
+            if m:
+                obj = m.group(2)
+                if munged_name[:len(obj)] == obj.lower():
+                    self._write_method(obj, name, ret, args)
+                    return
+
+        if self.prefix:
+            l = len(self.prefix)
+            if name[:l] == self.prefix and name[l] == '_':
+                fname = name[l+1:]
+            else:
+                fname = name
+        else:
+            fname = name
+
+        # it is either a constructor or normal function
+        self.fp.write('(define-function ' + fname + '\n')
+        self.fp.write('  (c-name "' + name + '")\n')
+
+        # Hmmm... Let's asume that a constructor function name
+        # ends with '_new' and it returns a pointer.
+        m = func_new_pat.match(name)
+        if pointer_pat.match(ret) and m:
+            cname = ''
+            for s in m.group(1).split ('_'):
+                cname += s.title()
+            if cname != '':
+                self.fp.write('  (is-constructor-of "' + cname + '")\n')
+
+        self._write_return(ret)
+        self._write_arguments(args)
+
+    def _write_method(self, obj, name, ret, args):
+        regex = string.join(map(lambda x: x+'_?', string.lower(obj)),'')
+        mname = re.sub(regex, '', name, 1)
+        if self.prefix:
+            l = len(self.prefix) + 1
+            if mname[:l] == self.prefix and mname[l+1] == '_':
+                mname = mname[l+1:]
+        self.fp.write('(define-method ' + mname + '\n')
+        self.fp.write('  (of-object "' + obj + '")\n')
+        self.fp.write('  (c-name "' + name + '")\n')
+        self._write_return(ret)
+        self._write_arguments(args[1:])
+
+    def _write_return(self, ret):
+        if ret != 'void':
+            self.fp.write('  (return-type "' + ret + '")\n')
+        else:
+            self.fp.write('  (return-type "none")\n')
+
+    def _write_arguments(self, args):
+        is_varargs = 0
+        has_args = len(args) > 0
+        for arg in args:
+            if arg == '...':
+                is_varargs = 1
+            elif arg in ('void', 'void '):
+                has_args = 0
+        if has_args:
+            self.fp.write('  (parameters\n')
+            for arg in args:
+                if arg != '...':
+                    tupleArg = tuple(string.split(arg))
+                    if len(tupleArg) == 2:
+                        self.fp.write('    \'("%s" "%s")\n' % tupleArg)
+            self.fp.write('  )\n')
+        if is_varargs:
+            self.fp.write('  (varargs #t)\n')
+        self.fp.write(')\n\n')
+
+# ------------------ Main function -----------------
+
+def main(args):
+    verbose = False
+    onlyenums = False
+    onlyobjdefs = False
+    separate = False
+    modulename = None
+    namespace = None
+    defsfilter = None
+    opts, args = getopt.getopt(args[1:], 'vs:m:n:f:',
+                               ['onlyenums', 'onlyobjdefs',
+                                'modulename=', 'namespace=',
+                                'separate=', 'defsfilter='])
+    for o, v in opts:
+        if o == '-v':
+            verbose = True
+        if o == '--onlyenums':
+            onlyenums = True
+        if o == '--onlyobjdefs':
+            onlyobjdefs = True
+        if o in ('-s', '--separate'):
+            separate = v
+        if o in ('-m', '--modulename'):
+            modulename = v
+        if o in ('-n', '--namespace'):
+            namespace = v
+        if o in ('-f', '--defsfilter'):
+            defsfilter = v
+
+    if not args[0:1]:
+        print 'Must specify at least one input file name'
+        return -1
+
+    # read all the object definitions in
+    objdefs = []
+    enums = []
+    for filename in args:
+        buf = open(filename).read()
+        find_obj_defs(buf, objdefs)
+        find_enum_defs(buf, enums)
+    objdefs = sort_obj_defs(objdefs)
+
+    if separate:
+        methods = file(separate + '.defs', 'w')
+        types = file(separate + '-types.defs', 'w')
+
+        dw = DefsWriter(methods, prefix=modulename, ns=namespace,
+                        verbose=verbose, defsfilter=defsfilter)
+        dw.write_obj_defs(objdefs, types)
+        dw.write_enum_defs(enums, types)
+        print "Wrote %s-types.defs" % separate
+
+        for filename in args:
+            dw.write_def(filename)
+        print "Wrote %s.defs" % separate
+    else:
+        dw = DefsWriter(prefix=modulename, ns=namespace,
+                        verbose=verbose, defsfilter=defsfilter)
+
+        if onlyenums:
+            dw.write_enum_defs(enums)
+        elif onlyobjdefs:
+            dw.write_obj_defs(objdefs)
+        else:
+            dw.write_obj_defs(objdefs)
+            dw.write_enum_defs(enums)
+
+            for filename in args:
+                dw.write_def(filename)
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
diff --git a/tools/defs_gen/scmexpr.py b/tools/defs_gen/scmexpr.py
new file mode 100755
index 0000000..02f2e4b
--- /dev/null
+++ b/tools/defs_gen/scmexpr.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+from __future__ import generators
+
+import string
+from cStringIO import StringIO
+
+class error(Exception):
+    def __init__(self, filename, lineno, msg):
+        Exception.__init__(self, msg)
+        self.filename = filename
+        self.lineno = lineno
+        self.msg = msg
+    def __str__(self):
+        return '%s:%d: error: %s' % (self.filename, self.lineno, self.msg)
+
+trans = [' '] * 256
+for i in range(256):
+    if chr(i) in string.letters + string.digits + '_':
+        trans[i] = chr(i)
+    else:
+        trans[i] = '_'
+trans = string.join(trans, '')
+
+def parse(filename):
+    if isinstance(filename, str):
+        fp = open(filename, 'r')
+    else: # if not string, assume it is some kind of iterator
+        fp = filename
+        filename = getattr(fp, 'name', '<unknown>')
+    whitespace = ' \t\n\r\x0b\x0c'
+    nonsymbol = whitespace + '();\'"'
+    stack = []
+    openlines = []
+    lineno = 0
+    for line in fp:
+        pos = 0
+        lineno += 1
+        while pos < len(line):
+            if line[pos] in whitespace: # ignore whitespace
+                pass
+            elif line[pos] == ';': # comment
+                break
+            elif line[pos:pos+2] == "'(":
+                pass # the open parenthesis will be handled next iteration
+            elif line[pos] == '(':
+                stack.append(())
+                openlines.append(lineno)
+            elif line[pos] == ')':
+                if len(stack) == 0:
+                    raise error(filename, lineno, 'close parenthesis found when none open')
+                closed = stack[-1]
+                del stack[-1]
+                del openlines[-1]
+                if stack:
+                    stack[-1] += (closed,)
+                else:
+                    yield closed
+            elif line[pos] == '"': # quoted string
+                if not stack:
+                    raise error(filename, lineno,
+                                'string found outside of s-expression')
+                endpos = pos + 1
+                chars = []
+                while endpos < len(line):
+                    if endpos+1 < len(line) and line[endpos] == '\\':
+                        endpos += 1
+                        if line[endpos] == 'n':
+                            chars.append('\n')
+                        elif line[endpos] == 'r':
+                            chars.append('\r')
+                        elif line[endpos] == 't':
+                            chars.append('\t')
+                        else:
+                            chars.append('\\')
+                            chars.append(line[endpos])
+                    elif line[endpos] == '"':
+                        break
+                    else:
+                        chars.append(line[endpos])
+                    endpos += 1
+                if endpos >= len(line):
+                    raise error(filename, lineno, "unclosed quoted string")
+                pos = endpos
+                stack[-1] += (''.join(chars),)
+            else: # symbol/number
+                if not stack:
+                    raise error(filename, lineno,
+                                'identifier found outside of s-expression')
+                endpos = pos
+                while endpos < len(line) and line[endpos] not in nonsymbol:
+                    endpos += 1
+                symbol = line[pos:endpos]
+                pos = max(pos, endpos-1)
+                try: symbol = int(symbol)
+                except ValueError:
+                    try: symbol = float(symbol)
+                    except ValueError: pass
+                stack[-1] += (symbol,)
+            pos += 1
+    if len(stack) != 0:
+        msg = '%d unclosed parentheses found at end of ' \
+              'file (opened on line(s) %s)' % (len(stack),
+                                               ', '.join(map(str, openlines)))
+        raise error(filename, lineno, msg)
+
+class Parser:
+    def __init__(self, filename):
+        """Argument is either a string, a parse tree, or file object"""
+        self.filename = filename
+    def startParsing(self, filename=None):
+        statements = parse(filename or self.filename)
+        for statement in statements:
+            self.handle(statement)
+    def handle(self, tup):
+        cmd = string.translate(tup[0], trans)
+        if hasattr(self, cmd):
+            getattr(self, cmd)(*tup[1:])
+        else:
+            self.unknown(tup)
+    def unknown(self, tup):
+        pass
+
+_testString = """; a scheme file
+(define-func gdk_font_load    ; a comment at end of line
+  GdkFont
+  ((string name)))
+
+(define-boxed GdkEvent
+  gdk_event_copy
+  gdk_event_free
+  "sizeof(GdkEvent)")
+"""
+
+if __name__ == '__main__':
+    import sys
+    if sys.argv[1:]:
+        fp = open(sys.argv[1])
+    else:
+        fp = StringIO(_testString)
+    statements = parse(fp)
+    for s in statements:
+        print `s`



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