Add codegen to the tracked files
authorMathieu Duponchelle <seeed@laposte.net>
Tue, 7 Jun 2011 00:26:20 +0000 (02:26 +0200)
committerThibault Saunier <thibault.saunier@collabora.com>
Wed, 10 Aug 2011 15:12:45 +0000 (17:12 +0200)
14 files changed:
bindings/python/codegen/__init__.py [new file with mode: 0644]
bindings/python/codegen/argtypes.py [new file with mode: 0644]
bindings/python/codegen/code-coverage.py [new file with mode: 0755]
bindings/python/codegen/codegen.py [new file with mode: 0644]
bindings/python/codegen/definitions.py [new file with mode: 0644]
bindings/python/codegen/defsparser.py [new file with mode: 0644]
bindings/python/codegen/docextract.py [new file with mode: 0644]
bindings/python/codegen/docgen.py [new file with mode: 0644]
bindings/python/codegen/h2def.py [new file with mode: 0755]
bindings/python/codegen/mergedefs.py [new file with mode: 0755]
bindings/python/codegen/mkskel.py [new file with mode: 0755]
bindings/python/codegen/override.py [new file with mode: 0644]
bindings/python/codegen/reversewrapper.py [new file with mode: 0644]
bindings/python/codegen/scmexpr.py [new file with mode: 0644]

diff --git a/bindings/python/codegen/__init__.py b/bindings/python/codegen/__init__.py
new file mode 100644 (file)
index 0000000..cfa896e
--- /dev/null
@@ -0,0 +1,15 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+
+__all__ = [
+    'argtypes',
+    'codegen',
+    'definitions',
+    'defsparser',
+    'docextract',
+    'docgen',
+    'h2def',
+    'mergedefs',
+    'mkskel',
+    'override',
+    'scmexpr'
+]
diff --git a/bindings/python/codegen/argtypes.py b/bindings/python/codegen/argtypes.py
new file mode 100644 (file)
index 0000000..948bae1
--- /dev/null
@@ -0,0 +1,1075 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+import string
+import keyword
+import struct
+
+class VarList:
+    """Nicely format a C variable list"""
+    def __init__(self):
+        self.vars = {}
+    def add(self, ctype, name):
+        if self.vars.has_key(ctype):
+            self.vars[ctype] = self.vars[ctype] + (name,)
+        else:
+            self.vars[ctype] = (name,)
+    def __str__(self):
+        ret = []
+        for type in self.vars.keys():
+            ret.append('    ')
+            ret.append(type)
+            ret.append(' ')
+            ret.append(string.join(self.vars[type], ', '))
+            ret.append(';\n')
+        if ret:
+            ret.append('\n')
+            return string.join(ret, '')
+        return ''
+
+class WrapperInfo:
+    """A class that holds information about variable defs, code
+    snippets, etcd for use in writing out the function/method
+    wrapper."""
+    def __init__(self):
+        self.varlist = VarList()
+        self.parsestr = ''
+        self.parselist = ['', 'kwlist']
+        self.codebefore = []
+        self.codeafter = []
+        self.arglist = []
+        self.kwlist = []
+    def get_parselist(self):
+        return string.join(self.parselist, ', ')
+    def get_codebefore(self):
+        return string.join(self.codebefore, '')
+    def get_codeafter(self):
+        return string.join(self.codeafter, '')
+    def get_arglist(self):
+        return string.join(self.arglist, ', ')
+    def get_varlist(self):
+        return str(self.varlist)
+    def get_kwlist(self):
+        ret = '    static char *kwlist[] = { %s };\n' % \
+              string.join(self.kwlist + [ 'NULL' ], ', ')
+        if not self.get_varlist():
+            ret = ret + '\n'
+        return ret
+
+    def add_parselist(self, codes, parseargs, keywords):
+        self.parsestr = self.parsestr + codes
+        for arg in parseargs:
+            self.parselist.append(arg)
+        for kw in keywords:
+            if keyword.iskeyword(kw):
+                kw = kw + '_'
+            self.kwlist.append('"%s"' % kw)
+
+class ArgType:
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        """Add code to the WrapperInfo instance to handle
+        parameter."""
+        raise RuntimeError, "write_param not implemented for %s" % \
+              self.__class__.__name__
+    def write_return(self, ptype, ownsreturn, info):
+        """Adds a variable named ret of the return type to
+        info.varlist, and add any required code to info.codeafter to
+        convert the return value to a python object."""
+        raise RuntimeError, "write_return not implemented for %s" % \
+              self.__class__.__name__
+
+class NoneArg(ArgType):
+    def write_return(self, ptype, ownsreturn, info):
+        info.codeafter.append('    Py_INCREF(Py_None);\n' +
+                              '    return Py_None;')
+
+class StringArg(ArgType):
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            if pdflt != 'NULL': pdflt = '"' + pdflt + '"'
+            info.varlist.add('char', '*' + pname + ' = ' + pdflt)
+        else:
+            info.varlist.add('char', '*' + pname)
+        info.arglist.append(pname)
+        if pnull:
+            info.add_parselist('z', ['&' + pname], [pname])
+        else:
+            info.add_parselist('s', ['&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        if ownsreturn:
+            # have to free result ...
+            info.varlist.add('gchar', '*ret')
+            info.codeafter.append('    if (ret) {\n' +
+                                  '        PyObject *py_ret = PyString_FromString(ret);\n' +
+                                  '        g_free(ret);\n' +
+                                  '        return py_ret;\n' +
+                                  '    }\n' +
+                                  '    Py_INCREF(Py_None);\n' +
+                                  '    return Py_None;')
+        else:
+            info.varlist.add('const gchar', '*ret')
+            info.codeafter.append('    if (ret)\n' +
+                                  '        return PyString_FromString(ret);\n'+
+                                  '    Py_INCREF(Py_None);\n' +
+                                  '    return Py_None;')
+
+class UCharArg(ArgType):
+    # allows strings with embedded NULLs.
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add('guchar', '*' + pname + ' = "' + pdflt + '"')
+        else:
+            info.varlist.add('guchar', '*' + pname)
+        info.varlist.add('int', pname + '_len')
+        info.arglist.append(pname)
+        if pnull:
+            info.add_parselist('z#', ['&' + pname, '&' + pname + '_len'],
+                               [pname])
+        else:
+            info.add_parselist('s#', ['&' + pname, '&' + pname + '_len'],
+                               [pname])
+
+class CharArg(ArgType):
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add('char', pname + " = '" + pdflt + "'")
+        else:
+            info.varlist.add('char', pname)
+        info.arglist.append(pname)
+        info.add_parselist('c', ['&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('gchar', 'ret')
+        info.codeafter.append('    return PyString_FromStringAndSize(&ret, 1);')
+class GUniCharArg(ArgType):
+    ret_tmpl = ('#if !defined(Py_UNICODE_SIZE) || Py_UNICODE_SIZE == 2\n'
+                '    if (ret > 0xffff) {\n'
+                '        PyErr_SetString(PyExc_RuntimeError, "returned character can not be represented in 16-bit unicode");\n'
+                '        return NULL;\n'
+                '    }\n'
+                '#endif\n'
+                '    py_ret = (Py_UNICODE)ret;\n'
+                '    return PyUnicode_FromUnicode(&py_ret, 1);\n')
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add('gunichar', pname + " = '" + pdflt + "'")
+        else:
+            info.varlist.add('gunichar', pname)
+        info.arglist.append(pname)
+        info.add_parselist('O&', ['pyg_pyobj_to_unichar_conv', '&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('gunichar', 'ret')
+        info.varlist.add('Py_UNICODE', 'py_ret')
+        info.codeafter.append(self.ret_tmpl)
+
+
+class IntArg(ArgType):
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add('int', pname + ' = ' + pdflt)
+        else:
+            info.varlist.add('int', pname)
+        info.arglist.append(pname)
+        info.add_parselist('i', ['&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('int', 'ret')
+        info.codeafter.append('    return PyInt_FromLong(ret);')
+
+class UIntArg(ArgType):
+    dflt = ('    if (py_%(name)s) {\n'
+            '        if (PyLong_Check(py_%(name)s))\n'
+            '            %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n'
+            '        else if (PyInt_Check(py_%(name)s))\n'
+            '            %(name)s = PyInt_AsLong(py_%(name)s);\n'
+            '        else\n'
+            '            PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n'
+            '        if (PyErr_Occurred())\n'
+            '            return NULL;\n'
+            '    }\n')
+    before = ('    if (PyLong_Check(py_%(name)s))\n'
+              '        %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n'
+              '    else if (PyInt_Check(py_%(name)s))\n'
+              '        %(name)s = PyInt_AsLong(py_%(name)s);\n'
+              '    else\n'
+              '        PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n'
+              '    if (PyErr_Occurred())\n'
+              '        return NULL;\n')
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if not pdflt:
+            pdflt = '0';
+
+        info.varlist.add(ptype, pname + ' = ' + pdflt)
+        info.codebefore.append(self.dflt % {'name':pname})
+        info.varlist.add('PyObject', "*py_" + pname + ' = NULL')
+        info.arglist.append(pname)
+        info.add_parselist('O', ['&py_' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add(ptype, 'ret')
+        info.codeafter.append('    return PyLong_FromUnsignedLong(ret);')
+
+class SizeArg(ArgType):
+
+    if struct.calcsize('P') <= struct.calcsize('l'):
+        llp64 = True
+    else:
+        llp64 = False
+
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add(ptype, pname + ' = ' + pdflt)
+        else:
+            info.varlist.add(ptype, pname)
+        info.arglist.append(pname)
+        if self.llp64:
+            info.add_parselist('k', ['&' + pname], [pname])
+        else:
+            info.add_parselist('K', ['&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add(ptype, 'ret')
+        if self.llp64:
+            info.codeafter.append('    return PyLong_FromUnsignedLongLong(ret);\n')
+        else:
+            info.codeafter.append('    return PyLong_FromUnsignedLong(ret);\n')
+
+class SSizeArg(ArgType):
+
+    if struct.calcsize('P') <= struct.calcsize('l'):
+        llp64 = True
+    else:
+        llp64 = False
+
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add(ptype, pname + ' = ' + pdflt)
+        else:
+            info.varlist.add(ptype, pname)
+        info.arglist.append(pname)
+        if self.llp64:
+            info.add_parselist('l', ['&' + pname], [pname])
+        else:
+            info.add_parselist('L', ['&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add(ptype, 'ret')
+        if self.llp64:
+            info.codeafter.append('    return PyLong_FromLongLong(ret);\n')
+        else:
+            info.codeafter.append('    return PyLong_FromLong(ret);\n')
+
+class LongArg(ArgType):
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add(ptype, pname + ' = ' + pdflt)
+        else:
+            info.varlist.add(ptype, pname)
+        info.arglist.append(pname)
+        info.add_parselist('l', ['&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add(ptype, 'ret')
+        info.codeafter.append('    return PyInt_FromLong(ret);\n')
+
+class BoolArg(IntArg):
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('int', 'ret')
+        info.codeafter.append('    return PyBool_FromLong(ret);\n')
+
+class TimeTArg(ArgType):
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add('time_t', pname + ' = ' + pdflt)
+        else:
+            info.varlist.add('time_t', pname)
+        info.arglist.append(pname)
+        info.add_parselist('i', ['&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('time_t', 'ret')
+        info.codeafter.append('    return PyInt_FromLong(ret);')
+
+class ULongArg(ArgType):
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add('unsigned long', pname + ' = ' + pdflt)
+        else:
+            info.varlist.add('unsigned long', pname)
+        info.arglist.append(pname)
+        info.add_parselist('k', ['&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add(ptype, 'ret')
+        info.codeafter.append('    return PyLong_FromUnsignedLong(ret);\n')
+
+class UInt32Arg(ULongArg):
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        ULongArg.write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info)
+        ## if sizeof(unsigned long) > sizeof(unsigned int), we need to
+        ## check the value is within guint32 range
+        if struct.calcsize('L') > struct.calcsize('I'):
+            info.codebefore.append((
+                '    if (%(pname)s > G_MAXUINT32) {\n'
+                '        PyErr_SetString(PyExc_ValueError,\n'
+                '                        "Value out of range in conversion of"\n'
+                '                        " %(pname)s parameter to unsigned 32 bit integer");\n'
+                '        return NULL;\n'
+                '    }\n') % vars())
+
+class Int64Arg(ArgType):
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add('gint64', pname + ' = ' + pdflt)
+        else:
+            info.varlist.add('gint64', pname)
+        info.arglist.append(pname)
+        info.add_parselist('L', ['&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('gint64', 'ret')
+        info.codeafter.append('    return PyLong_FromLongLong(ret);')
+
+class UInt64Arg(ArgType):
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add('guint64', pname + ' = ' + pdflt)
+        else:
+            info.varlist.add('guint64', pname)
+        info.arglist.append(pname)
+        info.add_parselist('K', ['&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('guint64', 'ret')
+        info.codeafter.append('    return PyLong_FromUnsignedLongLong(ret);')
+
+
+class DoubleArg(ArgType):
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add('double', pname + ' = ' + pdflt)
+        else:
+            info.varlist.add('double', pname)
+        info.arglist.append(pname)
+        info.add_parselist('d', ['&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('double', 'ret')
+        info.codeafter.append('    return PyFloat_FromDouble(ret);')
+
+class FileArg(ArgType):
+    nulldflt = ('    if (py_%(name)s == Py_None)\n'
+                '        %(name)s = NULL;\n'
+                '    else if (py_%(name)s && PyFile_Check(py_%(name)s)\n'
+                '        %s = PyFile_AsFile(py_%(name)s);\n'
+                '    else if (py_%(name)s) {\n'
+                '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a file object or None");\n'
+                '        return NULL;\n'
+                '    }')
+    null = ('    if (py_%(name)s && PyFile_Check(py_%(name)s)\n'
+            '        %(name)s = PyFile_AsFile(py_%(name)s);\n'
+            '    else if (py_%(name)s != Py_None) {\n'
+            '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a file object or None");\n'
+            '        return NULL;\n'
+            '    }\n')
+    dflt = ('    if (py_%(name)s)\n'
+            '        %(name)s = PyFile_AsFile(py_%(name)s);\n')
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pnull:
+            if pdflt:
+                info.varlist.add('FILE', '*' + pname + ' = ' + pdflt)
+                info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+                info.codebefore.append(self.nulldflt % {'name':pname})
+            else:
+                info.varlist.add('FILE', '*' + pname + ' = NULL')
+                info.varlist.add('PyObject', '*py_' + pname)
+                info.codebefore.append(self.null & {'name':pname})
+            info.arglist.appned(pname)
+            info.add_parselist('O', ['&py_' + pname], [pname])
+        else:
+            if pdflt:
+                info.varlist.add('FILE', '*' + pname + ' = ' + pdflt)
+                info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+                info.codebefore.append(self.dflt % {'name':pname})
+                info.arglist.append(pname)
+            else:
+                info.varlist.add('PyObject', '*' + pname)
+                info.arglist.append('PyFile_AsFile(' + pname + ')')
+            info.add_parselist('O!', ['&PyFile_Type', '&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('FILE', '*ret')
+        info.codeafter.append('    if (ret)\n' +
+                              '        return PyFile_FromFile(ret, "", "", fclose);\n' +
+                              '    Py_INCREF(Py_None);\n' +
+                              '    return Py_None;')
+
+class EnumArg(ArgType):
+    enum = ('    if (pyg_enum_get_value(%(typecode)s, py_%(name)s, (gint *)&%(name)s))\n'
+            '        return NULL;\n')
+    def __init__(self, enumname, typecode):
+        self.enumname = enumname
+        self.typecode = typecode
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add(self.enumname, pname + ' = ' + pdflt)
+        else:
+            info.varlist.add(self.enumname, pname)
+        info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+        info.codebefore.append(self.enum % { 'typecode': self.typecode,
+                                             'name': pname})
+        info.arglist.append(pname)
+        info.add_parselist('O', ['&py_' + pname], [pname]);
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('gint', 'ret')
+        info.codeafter.append('    return pyg_enum_from_gtype(%s, ret);' % self.typecode)
+
+class FlagsArg(ArgType):
+    flag = ('    if (%(default)spyg_flags_get_value(%(typecode)s, py_%(name)s, (gint *)&%(name)s))\n'
+            '        return NULL;\n')
+    def __init__(self, flagname, typecode):
+        self.flagname = flagname
+        self.typecode = typecode
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add(self.flagname, pname + ' = ' + pdflt)
+            default = "py_%s && " % (pname,)
+        else:
+            info.varlist.add(self.flagname, pname)
+            default = ""
+        info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+        info.codebefore.append(self.flag % {'default':default,
+                                            'typecode':self.typecode,
+                                            'name':pname})
+        info.arglist.append(pname)
+        info.add_parselist('O', ['&py_' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('guint', 'ret')
+        info.codeafter.append('    return pyg_flags_from_gtype(%s, ret);' % self.typecode)
+
+class ObjectArg(ArgType):
+    # should change these checks to more typesafe versions that check
+    # a little further down in the class heirachy.
+    nulldflt = ('    if ((PyObject *)py_%(name)s == Py_None)\n'
+                '        %(name)s = NULL;\n'
+                '    else if (py_%(name)s && pygobject_check(py_%(name)s, &Py%(type)s_Type))\n'
+                '        %(name)s = %(cast)s(py_%(name)s->obj);\n'
+                '    else if (py_%(name)s) {\n'
+                '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
+                '        return NULL;\n'
+                '    }\n')
+    null = ('    if (py_%(name)s && pygobject_check(py_%(name)s, &Py%(type)s_Type))\n'
+            '        %(name)s = %(cast)s(py_%(name)s->obj);\n'
+            '    else if ((PyObject *)py_%(name)s != Py_None) {\n'
+            '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
+            '        return NULL;\n'
+            '    }\n')
+    dflt = '    if (py_%(name)s)\n' \
+           '        %(name)s = %(cast)s(py_%(name)s->obj);\n'
+    def __init__(self, objname, parent, typecode):
+        self.objname = objname
+        self.cast = string.replace(typecode, '_TYPE_', '_', 1)
+        self.parent = parent
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pnull:
+            if pdflt:
+                info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
+                info.varlist.add('PyGObject', '*py_' + pname + ' = NULL')
+                info.codebefore.append(self.nulldflt % {'name':pname,
+                                                        'cast':self.cast,
+                                                        'type':self.objname})
+            else:
+                info.varlist.add(self.objname, '*' + pname + ' = NULL')
+                info.varlist.add('PyGObject', '*py_' + pname)
+                info.codebefore.append(self.null % {'name':pname,
+                                                    'cast':self.cast,
+                                                    'type':self.objname})
+            if ptype.endswith('*'):
+                typename = ptype[:-1]
+                try:
+                    const, typename = typename.split('const-')
+                except ValueError:
+                    const = ''
+                if typename != ptype:
+                    info.arglist.append('(%s *) %s' % (ptype[:-1], pname))
+                else:
+                    info.arglist.append(pname)
+
+            info.add_parselist('O', ['&py_' + pname], [pname])
+        else:
+            if pdflt:
+                info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
+                info.varlist.add('PyGObject', '*py_' + pname + ' = NULL')
+                info.codebefore.append(self.dflt % {'name':pname,
+                                                    'cast':self.cast})
+                info.arglist.append(pname)
+                info.add_parselist('O!', ['&Py%s_Type' % self.objname,
+                                         '&py_' + pname], [pname])
+            else:
+                info.varlist.add('PyGObject', '*' + pname)
+                info.arglist.append('%s(%s->obj)' % (self.cast, pname))
+                info.add_parselist('O!', ['&Py%s_Type' % self.objname,
+                                          '&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        if ptype.endswith('*'):
+            typename = ptype[:-1]
+            try:
+                const, typename = typename.split('const-')
+            except ValueError:
+                const = ''
+        info.varlist.add(typename, '*ret')
+        if ownsreturn:
+            info.varlist.add('PyObject', '*py_ret')
+            # < GLib 2.8: using our custom _new and _unref functions
+            # makes sure we update the proper GstObject refcount
+            info.codeafter.append('    py_ret = pygobject_new((GObject *)ret);\n'
+                                  '    if (ret != NULL)\n'
+                                  '        g_object_unref((GObject *)ret);\n'
+                                  '    return py_ret;')
+        else:
+            info.codeafter.append('    /* pygobject_new handles NULL checking */\n' +
+                                  '    return pygobject_new((GObject *)ret);')
+
+class MiniObjectArg(ArgType):
+    # should change these checks to more typesafe versions that check
+    # a little further down in the class heirachy.
+    nulldflt = ('    if ((PyObject *)py_%(name)s == Py_None)\n'
+                '        %(name)s = NULL;\n'
+                '    else if (py_%(name)s) && pygstminiobject_check(py_%(name)s, &Py%(type)s_Type))\n'
+                '        %(name)s = %(cast)s(py_%(name)s->obj);\n'
+                '    else if (py_%(name)s) {\n'
+                '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
+                '        return NULL;\n'
+                '    }\n')
+    null = ('    if (py_%(name)s && pygstminiobject_check(py_%(name)s, &Py%(type)s_Type))\n'
+            '        %(name)s = %(cast)s(py_%(name)s->obj);\n'
+            '    else if ((PyObject *)py_%(name)s != Py_None) {\n'
+            '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
+            '        return NULL;\n'
+            '    }\n')
+    dflt = '    if (py_%(name)s)\n' \
+           '        %(name)s = %(cast)s(py_%(name)s->obj);\n'
+    def __init__(self, objname, parent, typecode):
+       self.objname = objname
+       self.cast = string.replace(typecode, '_TYPE_', '_', 1)
+        self.parent = parent
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+       if pnull:
+           if pdflt:
+               info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
+               info.varlist.add('PyGstMiniObject', '*py_' + pname + ' = NULL')
+               info.codebefore.append(self.nulldflt % {'name':pname,
+                                                        'cast':self.cast,
+                                                        'type':self.objname}) 
+           else:
+               info.varlist.add(self.objname, '*' + pname + ' = NULL')
+               info.varlist.add('PyGstMiniObject', '*py_' + pname)
+               info.codebefore.append(self.null % {'name':pname,
+                                                    'cast':self.cast,
+                                                    'type':self.objname}) 
+            if ptype.endswith('*'):
+                typename = ptype[:-1]
+                try:
+                    const, typename = typename.split('const-')
+                except ValueError:
+                    const = ''
+                if typename != ptype:
+                    info.arglist.append('(%s *) %s' % (ptype[:-1], pname))
+                else:
+                    info.arglist.append(pname)
+                    
+            info.add_parselist('O', ['&py_' + pname], [pname])
+       else:
+           if pdflt:
+               info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
+               info.varlist.add('PyGstMiniObject', '*py_' + pname + ' = NULL')
+               info.codebefore.append(self.dflt % {'name':pname,
+                                                    'cast':self.cast}) 
+               info.arglist.append(pname)
+                info.add_parselist('O', ['&Py%s_Type' % self.objname,
+                                         '&py_' + pname], [pname])
+           else:
+               info.varlist.add('PyGstMiniObject', '*' + pname)
+               info.arglist.append('%s(%s->obj)' % (self.cast, pname))
+                info.add_parselist('O!', ['&Py%s_Type' % self.objname,
+                                          '&' + pname], [pname])
+        if keeprefcount:
+            info.codebefore.append('    gst_mini_object_ref(GST_MINI_OBJECT(%s->obj));\n' % pname)
+    def write_return(self, ptype, ownsreturn, info):
+        if ptype.endswith('*'):
+            typename = ptype[:-1]
+            try:
+                const, typename = typename.split('const-')
+            except ValueError:
+                const = ''
+        info.varlist.add(typename, '*ret')
+        if ownsreturn:
+            info.varlist.add('PyObject', '*py_ret')
+            info.codeafter.append('    py_ret = pygstminiobject_new((GstMiniObject *)ret);\n'
+                                  '    if (ret != NULL)\n'
+                                  '       gst_mini_object_unref((GstMiniObject *)ret);\n'
+                                  '    return py_ret;')
+        else:
+            info.codeafter.append('    /* pygobject_new handles NULL checking */\n' +
+                                  '    return pygstminiobject_new((GstMiniObject *)ret);')
+
+class BoxedArg(ArgType):
+    # haven't done support for default args.  Is it needed?
+    check = ('    if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n'
+             '        %(name)s = pyg_boxed_get(py_%(name)s, %(typename)s);\n'
+             '    else {\n'
+             '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s");\n'
+             '        return NULL;\n'
+             '    }\n')
+    null = ('    if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n'
+            '        %(name)s = pyg_boxed_get(py_%(name)s, %(typename)s);\n'
+            '    else if (py_%(name)s != Py_None) {\n'
+            '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s or None");\n'
+            '        return NULL;\n'
+            '    }\n')
+    def __init__(self, ptype, typecode):
+        self.typename = ptype
+        self.typecode = typecode
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pnull:
+            info.varlist.add(self.typename, '*' + pname + ' = NULL')
+            info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
+            info.codebefore.append(self.null % {'name':  pname,
+                                                'typename': self.typename,
+                                                'typecode': self.typecode})
+        else:
+            info.varlist.add(self.typename, '*' + pname + ' = NULL')
+            info.varlist.add('PyObject', '*py_' + pname)
+            info.codebefore.append(self.check % {'name':  pname,
+                                                 'typename': self.typename,
+                                                 'typecode': self.typecode})
+        if ptype[-1] == '*':
+            typename = ptype[:-1]
+            if typename[:6] == 'const-': typename = typename[6:]
+            if typename != self.typename:
+                info.arglist.append('(%s *)%s' % (ptype[:-1], pname))
+            else:
+                info.arglist.append(pname)
+        else:
+            info.arglist.append(pname)
+        info.add_parselist('O', ['&py_' + pname], [pname])
+    ret_tmpl = '    /* pyg_boxed_new handles NULL checking */\n' \
+               '    return pyg_boxed_new(%(typecode)s, %(ret)s, %(copy)s, TRUE);'
+    def write_return(self, ptype, ownsreturn, info):
+        if ptype[-1] == '*':
+            info.varlist.add(self.typename, '*ret')
+            ret = 'ret'
+        else:
+            info.varlist.add(self.typename, 'ret')
+            ret = '&ret'
+            ownsreturn = 0 # of course it can't own a ref to a local var ...
+        info.codeafter.append(self.ret_tmpl %
+                              { 'typecode': self.typecode,
+                                'ret': ret,
+                                'copy': ownsreturn and 'FALSE' or 'TRUE'})
+
+class CustomBoxedArg(ArgType):
+    # haven't done support for default args.  Is it needed?
+    null = ('    if (%(check)s(py_%(name)s))\n'
+            '        %(name)s = %(get)s(py_%(name)s);\n'
+            '    else if (py_%(name)s != Py_None) {\n'
+            '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
+            '        return NULL;\n'
+            '    }\n')
+    def __init__(self, ptype, pytype, getter, new):
+        self.pytype = pytype
+        self.getter = getter
+        self.checker = 'Py' + ptype + '_Check'
+        self.new = new
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pnull:
+            info.varlist.add(ptype[:-1], '*' + pname + ' = NULL')
+            info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
+            info.codebefore.append(self.null % {'name':  pname,
+                                                'get':   self.getter,
+                                                'check': self.checker,
+                                                'type':  ptype[:-1]})
+            info.arglist.append(pname)
+            info.add_parselist('O', ['&py_' + pname], [pname])
+        else:
+            info.varlist.add('PyObject', '*' + pname)
+            info.arglist.append(self.getter + '(' + pname + ')')
+            info.add_parselist('O!', ['&' + self.pytype, '&' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add(ptype[:-1], '*ret')
+        info.codeafter.append('    if (ret)\n' +
+                              '        return ' + self.new + '(ret);\n' +
+                              '    Py_INCREF(Py_None);\n' +
+                              '    return Py_None;')
+
+class PointerArg(ArgType):
+    # haven't done support for default args.  Is it needed?
+    check = ('    if (pyg_pointer_check(py_%(name)s, %(typecode)s))\n'
+             '        %(name)s = pyg_pointer_get(py_%(name)s, %(typename)s);\n'
+             '    else {\n'
+             '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s");\n'
+             '        return NULL;\n'
+             '    }\n')
+    null = ('    if (pyg_pointer_check(py_%(name)s, %(typecode)s))\n'
+            '        %(name)s = pyg_pointer_get(py_%(name)s, %(typename)s);\n'
+            '    else if (py_%(name)s != Py_None) {\n'
+            '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s or None");\n'
+            '        return NULL;\n'
+            '    }\n')
+    def __init__(self, ptype, typecode):
+        self.typename = ptype
+        self.typecode = typecode
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pnull:
+            info.varlist.add(self.typename, '*' + pname + ' = NULL')
+            info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
+            info.codebefore.append(self.null % {'name':  pname,
+                                                'typename': self.typename,
+                                                'typecode': self.typecode})
+        else:
+            info.varlist.add(self.typename, '*' + pname + ' = NULL')
+            info.varlist.add('PyObject', '*py_' + pname)
+            info.codebefore.append(self.check % {'name':  pname,
+                                                 'typename': self.typename,
+                                                 'typecode': self.typecode})
+        info.arglist.append(pname)
+        info.add_parselist('O', ['&py_' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        if ptype[-1] == '*':
+            info.varlist.add(self.typename, '*ret')
+            info.codeafter.append('    /* pyg_pointer_new handles NULL checking */\n' +
+                                  '    return pyg_pointer_new(' + self.typecode + ', ret);')
+        else:
+            info.varlist.add(self.typename, 'ret')
+            info.codeafter.append('    /* pyg_pointer_new handles NULL checking */\n' +
+                                  '    return pyg_pointer_new(' + self.typecode + ', &ret);')
+
+class AtomArg(IntArg):
+    dflt = '    if (py_%(name)s) {\n' \
+           '        %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n' \
+           '        if (PyErr_Occurred())\n' \
+           '            return NULL;\n' \
+           '    }\n'
+    atom = ('    %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n'
+            '    if (PyErr_Occurred())\n'
+            '        return NULL;\n')
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pdflt:
+            info.varlist.add('GdkAtom', pname + ' = ' + pdflt)
+            info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+            info.codebefore.append(self.dflt % {'name': pname})
+        else:
+            info.varlist.add('GdkAtom', pname)
+            info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+            info.codebefore.append(self.atom % {'name': pname})
+        info.arglist.append(pname)
+        info.add_parselist('O', ['&py_' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('GdkAtom', 'ret')
+        info.varlist.add('PyObject *', 'py_ret')
+        info.varlist.add('gchar *', 'name')
+        info.codeafter.append('    name = gdk_atom_name(ret);\n'
+                              '    py_ret = PyString_FromString(name);\n'
+                              '    g_free(name);\n'
+                              '    return py_ret;')
+
+class GTypeArg(ArgType):
+    gtype = ('    if ((%(name)s = pyg_type_from_object(py_%(name)s)) == 0)\n'
+             '        return NULL;\n')
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        info.varlist.add('GType', pname)
+        info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+        info.codebefore.append(self.gtype % {'name': pname})
+        info.arglist.append(pname)
+        info.add_parselist('O', ['&py_' + pname], [pname])
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('GType', 'ret')
+        info.codeafter.append('    return pyg_type_wrapper_new(ret);')
+
+# simple GError handler.
+class GErrorArg(ArgType):
+    handleerror = ('    if (pyg_error_check(&%(name)s))\n'
+                   '        return NULL;\n')
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        info.varlist.add('GError', '*' + pname + ' = NULL')
+        info.arglist.append('&' + pname)
+        info.codeafter.append(self.handleerror % { 'name': pname })
+
+class GtkTreePathArg(ArgType):
+    # haven't done support for default args.  Is it needed?
+    normal = ('    %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n'
+              '    if (!%(name)s) {\n'
+              '        PyErr_SetString(PyExc_TypeError, "could not convert %(name)s to a GtkTreePath");\n'
+              '        return NULL;\n'
+              '    }\n')
+    null = ('    if (py_%(name)s != Py_None) {\n'
+            '        %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n'
+            '        if (!%(name)s) {\n'
+            '            PyErr_SetString(PyExc_TypeError, "could not convert %(name)s to a GtkTreePath");\n'
+            '            return NULL;\n'
+            '        }\n'
+            '    }\n')
+    freepath = ('    if (%(name)s)\n'
+                '        gtk_tree_path_free(%(name)s);\n')
+    def __init__(self):
+        pass
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pnull:
+            info.varlist.add('GtkTreePath', '*' + pname + ' = NULL')
+            info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
+            info.codebefore.append(self.null % {'name':  pname})
+            info.arglist.append(pname)
+            info.add_parselist('O', ['&py_' + pname], [pname])
+        else:
+            info.varlist.add('GtkTreePath', '*' + pname)
+            info.varlist.add('PyObject', '*py_' + pname)
+            info.codebefore.append(self.normal % {'name': pname})
+            info.arglist.append(pname)
+            info.add_parselist('O', ['&py_' + pname], [pname])
+        info.codeafter.append(self.freepath % {'name': pname})
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('GtkTreePath', '*ret')
+        if ownsreturn:
+            info.codeafter.append('    if (ret) {\n'
+                                  '        PyObject *py_ret = pygtk_tree_path_to_pyobject(ret);\n'
+                                  '        gtk_tree_path_free(ret);\n'
+                                  '        return py_ret;\n'
+                                  '    }\n'
+                                  '    Py_INCREF(Py_None);\n'
+                                  '    return Py_None;')
+        else:
+            info.codeafter.append('    if (ret) {\n'
+                                  '        PyObject *py_ret = pygtk_tree_path_to_pyobject(ret);\n'
+                                  '        return py_ret;\n'
+                                  '    }\n'
+                                  '    Py_INCREF(Py_None);\n'
+                                  '    return Py_None;')
+
+class GdkRectanglePtrArg(ArgType):
+    normal = ('    if (!pygdk_rectangle_from_pyobject(py_%(name)s, &%(name)s))\n'
+              '        return NULL;\n')
+    null =   ('    if (py_%(name)s == Py_None)\n'
+              '        %(name)s = NULL;\n'
+              '    else if (pygdk_rectangle_from_pyobject(py_%(name)s, &%(name)s_rect))\n'
+              '        %(name)s = &%(name)s_rect;\n'
+              '    else\n'
+              '            return NULL;\n')
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        if pnull:
+            info.varlist.add('GdkRectangle', pname + '_rect = { 0, 0, 0, 0 }')
+            info.varlist.add('GdkRectangle', '*' + pname)
+            info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
+            info.add_parselist('O', ['&py_' + pname], [pname])
+            info.arglist.append(pname)
+            info.codebefore.append(self.null % {'name':  pname})
+        else:
+            info.varlist.add('GdkRectangle', pname + ' = { 0, 0, 0, 0 }')
+            info.varlist.add('PyObject', '*py_' + pname)
+            info.add_parselist('O', ['&py_' + pname], [pname])
+            info.arglist.append('&' + pname)
+            info.codebefore.append(self.normal % {'name':  pname})
+
+class GdkRectangleArg(ArgType):
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add('GdkRectangle', 'ret')
+        info.codeafter.append('    return pyg_boxed_new(GDK_TYPE_RECTANGLE, &ret, TRUE, TRUE);')
+
+class PyObjectArg(ArgType):
+    def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
+        info.varlist.add('PyObject', '*' + pname)
+        info.add_parselist('O', ['&' + pname], [pname])
+        info.arglist.append(pname)
+    def write_return(self, ptype, ownsreturn, info):
+        info.varlist.add("PyObject", "*ret")
+        if ownsreturn:
+            info.codeafter.append('    if (ret) {\n'
+                                  '       return ret;\n'
+                                  '    }\n'
+                                  '    Py_INCREF(Py_None);\n'
+                                  '    return Py_None;')
+        else:
+            info.codeafter.append('    if (!ret) ret = Py_None;\n'
+                                  '    Py_INCREF(ret);\n'
+                                  '    return ret;')
+
+class ArgMatcher:
+    def __init__(self):
+        self.argtypes = {}
+        self.reverse_argtypes = {}
+        self.reverse_rettypes = {}
+
+    def register(self, ptype, handler):
+        self.argtypes[ptype] = handler
+    def register_reverse(self, ptype, handler):
+        self.reverse_argtypes[ptype] = handler
+    def register_reverse_ret(self, ptype, handler):
+        self.reverse_rettypes[ptype] = handler
+
+    def register_enum(self, ptype, typecode):
+        if typecode is None:
+            typecode = "G_TYPE_NONE"
+        self.register(ptype, EnumArg(ptype, typecode))
+    def register_flag(self, ptype, typecode):
+        if typecode is None:
+            typecode = "G_TYPE_NONE"
+        self.register(ptype, FlagsArg(ptype, typecode))
+    def register_object(self, ptype, parent, typecode):
+        oa = ObjectArg(ptype, parent, typecode)
+        self.register(ptype, oa)  # in case I forget the * in the .defs
+        self.register(ptype+'*', oa)
+        self.register('const-'+ptype+'*', oa)
+        if ptype == 'GdkPixmap':
+            # hack to handle GdkBitmap synonym.
+            self.register('GdkBitmap', oa)
+            self.register('GdkBitmap*', oa)
+    def register_miniobject(self, ptype, parent, typecode):
+        oa = MiniObjectArg(ptype, parent, typecode)
+        self.register(ptype, oa)  # in case I forget the * in the .defs
+        self.register(ptype+'*', oa)
+    def register_boxed(self, ptype, typecode):
+        if self.argtypes.has_key(ptype): return
+        arg = BoxedArg(ptype, typecode)
+        self.register(ptype, arg)
+        self.register(ptype+'*', arg)
+        self.register('const-'+ptype+'*', arg)
+    def register_custom_boxed(self, ptype, pytype, getter, new):
+        arg = CustomBoxedArg(ptype, pytype, getter, new)
+        self.register(ptype+'*', arg)
+        self.register('const-'+ptype+'*', arg)
+    def register_pointer(self, ptype, typecode):
+        arg = PointerArg(ptype, typecode)
+        self.register(ptype, arg)
+        self.register(ptype+'*', arg)
+        self.register('const-'+ptype+'*', arg)
+
+    def get(self, ptype):
+        try:
+            return self.argtypes[ptype]
+        except KeyError:
+            if ptype[:8] == 'GdkEvent' and ptype[-1] == '*':
+                return self.argtypes['GdkEvent*']
+            raise
+    def _get_reverse_common(self, ptype, registry):
+        props = dict(c_type=ptype)
+        try:
+            return registry[ptype], props
+        except KeyError:
+            try:
+                handler = self.argtypes[ptype]
+            except KeyError:
+                if ptype.startswith('GdkEvent') and ptype.endswith('*'):
+                    handler = self.argtypes['GdkEvent*']
+                else:
+                    raise
+            if isinstance(handler, ObjectArg):
+                return registry['GObject*'], props
+            elif isinstance(handler, EnumArg):
+                props['typecode'] = handler.typecode
+                props['enumname'] = handler.enumname
+                return registry['GEnum'], props
+            elif isinstance(handler, FlagsArg):
+                props['typecode'] = handler.typecode
+                props['flagname'] = handler.flagname
+                return registry['GFlags'], props
+            elif isinstance(handler, BoxedArg):
+                props['typecode'] = handler.typecode
+                props['typename'] = handler.typename
+                return registry['GBoxed'], props
+            else:
+                raise
+    def get_reverse(self, ptype):
+        return self._get_reverse_common(ptype, self.reverse_argtypes)
+    def get_reverse_ret(self, ptype):
+        return self._get_reverse_common(ptype, self.reverse_rettypes)
+
+    def object_is_a(self, otype, parent):
+        if otype == None: return 0
+        if otype == parent: return 1
+        if not self.argtypes.has_key(otype): return 0
+        return self.object_is_a(self.get(otype).parent, parent)
+
+matcher = ArgMatcher()
+
+arg = NoneArg()
+matcher.register(None, arg)
+matcher.register('none', arg)
+
+arg = StringArg()
+matcher.register('char*', arg)
+matcher.register('gchar*', arg)
+matcher.register('const-char*', arg)
+matcher.register('char-const*', arg)
+matcher.register('const-gchar*', arg)
+matcher.register('gchar-const*', arg)
+matcher.register('string', arg)
+matcher.register('static_string', arg)
+
+arg = UCharArg()
+matcher.register('unsigned-char*', arg)
+matcher.register('const-guchar*', arg)
+matcher.register('guchar*', arg)
+
+arg = CharArg()
+matcher.register('char', arg)
+matcher.register('gchar', arg)
+matcher.register('guchar', arg)
+
+arg = GUniCharArg()
+matcher.register('gunichar', arg)
+
+arg = IntArg()
+matcher.register('int', arg)
+matcher.register('gint', arg)
+matcher.register('short', arg)
+matcher.register('gshort', arg)
+matcher.register('gushort', arg)
+matcher.register('gsize', SizeArg())
+matcher.register('gssize', SSizeArg())
+matcher.register('guint8', arg)
+matcher.register('gint8', arg)
+matcher.register('guint16', arg)
+matcher.register('gint16', arg)
+matcher.register('gint32', arg)
+matcher.register('GTime', arg)
+
+arg = LongArg()
+matcher.register('long', arg)
+matcher.register('glong', arg)
+
+arg = UIntArg()
+matcher.register('guint', arg)
+
+arg = BoolArg()
+matcher.register('gboolean', arg)
+
+arg = TimeTArg()
+matcher.register('time_t', arg)
+
+matcher.register('guint32', UInt32Arg())
+
+arg = ULongArg()
+matcher.register('gulong', arg)
+
+arg = Int64Arg()
+matcher.register('gint64', arg)
+matcher.register('long-long', arg)
+
+arg = UInt64Arg()
+matcher.register('guint64', arg)
+matcher.register('unsigned-long-long', arg)
+
+arg = DoubleArg()
+matcher.register('double', arg)
+matcher.register('gdouble', arg)
+matcher.register('float', arg)
+matcher.register('gfloat', arg)
+
+arg = FileArg()
+matcher.register('FILE*', arg)
+
+# enums, flags, objects
+
+matcher.register('GdkAtom', AtomArg())
+
+matcher.register('GType', GTypeArg())
+matcher.register('GtkType', GTypeArg())
+
+matcher.register('GError**', GErrorArg())
+matcher.register('GtkTreePath*', GtkTreePathArg())
+matcher.register('GdkRectangle*', GdkRectanglePtrArg())
+matcher.register('GtkAllocation*', GdkRectanglePtrArg())
+matcher.register('GdkRectangle', GdkRectangleArg())
+matcher.register('PyObject*', PyObjectArg())
+
+matcher.register('GdkNativeWindow', ULongArg())
+
+matcher.register_object('GObject', None, 'G_TYPE_OBJECT')
+matcher.register_miniobject('GstMiniObject', None, 'GST_TYPE_MINI_OBJECT')
+
+del arg
diff --git a/bindings/python/codegen/code-coverage.py b/bindings/python/codegen/code-coverage.py
new file mode 100755 (executable)
index 0000000..fd15034
--- /dev/null
@@ -0,0 +1,42 @@
+from __future__ import generators
+import sys, os
+
+def read_symbols(file, type=None, dynamic=0):
+    if dynamic:
+        cmd = 'nm -D %s' % file
+    else:
+        cmd = 'nm %s' % file
+    for line in os.popen(cmd, 'r'):
+        if line[0] != ' ':  # has an address as first bit of line
+            while line[0] != ' ':
+                line = line[1:]
+        while line[0] == ' ':
+            line = line[1:]
+        # we should be up to "type symbolname" now
+        sym_type = line[0]
+        symbol = line[1:].strip()
+
+        if not type or type == sym_type:
+            yield symbol
+
+def main():
+    if len(sys.argv) != 3:
+        sys.stderr.write('usage: coverage-check library.so wrapper.so\n')
+        sys.exit(1)
+    library = sys.argv[1]
+    wrapper = sys.argv[2]
+
+    # first create a dict with all referenced symbols in the wrapper
+    # should really be a set, but a dict will do ...
+    wrapper_symbols = {}
+    for symbol in read_symbols(wrapper, type='U', dynamic=1):
+        wrapper_symbols[symbol] = 1
+
+    # now go through the library looking for matches on the defined symbols:
+    for symbol in read_symbols(library, type='T', dynamic=1):
+        if symbol[0] == '_': continue
+        if symbol not in wrapper_symbols:
+            print symbol
+
+if __name__ == '__main__':
+    main()
diff --git a/bindings/python/codegen/codegen.py b/bindings/python/codegen/codegen.py
new file mode 100644 (file)
index 0000000..8f20bf7
--- /dev/null
@@ -0,0 +1,1572 @@
+import getopt
+import keyword
+import os
+import string
+import sys
+
+import argtypes
+import definitions
+import defsparser
+import override
+import reversewrapper
+
+class Coverage(object):
+    def __init__(self, name):
+        self.name = name
+        self.wrapped = 0
+        self.not_wrapped = 0
+
+    def declare_wrapped(self):
+        self.wrapped += 1
+
+    def declare_not_wrapped(self):
+        self.not_wrapped += 1
+
+    def printstats(self):
+        total = self.wrapped + self.not_wrapped
+        fd = sys.stderr
+        if total:
+            fd.write("***INFO*** The coverage of %s is %.2f%% (%i/%i)\n" %
+                     (self.name,
+                      float(self.wrapped*100)/total,
+                      self.wrapped,
+                      total))
+        else:
+            fd.write("***INFO*** There are no declared %s." % self.name)
+
+functions_coverage = Coverage("global functions")
+methods_coverage = Coverage("methods")
+vproxies_coverage = Coverage("virtual proxies")
+vaccessors_coverage = Coverage("virtual accessors")
+iproxies_coverage = Coverage("interface proxies")
+
+def exc_info():
+    #traceback.print_exc()
+    etype, value, tb = sys.exc_info()
+    ret = ""
+    try:
+        sval = str(value)
+        if etype == KeyError:
+            ret = "No ArgType for %s" % (sval,)
+        else:
+            ret = sval
+    finally:
+        del etype, value, tb
+    return ret
+
+def fixname(name):
+    if keyword.iskeyword(name):
+        return name + '_'
+    return name
+
+class FileOutput:
+    '''Simple wrapper for file object, that makes writing #line
+    statements easier.''' # "
+    def __init__(self, fp, filename=None):
+        self.fp = fp
+        self.lineno = 1
+        if filename:
+            self.filename = filename
+        else:
+            self.filename = self.fp.name
+    # handle writing to the file, and keep track of the line number ...
+    def write(self, str):
+        self.fp.write(str)
+        self.lineno = self.lineno + string.count(str, '\n')
+    def writelines(self, sequence):
+        for line in sequence:
+            self.write(line)
+    def close(self):
+        self.fp.close()
+    def flush(self):
+        self.fp.flush()
+
+    def setline(self, linenum, filename):
+        '''writes out a #line statement, for use by the C
+        preprocessor.''' # "
+        self.write('#line %d "%s"\n' % (linenum, filename))
+    def resetline(self):
+        '''resets line numbering to the original file'''
+        self.setline(self.lineno + 1, self.filename)
+
+class Wrapper:
+    type_tmpl = (
+        'PyTypeObject Py%(typename)s_Type = {\n'
+        '    PyObject_HEAD_INIT(NULL)\n'
+        '    0,                                 /* ob_size */\n'
+        '    "%(classname)s",                   /* tp_name */\n'
+        '    sizeof(%(tp_basicsize)s),          /* tp_basicsize */\n'
+        '    0,                                 /* tp_itemsize */\n'
+        '    /* methods */\n'
+        '    (destructor)%(tp_dealloc)s,        /* tp_dealloc */\n'
+        '    (printfunc)0,                      /* tp_print */\n'
+        '    (getattrfunc)%(tp_getattr)s,       /* tp_getattr */\n'
+        '    (setattrfunc)%(tp_setattr)s,       /* tp_setattr */\n'
+        '    (cmpfunc)%(tp_compare)s,           /* tp_compare */\n'
+        '    (reprfunc)%(tp_repr)s,             /* tp_repr */\n'
+        '    (PyNumberMethods*)%(tp_as_number)s,     /* tp_as_number */\n'
+        '    (PySequenceMethods*)%(tp_as_sequence)s, /* tp_as_sequence */\n'
+        '    (PyMappingMethods*)%(tp_as_mapping)s,   /* tp_as_mapping */\n'
+        '    (hashfunc)%(tp_hash)s,             /* tp_hash */\n'
+        '    (ternaryfunc)%(tp_call)s,          /* tp_call */\n'
+        '    (reprfunc)%(tp_str)s,              /* tp_str */\n'
+        '    (getattrofunc)%(tp_getattro)s,     /* tp_getattro */\n'
+        '    (setattrofunc)%(tp_setattro)s,     /* tp_setattro */\n'
+        '    (PyBufferProcs*)%(tp_as_buffer)s,  /* tp_as_buffer */\n'
+        '    %(tp_flags)s,                      /* tp_flags */\n'
+        '    %(tp_doc)s,                        /* Documentation string */\n'
+        '    (traverseproc)%(tp_traverse)s,     /* tp_traverse */\n'
+        '    (inquiry)%(tp_clear)s,             /* tp_clear */\n'
+        '    (richcmpfunc)%(tp_richcompare)s,   /* tp_richcompare */\n'
+        '    %(tp_weaklistoffset)s,             /* tp_weaklistoffset */\n'
+        '    (getiterfunc)%(tp_iter)s,          /* tp_iter */\n'
+        '    (iternextfunc)%(tp_iternext)s,     /* tp_iternext */\n'
+        '    (struct PyMethodDef*)%(tp_methods)s, /* tp_methods */\n'
+        '    (struct PyMemberDef*)0,              /* tp_members */\n'
+        '    (struct PyGetSetDef*)%(tp_getset)s,  /* tp_getset */\n'
+        '    NULL,                              /* tp_base */\n'
+        '    NULL,                              /* tp_dict */\n'
+        '    (descrgetfunc)%(tp_descr_get)s,    /* tp_descr_get */\n'
+        '    (descrsetfunc)%(tp_descr_set)s,    /* tp_descr_set */\n'
+        '    %(tp_dictoffset)s,                 /* tp_dictoffset */\n'
+        '    (initproc)%(tp_init)s,             /* tp_init */\n'
+        '    (allocfunc)%(tp_alloc)s,           /* tp_alloc */\n'
+        '    (newfunc)%(tp_new)s,               /* tp_new */\n'
+        '    (freefunc)%(tp_free)s,             /* tp_free */\n'
+        '    (inquiry)%(tp_is_gc)s              /* tp_is_gc */\n'
+        '};\n\n'
+        )
+
+    slots_list = [
+        'tp_getattr', 'tp_setattr', 'tp_getattro', 'tp_setattro',
+        'tp_compare', 'tp_repr',
+        'tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'tp_hash',
+        'tp_call', 'tp_str', 'tp_as_buffer', 'tp_richcompare', 'tp_iter',
+        'tp_iternext', 'tp_descr_get', 'tp_descr_set', 'tp_init',
+        'tp_alloc', 'tp_new', 'tp_free', 'tp_is_gc',
+        'tp_traverse', 'tp_clear', 'tp_dealloc', 'tp_flags', 'tp_doc'
+        ]
+
+    getter_tmpl = (
+        'static PyObject *\n'
+        '%(funcname)s(PyObject *self, void *closure)\n'
+        '{\n'
+        '%(varlist)s'
+        '    ret = %(field)s;\n'
+        '%(codeafter)s\n'
+        '}\n\n'
+        )
+
+    parse_tmpl = (
+        '    if (!PyArg_ParseTupleAndKeywords(args, kwargs,'
+        '"%(typecodes)s:%(name)s"%(parselist)s))\n'
+        '        return %(errorreturn)s;\n'
+        )
+
+    deprecated_tmpl = (
+        '    if (PyErr_Warn(PyExc_DeprecationWarning, '
+        '"%(deprecationmsg)s") < 0)\n'
+        '        return %(errorreturn)s;\n'
+        )
+
+    methdef_tmpl = (
+        '    { "%(name)s", (PyCFunction)%(cname)s, %(flags)s,\n'
+        '      %(docstring)s },\n'
+        )
+
+    noconstructor = (
+        'static int\n'
+        'pygobject_no_constructor(PyObject *self, PyObject *args, '
+        'PyObject *kwargs)\n'
+        '{\n'
+        '    gchar buf[512];\n'
+        '\n'
+        '    g_snprintf(buf, sizeof(buf), "%s is an abstract widget", '
+        'self->ob_type->tp_name);\n'
+        '    PyErr_SetString(PyExc_NotImplementedError, buf);\n'
+        '    return -1;\n'
+        '}\n\n'
+        )
+
+    function_tmpl = (
+        'static PyObject *\n'
+        '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n'
+        '{\n'
+        '%(varlist)s'
+        '%(parseargs)s'
+        '%(codebefore)s'
+        '    %(begin_allow_threads)s\n'
+        '    %(setreturn)s%(cname)s(%(arglist)s);\n'
+        '    %(end_allow_threads)s\n'
+        '%(codeafter)s\n'
+        '}\n\n'
+        )
+
+    virtual_accessor_tmpl = (
+        'static PyObject *\n'
+        '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n'
+        '{\n'
+        '    gpointer klass;\n'
+        '%(varlist)s'
+        '%(parseargs)s'
+        '%(codebefore)s'
+        '    klass = g_type_class_ref(pyg_type_from_object(cls));\n'
+        '    if (%(class_cast_macro)s(klass)->%(virtual)s) {\n'
+        '        pyg_begin_allow_threads;\n'
+        '        %(setreturn)s%(class_cast_macro)s(klass)->'
+        '%(virtual)s(%(arglist)s);\n'
+        '        pyg_end_allow_threads;\n'
+        '    } else {\n'
+        '        PyErr_SetString(PyExc_NotImplementedError, '
+        '"virtual method %(name)s not implemented");\n'
+        '        g_type_class_unref(klass);\n'
+        '        return NULL;\n'
+        '    }\n'
+        '    g_type_class_unref(klass);\n'
+        '%(codeafter)s\n'
+        '}\n\n'
+        )
+
+    # template for method calls
+    constructor_tmpl = None
+    method_tmpl = None
+
+    def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)):
+        self.parser = parser
+        self.objinfo = objinfo
+        self.overrides = overrides
+        self.fp = fp
+
+    def get_lower_name(self):
+        return string.lower(string.replace(self.objinfo.typecode,
+                                           '_TYPE_', '_', 1))
+
+    def get_field_accessor(self, fieldname):
+        raise NotImplementedError
+
+    def get_initial_class_substdict(self): return {}
+
+    def get_initial_constructor_substdict(self, constructor):
+        return { 'name': '%s.__init__' % self.objinfo.c_name,
+                 'errorreturn': '-1' }
+    def get_initial_method_substdict(self, method):
+        substdict = { 'name': '%s.%s' % (self.objinfo.c_name, method.name) }
+        substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;'
+        substdict['end_allow_threads'] = 'pyg_end_allow_threads;'
+        return substdict
+
+    def write_class(self):
+        if self.overrides.is_type_ignored(self.objinfo.c_name):
+            return
+        self.fp.write('\n/* ----------- %s ----------- */\n\n' %
+                      self.objinfo.c_name)
+        substdict = self.get_initial_class_substdict()
+        if not substdict.has_key('tp_flags'):
+            substdict['tp_flags'] = 'Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE'
+        substdict['typename'] = self.objinfo.c_name
+        if self.overrides.modulename:
+            substdict['classname'] = '%s.%s' % (self.overrides.modulename,
+                                           self.objinfo.name)
+        else:
+            substdict['classname'] = self.objinfo.name
+        substdict['tp_doc'] = self.objinfo.docstring
+
+        # Maybe this could be done in a nicer way, but I'll leave it as it is
+        # for now: -- Johan
+        if not self.overrides.slot_is_overriden('%s.tp_init' %
+                                                self.objinfo.c_name):
+            substdict['tp_init'] = self.write_constructor()
+        substdict['tp_methods'] = self.write_methods()
+        substdict['tp_getset'] = self.write_getsets()
+
+        # handle slots ...
+        for slot in self.slots_list:
+
+            slotname = '%s.%s' % (self.objinfo.c_name, slot)
+            slotfunc = '_wrap_%s_%s' % (self.get_lower_name(), slot)
+            if slot[:6] == 'tp_as_':
+                slotfunc = '&' + slotfunc
+            if self.overrides.slot_is_overriden(slotname):
+                data = self.overrides.slot_override(slotname)
+                self.write_function(slotname, data)
+                substdict[slot] = slotfunc
+            else:
+                if not substdict.has_key(slot):
+                    substdict[slot] = '0'
+
+        self.fp.write(self.type_tmpl % substdict)
+
+        self.write_virtuals()
+
+    def write_function_wrapper(self, function_obj, template,
+                               handle_return=0, is_method=0, kwargs_needed=0,
+                               substdict=None):
+        '''This function is the guts of all functions that generate
+        wrappers for functions, methods and constructors.'''
+        if not substdict: substdict = {}
+
+        info = argtypes.WrapperInfo()
+
+        substdict.setdefault('errorreturn', 'NULL')
+
+        # for methods, we want the leading comma
+        if is_method:
+            info.arglist.append('')
+
+        if function_obj.varargs:
+            raise ValueError, "varargs functions not supported"
+
+        for param in function_obj.params:
+            if param.pdflt and '|' not in info.parsestr:
+                info.add_parselist('|', [], [])
+            handler = argtypes.matcher.get(param.ptype)
+            handler.write_param(param.ptype, param.pname, param.pdflt,
+                                param.pnull, param.keeprefcount, info)
+
+        substdict['setreturn'] = ''
+        if handle_return:
+            if function_obj.ret not in ('none', None):
+                substdict['setreturn'] = 'ret = '
+            handler = argtypes.matcher.get(function_obj.ret)
+            handler.write_return(function_obj.ret,
+                                 function_obj.caller_owns_return, info)
+
+        if function_obj.deprecated != None:
+            deprecated = self.deprecated_tmpl % {
+                'deprecationmsg': function_obj.deprecated,
+                'errorreturn': substdict['errorreturn'] }
+        else:
+            deprecated = ''
+
+        # if name isn't set, set it to function_obj.name
+        substdict.setdefault('name', function_obj.name)
+
+        substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;'
+        substdict['end_allow_threads'] = 'pyg_end_allow_threads;'
+
+        if self.objinfo:
+            substdict['typename'] = self.objinfo.c_name
+        substdict.setdefault('cname',  function_obj.c_name)
+        substdict['varlist'] = info.get_varlist()
+        substdict['typecodes'] = info.parsestr
+        substdict['parselist'] = info.get_parselist()
+        substdict['arglist'] = info.get_arglist()
+        substdict['codebefore'] = deprecated + (
+            string.replace(info.get_codebefore(),
+            'return NULL', 'return ' + substdict['errorreturn'])
+            )
+        substdict['codeafter'] = (
+            string.replace(info.get_codeafter(),
+                           'return NULL',
+                           'return ' + substdict['errorreturn']))
+
+        if info.parsestr or kwargs_needed:
+            substdict['parseargs'] = self.parse_tmpl % substdict
+            substdict['extraparams'] = ', PyObject *args, PyObject *kwargs'
+            flags = 'METH_VARARGS|METH_KEYWORDS'
+
+            # prepend the keyword list to the variable list
+            substdict['varlist'] = info.get_kwlist() + substdict['varlist']
+        else:
+            substdict['parseargs'] = ''
+            substdict['extraparams'] = ''
+            flags = 'METH_NOARGS'
+
+        return template % substdict, flags
+
+    def write_constructor(self):
+        initfunc = '0'
+        constructor = self.parser.find_constructor(self.objinfo,self.overrides)
+        if not constructor:
+            return self.write_default_constructor()
+
+        funcname = constructor.c_name
+        try:
+            if self.overrides.is_overriden(funcname):
+                data = self.overrides.override(funcname)
+                self.write_function(funcname, data)
+                self.objinfo.has_new_constructor_api = (
+                    self.objinfo.typecode in
+                    self.overrides.newstyle_constructors)
+            else:
+                # ok, a hack to determine if we should use
+                # new-style constructores :P
+                property_based = getattr(self,
+                                         'write_property_based_constructor',
+                                         None)
+                if property_based:
+                    if (len(constructor.params) == 0 or
+                        isinstance(constructor.params[0],
+                                   definitions.Property)):
+                        # write_property_based_constructor is only
+                        # implemented in GObjectWrapper
+                        return self.write_property_based_constructor(
+                            constructor)
+                    else:
+                        sys.stderr.write(
+                            "Warning: generating old-style constructor for:" +
+                            constructor.c_name + '\n')
+
+                # write constructor from template ...
+                code = self.write_function_wrapper(constructor,
+                    self.constructor_tmpl,
+                    handle_return=0, is_method=0, kwargs_needed=1,
+                    substdict=self.get_initial_constructor_substdict(
+                    constructor))[0]
+                self.fp.write(code)
+            initfunc = '_wrap_' + funcname
+        except:
+            sys.stderr.write('Could not write constructor for %s: %s\n'
+                             % (self.objinfo.c_name, exc_info()))
+
+            initfunc = self.write_noconstructor()
+        return initfunc
+
+    def write_noconstructor(self):
+        # this is a hack ...
+        if not hasattr(self.overrides, 'no_constructor_written'):
+            self.fp.write(self.noconstructor)
+            self.overrides.no_constructor_written = 1
+        initfunc = 'pygobject_no_constructor'
+        return initfunc
+
+    def write_default_constructor(self):
+        return self.write_noconstructor()
+
+    def get_methflags(self, funcname):
+        if self.overrides.wants_kwargs(funcname):
+            flags = 'METH_VARARGS|METH_KEYWORDS'
+        elif self.overrides.wants_noargs(funcname):
+            flags = 'METH_NOARGS'
+        elif self.overrides.wants_onearg(funcname):
+            flags = 'METH_O'
+        else:
+            flags = 'METH_VARARGS'
+        if self.overrides.is_staticmethod(funcname):
+            flags += '|METH_STATIC'
+        elif self.overrides.is_classmethod(funcname):
+            flags += '|METH_CLASS'
+        return flags
+
+    def write_function(self, funcname, data):
+        lineno, filename = self.overrides.getstartline(funcname)
+        self.fp.setline(lineno, filename)
+        self.fp.write(data)
+        self.fp.resetline()
+        self.fp.write('\n\n')
+
+    def _get_class_virtual_substdict(self, meth, cname, parent):
+        substdict = self.get_initial_method_substdict(meth)
+        substdict['virtual'] = substdict['name'].split('.')[1]
+        substdict['cname'] = cname
+        substdict['class_cast_macro'] = parent.typecode.replace(
+            '_TYPE_', '_', 1) + "_CLASS"
+        substdict['typecode'] = self.objinfo.typecode
+        substdict['cast'] = string.replace(parent.typecode, '_TYPE_', '_', 1)
+        return substdict
+
+    def write_methods(self):
+        methods = []
+        klass = self.objinfo.c_name
+        # First, get methods from the defs files
+        for meth in self.parser.find_methods(self.objinfo):
+            method_name = meth.c_name
+            if self.overrides.is_ignored(method_name):
+                continue
+            try:
+                if self.overrides.is_overriden(method_name):
+                    if not self.overrides.is_already_included(method_name):
+                        data = self.overrides.override(method_name)
+                        self.write_function(method_name, data)
+
+                    methflags = self.get_methflags(method_name)
+                else:
+                    # write constructor from template ...
+                    code, methflags = self.write_function_wrapper(meth,
+                        self.method_tmpl, handle_return=1, is_method=1,
+                        substdict=self.get_initial_method_substdict(meth))
+                    self.fp.write(code)
+                methods.append(self.methdef_tmpl %
+                               { 'name':  fixname(meth.name),
+                                 'cname': '_wrap_' + method_name,
+                                 'flags': methflags,
+                                 'docstring': meth.docstring })
+                methods_coverage.declare_wrapped()
+            except:
+                methods_coverage.declare_not_wrapped()
+                sys.stderr.write('Could not write method %s.%s: %s\n'
+                                % (klass, meth.name, exc_info()))
+
+        # Now try to see if there are any defined in the override
+        for method_name in self.overrides.get_defines_for(klass):
+            c_name = override.class2cname(klass, method_name)
+            if self.overrides.is_already_included(method_name):
+                continue
+
+            try:
+                data = self.overrides.define(klass, method_name)
+                self.write_function(method_name, data)
+                methflags = self.get_methflags(method_name)
+
+                methods.append(self.methdef_tmpl %
+                               { 'name':  method_name,
+                                 'cname': '_wrap_' + c_name,
+                                 'flags': methflags,
+                                 'docstring': meth.docstring })
+                methods_coverage.declare_wrapped()
+            except:
+                methods_coverage.declare_not_wrapped()
+                sys.stderr.write('Could not write method %s.%s: %s\n'
+                                % (klass, meth.name, exc_info()))
+
+        # Add GObject virtual method accessors, for chaining to parent
+        # virtuals from subclasses
+        methods += self.write_virtual_accessors()
+
+        if methods:
+            methoddefs = '_Py%s_methods' % self.objinfo.c_name
+            # write the PyMethodDef structure
+            methods.append('    { NULL, NULL, 0, NULL }\n')
+            self.fp.write('static const PyMethodDef %s[] = {\n' % methoddefs)
+            self.fp.write(string.join(methods, ''))
+            self.fp.write('};\n\n')
+        else:
+            methoddefs = 'NULL'
+        return methoddefs
+
+    def write_virtual_accessors(self):
+        klass = self.objinfo.c_name
+        methods = []
+        for meth in self.parser.find_virtuals(self.objinfo):
+            method_name = self.objinfo.c_name + "__do_" + meth.name
+            if self.overrides.is_ignored(method_name):
+                continue
+            try:
+                if self.overrides.is_overriden(method_name):
+                    if not self.overrides.is_already_included(method_name):
+                        data = self.overrides.override(method_name)
+                        self.write_function(method_name, data)
+                    methflags = self.get_methflags(method_name)
+                else:
+                    # temporarily add a 'self' parameter as first argument
+                    meth.params.insert(0, definitions.Parameter(
+                        ptype=(self.objinfo.c_name + '*'),
+                        pname='self', pdflt=None, pnull=None))
+                    try:
+                        # write method from template ...
+                        code, methflags = self.write_function_wrapper(
+                            meth, self.virtual_accessor_tmpl,
+                            handle_return=True, is_method=False,
+                            substdict=self._get_class_virtual_substdict(
+                            meth, method_name, self.objinfo))
+                        self.fp.write(code)
+                    finally:
+                        del meth.params[0]
+                methods.append(self.methdef_tmpl %
+                               { 'name':  "do_" + fixname(meth.name),
+                                 'cname': '_wrap_' + method_name,
+                                 'flags': methflags + '|METH_CLASS',
+                                 'docstring': 'NULL'})
+                vaccessors_coverage.declare_wrapped()
+            except:
+                vaccessors_coverage.declare_not_wrapped()
+                sys.stderr.write(
+                    'Could not write virtual accessor method %s.%s: %s\n'
+                    % (klass, meth.name, exc_info()))
+        return methods
+
+    def write_virtuals(self):
+        '''
+        Write _wrap_FooBar__proxy_do_zbr() reverse wrapers for
+        GObject virtuals
+        '''
+        klass = self.objinfo.c_name
+        virtuals = []
+        for meth in self.parser.find_virtuals(self.objinfo):
+            method_name = self.objinfo.c_name + "__proxy_do_" + meth.name
+            if self.overrides.is_ignored(method_name):
+                continue
+            try:
+                if self.overrides.is_overriden(method_name):
+                    if not self.overrides.is_already_included(method_name):
+                        data = self.overrides.override(method_name)
+                        self.write_function(method_name, data)
+                else:
+                    # write virtual proxy ...
+                    ret, props = argtypes.matcher.get_reverse_ret(meth.ret)
+                    wrapper = reversewrapper.ReverseWrapper(
+                        '_wrap_' + method_name, is_static=True)
+                    wrapper.set_return_type(ret(wrapper, **props))
+                    wrapper.add_parameter(reversewrapper.PyGObjectMethodParam(
+                        wrapper, "self", method_name="do_" + meth.name,
+                        c_type=(klass + ' *')))
+                    for param in meth.params:
+                        handler, props = argtypes.matcher.get_reverse(
+                            param.ptype)
+                        props["direction"] = param.pdir
+                        wrapper.add_parameter(handler(wrapper,
+                                                      param.pname, **props))
+                    buf = reversewrapper.MemoryCodeSink()
+                    wrapper.generate(buf)
+                    self.fp.write(buf.flush())
+                virtuals.append((fixname(meth.name), '_wrap_' + method_name))
+                vproxies_coverage.declare_wrapped()
+            except (KeyError, ValueError):
+                vproxies_coverage.declare_not_wrapped()
+                virtuals.append((fixname(meth.name), None))
+                sys.stderr.write('Could not write virtual proxy %s.%s: %s\n'
+                                % (klass, meth.name, exc_info()))
+        if virtuals:
+            # Write a 'pygtk class init' function for this object,
+            # except when the object type is explicitly ignored (like
+            # GtkPlug and GtkSocket on win32).
+            if self.overrides.is_ignored(self.objinfo.typecode):
+                return
+            class_cast_macro = self.objinfo.typecode.replace(
+                '_TYPE_', '_', 1) + "_CLASS"
+            cast_macro = self.objinfo.typecode.replace('_TYPE_', '_', 1)
+            funcname = "__%s_class_init" % klass
+            self.objinfo.class_init_func = funcname
+            have_implemented_virtuals = not not [True
+                                                 for name, cname in virtuals
+                                                     if cname is not None]
+            self.fp.write(
+            ('\nstatic int\n'
+             '%(funcname)s(gpointer gclass, PyTypeObject *pyclass)\n'
+             '{\n') % vars())
+
+            if have_implemented_virtuals:
+                self.fp.write('    PyObject *o;\n')
+                self.fp.write(
+                    '    %(klass)sClass *klass = '
+                    '%(class_cast_macro)s(gclass);\n'
+                    '    PyObject *gsignals = '
+                    'PyDict_GetItemString(pyclass->tp_dict, "__gsignals__");\n'
+                    % vars())
+
+            for name, cname in virtuals:
+                do_name = 'do_' + name
+                if cname is None:
+                    self.fp.write('\n    /* overriding %(do_name)s '
+                                  'is currently not supported */\n' % vars())
+                else:
+                    self.fp.write('''
+    o = PyObject_GetAttrString((PyObject *) pyclass, "%(do_name)s");
+    if (o == NULL)
+        PyErr_Clear();
+    else {
+        if (!PyObject_TypeCheck(o, &PyCFunction_Type)
+            && !(gsignals && PyDict_GetItemString(gsignals, "%(name)s")))
+            klass->%(name)s = %(cname)s;
+        Py_DECREF(o);
+    }
+''' % vars())
+            self.fp.write('    return 0;\n}\n')
+
+    def write_getsets(self):
+        lower_name = self.get_lower_name()
+        getsets_name = lower_name + '_getsets'
+        getterprefix = '_wrap_' + lower_name + '__get_'
+        setterprefix = '_wrap_' + lower_name + '__set_'
+
+        # no overrides for the whole function.  If no fields,
+        # don't write a func
+        if not self.objinfo.fields:
+            return '0'
+        getsets = []
+        for ftype, cfname in self.objinfo.fields:
+            fname = cfname.replace('.', '_')
+            gettername = '0'
+            settername = '0'
+            attrname = self.objinfo.c_name + '.' + fname
+            if self.overrides.attr_is_overriden(attrname):
+                code = self.overrides.attr_override(attrname)
+                self.write_function(attrname, code)
+                if string.find(code, getterprefix + fname) >= 0:
+                    gettername = getterprefix + fname
+                if string.find(code, setterprefix + fname) >= 0:
+                    settername = setterprefix + fname
+            if gettername == '0':
+                try:
+                    funcname = getterprefix + fname
+                    info = argtypes.WrapperInfo()
+                    handler = argtypes.matcher.get(ftype)
+                    # for attributes, we don't own the "return value"
+                    handler.write_return(ftype, 0, info)
+                    self.fp.write(self.getter_tmpl %
+                                  { 'funcname': funcname,
+                                    'varlist': info.varlist,
+                                    'field': self.get_field_accessor(cfname),
+                                    'codeafter': info.get_codeafter() })
+                    gettername = funcname
+                except:
+                    sys.stderr.write(
+                        "Could not write getter for %s.%s: %s\n"
+                        % (self.objinfo.c_name, fname, exc_info()))
+            if gettername != '0' or settername != '0':
+                getsets.append('    { "%s", (getter)%s, (setter)%s },\n' %
+                               (fixname(fname), gettername, settername))
+
+        if not getsets:
+            return '0'
+        self.fp.write('static const PyGetSetDef %s[] = {\n' % getsets_name)
+        for getset in getsets:
+            self.fp.write(getset)
+        self.fp.write('    { NULL, (getter)0, (setter)0 },\n')
+        self.fp.write('};\n\n')
+
+        return getsets_name
+
+    def write_functions(self, prefix):
+        self.fp.write('\n/* ----------- functions ----------- */\n\n')
+        functions = []
+
+        # First, get methods from the defs files
+        for func in self.parser.find_functions():
+            funcname = func.c_name
+            if self.overrides.is_ignored(funcname):
+                continue
+            try:
+                if self.overrides.is_overriden(funcname):
+                    data = self.overrides.override(funcname)
+                    self.write_function(funcname, data)
+
+                    methflags = self.get_methflags(funcname)
+                else:
+                    # write constructor from template ...
+                    code, methflags = self.write_function_wrapper(func,
+                        self.function_tmpl, handle_return=1, is_method=0)
+                    self.fp.write(code)
+                functions.append(self.methdef_tmpl %
+                                 { 'name':  func.name,
+                                   'cname': '_wrap_' + funcname,
+                                   'flags': methflags,
+                                   'docstring': func.docstring })
+                functions_coverage.declare_wrapped()
+            except:
+                functions_coverage.declare_not_wrapped()
+                sys.stderr.write('Could not write function %s: %s\n'
+                                 % (func.name, exc_info()))
+
+        # Now try to see if there are any defined in the override
+        for funcname in self.overrides.get_functions():
+            try:
+                data = self.overrides.function(funcname)
+                self.write_function(funcname, data)
+                methflags = self.get_methflags(funcname)
+                functions.append(self.methdef_tmpl %
+                                 { 'name':  funcname,
+                                   'cname': '_wrap_' + funcname,
+                                   'flags': methflags,
+                                   'docstring': 'NULL'})
+                functions_coverage.declare_wrapped()
+            except:
+                functions_coverage.declare_not_wrapped()
+                sys.stderr.write('Could not write function %s: %s\n'
+                                 % (funcname, exc_info()))
+
+        # write the PyMethodDef structure
+        functions.append('    { NULL, NULL, 0, NULL }\n')
+
+        self.fp.write('const PyMethodDef ' + prefix + '_functions[] = {\n')
+        self.fp.write(string.join(functions, ''))
+        self.fp.write('};\n\n')
+
+class GObjectWrapper(Wrapper):
+    constructor_tmpl = (
+        'static int\n'
+        '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n'
+        '{\n'
+        '%(varlist)s'
+        '%(parseargs)s'
+        '%(codebefore)s'
+        '    self->obj = (GObject *)%(cname)s(%(arglist)s);\n'
+        '%(codeafter)s\n'
+        '    if (!self->obj) {\n'
+        '        PyErr_SetString(PyExc_RuntimeError, '
+        '"could not create %(typename)s object");\n'
+        '        return -1;\n'
+        '    }\n'
+        '%(aftercreate)s'
+        '    pygobject_register_wrapper((PyObject *)self);\n'
+        '    return 0;\n'
+        '}\n\n'
+        )
+
+    method_tmpl = (
+        'static PyObject *\n'
+        '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n'
+        '{\n'
+        '%(varlist)s'
+        '%(parseargs)s'
+        '%(codebefore)s'
+        '    %(begin_allow_threads)s\n'
+        '    %(setreturn)s%(cname)s(%(cast)s(self->obj)%(arglist)s);\n'
+        '    %(end_allow_threads)s\n'
+        '%(codeafter)s\n'
+        '}\n\n'
+        )
+    def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)):
+        Wrapper.__init__(self, parser, objinfo, overrides, fp)
+        if self.objinfo:
+            self.castmacro = string.replace(self.objinfo.typecode,
+                                            '_TYPE_', '_', 1)
+
+    def get_initial_class_substdict(self):
+        return { 'tp_basicsize'      : 'PyGObject',
+                 'tp_weaklistoffset' : 'offsetof(PyGObject, weakreflist)',
+                 'tp_dictoffset'     : 'offsetof(PyGObject, inst_dict)' }
+
+    def get_field_accessor(self, fieldname):
+        castmacro = string.replace(self.objinfo.typecode, '_TYPE_', '_', 1)
+        return '%s(pygobject_get(self))->%s' % (castmacro, fieldname)
+
+    def get_initial_constructor_substdict(self, constructor):
+        substdict = Wrapper.get_initial_constructor_substdict(self,
+                                                              constructor)
+        if not constructor.caller_owns_return:
+            substdict['aftercreate'] = "    g_object_ref(self->obj);\n"
+        else:
+            substdict['aftercreate'] = ''
+        return substdict
+
+    def get_initial_method_substdict(self, method):
+        substdict = Wrapper.get_initial_method_substdict(self, method)
+        substdict['cast'] = string.replace(self.objinfo.typecode,
+                                           '_TYPE_', '_', 1)
+        return substdict
+
+    def write_default_constructor(self):
+        try:
+            parent = self.parser.find_object(self.objinfo.parent)
+        except ValueError:
+            parent = None
+        if parent is not None:
+            ## just like the constructor is inheritted, we should
+            # inherit the new API compatibility flag
+            self.objinfo.has_new_constructor_api = (
+                parent.has_new_constructor_api)
+        elif self.objinfo.parent == 'GObject':
+            self.objinfo.has_new_constructor_api = True
+        return '0'
+
+    def write_property_based_constructor(self, constructor):
+        self.objinfo.has_new_constructor_api = True
+        out = self.fp
+        print >> out, "static int"
+        print >> out, '_wrap_%s(PyGObject *self, PyObject *args,' \
+              ' PyObject *kwargs)\n{' % constructor.c_name
+        if constructor.params:
+            s = "    GType obj_type = pyg_type_from_object((PyObject *) self);"
+            print >> out, s
+
+        def py_str_list_to_c(arg):
+            if arg:
+                return "{" + ", ".join(
+                    map(lambda s: '"' + s + '"', arg)) + ", NULL }"
+            else:
+                return "{ NULL }"
+
+        classname = '%s.%s' % (self.overrides.modulename,
+                               self.objinfo.name)
+
+        if constructor.params:
+            mandatory_arguments = [param for param in constructor.params
+                                             if not param.optional]
+            optional_arguments = [param for param in constructor.params
+                                            if param.optional]
+            arg_names = py_str_list_to_c(
+            [param.argname
+             for param in mandatory_arguments + optional_arguments])
+
+            prop_names = py_str_list_to_c(
+            [param.pname
+             for param in mandatory_arguments + optional_arguments])
+
+            print >> out, "    GParameter params[%i];" % \
+                  len(constructor.params)
+            print >> out, "    PyObject *parsed_args[%i] = {NULL, };" % \
+                  len(constructor.params)
+            print >> out, "    char *arg_names[] = %s;" % arg_names
+            print >> out, "    char *prop_names[] = %s;" % prop_names
+            print >> out, "    guint nparams, i;"
+            print >> out
+            if constructor.deprecated is not None:
+                out.write(
+                    '    if (PyErr_Warn(PyExc_DeprecationWarning, '
+                    '"%s") < 0)\n' %
+                    constructor.deprecated)
+                print >> out, '        return -1;'
+                print >> out
+            out.write("    if (!PyArg_ParseTupleAndKeywords(args, kwargs, ")
+            template = '"'
+            if mandatory_arguments:
+                template += "O"*len(mandatory_arguments)
+            if optional_arguments:
+                template += "|" + "O"*len(optional_arguments)
+            template += ':%s.__init__"' % classname
+            print >> out, template, ", arg_names",
+            for i in range(len(constructor.params)):
+                print >> out, ", &parsed_args[%i]" % i,
+
+            out.write(
+                "))\n"
+                "        return -1;\n"
+                "\n"
+                "    memset(params, 0, sizeof(GParameter)*%i);\n"
+                "    if (!pyg_parse_constructor_args(obj_type, arg_names,\n"
+                "                                    prop_names, params, \n"
+                "                                    &nparams, parsed_args))\n"
+                "        return -1;\n"
+                "    pygobject_constructv(self, nparams, params);\n"
+                "    for (i = 0; i < nparams; ++i)\n"
+                "        g_value_unset(&params[i].value);\n"
+                % len(constructor.params))
+        else:
+            out.write(
+                "    static char* kwlist[] = { NULL };\n"
+                "\n")
+
+            if constructor.deprecated is not None:
+                out.write(
+                    '    if (PyErr_Warn(PyExc_DeprecationWarning, "%s") < 0)\n'
+                    '        return -1;\n'
+                    '\n' % constructor.deprecated)
+
+            out.write(
+                '    if (!PyArg_ParseTupleAndKeywords(args, kwargs,\n'
+                '                                     ":%s.__init__",\n'
+                '                                     kwlist))\n'
+                '        return -1;\n'
+                '\n'
+                '    pygobject_constructv(self, 0, NULL);\n' % classname)
+        out.write(
+            '    if (!self->obj) {\n'
+            '        PyErr_SetString(\n'
+            '            PyExc_RuntimeError, \n'
+            '            "could not create %s object");\n'
+            '        return -1;\n'
+            '    }\n' % classname)
+
+        if not constructor.caller_owns_return:
+            print >> out, "    g_object_ref(self->obj);\n"
+
+        out.write(
+            '    return 0;\n'
+            '}\n\n')
+
+        return "_wrap_%s" % constructor.c_name
+
+
+## TODO : Add GstMiniObjectWrapper(Wrapper)
+class GstMiniObjectWrapper(Wrapper):
+    constructor_tmpl = (
+        'static int\n'
+        '_wrap_%(cname)s(PyGstMiniObject *self%(extraparams)s)\n'
+        '{\n'
+        '%(varlist)s'
+        '%(parseargs)s'
+        '%(codebefore)s'
+        '    self->obj = (GstMiniObject *)%(cname)s(%(arglist)s);\n'
+        '%(codeafter)s\n'
+        '    if (!self->obj) {\n'
+        '        PyErr_SetString(PyExc_RuntimeError, '
+        '"could not create %(typename)s miniobject");\n'
+        '        return -1;\n'
+        '    }\n'
+        '%(aftercreate)s'
+        '    pygstminiobject_register_wrapper((PyObject *)self);\n'
+        '    return 0;\n'
+        '}\n\n'
+        )
+    method_tmpl = (
+        'static PyObject *\n'
+        '_wrap_%(cname)s(PyGstMiniObject *self%(extraparams)s)\n'
+        '{\n'
+        '%(varlist)s'
+        '%(parseargs)s'
+        '%(codebefore)s'
+        '    %(begin_allow_threads)s\n'
+        '    %(setreturn)s%(cname)s(%(cast)s(self->obj)%(arglist)s);\n'
+        '    %(end_allow_threads)s\n'
+        '%(codeafter)s\n'
+        '}\n\n'
+        )
+    def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)):
+        Wrapper.__init__(self, parser, objinfo, overrides, fp)
+        if self.objinfo:
+            self.castmacro = string.replace(self.objinfo.typecode,
+                                            '_TYPE_', '_', 1)
+
+    def get_initial_class_substdict(self):
+        return { 'tp_basicsize'      : 'PyGstMiniObject',
+                 'tp_weaklistoffset' : 'offsetof(PyGstMiniObject, weakreflist)',
+                 'tp_dictoffset'     : 'offsetof(PyGstMiniObject, inst_dict)' }
+    
+    def get_field_accessor(self, fieldname):
+        castmacro = string.replace(self.objinfo.typecode, '_TYPE_', '_', 1)
+        return '%s(pygstminiobject_get(self))->%s' % (castmacro, fieldname)
+
+    def get_initial_constructor_substdict(self, constructor):
+        substdict = Wrapper.get_initial_constructor_substdict(self,
+                                                              constructor)
+        if not constructor.caller_owns_return:
+            substdict['aftercreate'] = "    gst_mini_object_ref(self->obj);\n"
+        else:
+            substdict['aftercreate'] = ''
+        return substdict
+
+    def get_initial_method_substdict(self, method):
+        substdict = Wrapper.get_initial_method_substdict(self, method)
+        substdict['cast'] = string.replace(self.objinfo.typecode,
+                                           '_TYPE_', '_', 1)
+        return substdict
+    
+
+
+class GInterfaceWrapper(GObjectWrapper):
+    virtual_accessor_tmpl = (
+        'static PyObject *\n'
+        '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n'
+        '{\n'
+        '    %(vtable)s *iface;\n'
+        '%(varlist)s'
+        '%(parseargs)s'
+        '%(codebefore)s'
+        '    iface = g_type_interface_peek('
+        'g_type_class_peek(pyg_type_from_object(cls)), %(typecode)s);\n'
+        '    if (iface->%(virtual)s)\n'
+        '        %(setreturn)siface->%(virtual)s(%(arglist)s);\n'
+        '    else {\n'
+        '        PyErr_SetString(PyExc_NotImplementedError, '
+        '"interface method %(name)s not implemented");\n'
+        '        return NULL;\n'
+        '    }\n'
+        '%(codeafter)s\n'
+        '}\n\n'
+        )
+
+    def get_initial_class_substdict(self):
+        return { 'tp_basicsize'      : 'PyObject',
+                 'tp_weaklistoffset' : '0',
+                 'tp_dictoffset'     : '0'}
+
+    def write_constructor(self):
+        # interfaces have no constructors ...
+        return '0'
+    def write_getsets(self):
+        # interfaces have no fields ...
+        return '0'
+
+    def _get_class_virtual_substdict(self, meth, cname, parent):
+        substdict = self.get_initial_method_substdict(meth)
+        substdict['virtual'] = substdict['name'].split('.')[1]
+        substdict['cname'] = cname
+        substdict['typecode'] = self.objinfo.typecode
+        substdict['vtable'] = self.objinfo.vtable
+        return substdict
+
+    def write_virtuals(self):
+        ## Now write reverse method wrappers, which let python code
+        ## implement interface methods.
+        # First, get methods from the defs files
+        klass = self.objinfo.c_name
+        proxies = []
+        for meth in self.parser.find_virtuals(self.objinfo):
+            method_name = self.objinfo.c_name + "__proxy_do_" + meth.name
+            if self.overrides.is_ignored(method_name):
+                continue
+            try:
+                if self.overrides.is_overriden(method_name):
+                    if not self.overrides.is_already_included(method_name):
+                        data = self.overrides.override(method_name)
+                        self.write_function(method_name, data)
+                else:
+                    # write proxy ...
+                    ret, props = argtypes.matcher.get_reverse_ret(meth.ret)
+                    wrapper = reversewrapper.ReverseWrapper(
+                        '_wrap_' + method_name, is_static=True)
+                    wrapper.set_return_type(ret(wrapper, **props))
+                    wrapper.add_parameter(reversewrapper.PyGObjectMethodParam(
+                        wrapper, "self", method_name="do_" + meth.name,
+                        c_type=(klass + ' *')))
+                    for param in meth.params:
+                        handler, props = argtypes.matcher.get_reverse(
+                            param.ptype)
+                        props["direction"] = param.pdir
+                        wrapper.add_parameter(
+                            handler(wrapper, param.pname, **props))
+                    buf = reversewrapper.MemoryCodeSink()
+                    wrapper.generate(buf)
+                    self.fp.write(buf.flush())
+                proxies.append((fixname(meth.name), '_wrap_' + method_name))
+                iproxies_coverage.declare_wrapped()
+            except (KeyError, ValueError):
+                iproxies_coverage.declare_not_wrapped()
+                proxies.append((fixname(meth.name), None))
+                sys.stderr.write('Could not write interface proxy %s.%s: %s\n'
+                                % (klass, meth.name, exc_info()))
+
+        if not proxies:
+            return
+
+        # Make sure we have at least one proxy function
+        if not [cname for name,cname in proxies if not cname is None]:
+            return
+        
+        ## Write an interface init function for this object
+        funcname = "__%s__interface_init" % klass
+        vtable = self.objinfo.vtable
+        self.fp.write(
+            '\nstatic void\n'
+            '%(funcname)s(%(vtable)s *iface, PyTypeObject *pytype)\n'
+            '{\n'
+            '    %(vtable)s *parent_iface = '
+            'g_type_interface_peek_parent(iface);\n'
+            '    PyObject *py_method;\n'
+            '\n'
+            % vars())
+
+        for name, cname in proxies:
+            do_name = 'do_' + name
+            if cname is None:
+                continue
+
+            self.fp.write((
+                '    py_method = pytype? PyObject_GetAttrString('
+                '(PyObject *) pytype, "%(do_name)s") : NULL;\n'
+                '    if (py_method && !PyObject_TypeCheck(py_method, '
+                '&PyCFunction_Type)) {\n'
+                '        iface->%(name)s = %(cname)s;\n'
+                '    } else {\n'
+                '        PyErr_Clear();\n'
+                '        if (parent_iface) {\n'
+                '            iface->%(name)s = parent_iface->%(name)s;\n'
+                '        }\n'
+                '    Py_XDECREF(py_method);\n'
+                '    }\n'
+                ) % vars())
+        self.fp.write('}\n\n')
+        interface_info = "__%s__iinfo" % klass
+        self.fp.write('''
+static const GInterfaceInfo %s = {
+    (GInterfaceInitFunc) %s,
+    NULL,
+    NULL
+};
+''' % (interface_info, funcname))
+        self.objinfo.interface_info = interface_info
+
+class GBoxedWrapper(Wrapper):
+    constructor_tmpl = (
+        'static int\n'
+        '_wrap_%(cname)s(PyGBoxed *self%(extraparams)s)\n'
+        '{\n' \
+        '%(varlist)s'
+        '%(parseargs)s'
+        '%(codebefore)s'
+        '    self->gtype = %(typecode)s;\n'
+        '    self->free_on_dealloc = FALSE;\n'
+        '    self->boxed = %(cname)s(%(arglist)s);\n'
+        '%(codeafter)s\n'
+        '    if (!self->boxed) {\n'
+        '        PyErr_SetString(PyExc_RuntimeError, '
+        '"could not create %(typename)s object");\n'
+        '        return -1;\n'
+        '    }\n'
+        '    self->free_on_dealloc = TRUE;\n'
+        '    return 0;\n'
+        '}\n\n'
+        )
+
+    method_tmpl = (
+        'static PyObject *\n'
+        '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n'
+        '{\n'
+        '%(varlist)s'
+        '%(parseargs)s'
+        '%(codebefore)s'
+        '    %(begin_allow_threads)s\n'
+        '    %(setreturn)s%(cname)s(pyg_boxed_get(self, '
+        '%(typename)s)%(arglist)s);\n'
+        '    %(end_allow_threads)s\n'
+        '%(codeafter)s\n'
+        '}\n\n'
+        )
+
+    def get_initial_class_substdict(self):
+        return { 'tp_basicsize'      : 'PyGBoxed',
+                 'tp_weaklistoffset' : '0',
+                 'tp_dictoffset'     : '0' }
+
+    def get_field_accessor(self, fieldname):
+        return 'pyg_boxed_get(self, %s)->%s' % (self.objinfo.c_name, fieldname)
+
+    def get_initial_constructor_substdict(self, constructor):
+        substdict = Wrapper.get_initial_constructor_substdict(
+            self, constructor)
+        substdict['typecode'] = self.objinfo.typecode
+        return substdict
+
+class GPointerWrapper(GBoxedWrapper):
+    constructor_tmpl = (
+        'static int\n'
+        '_wrap_%(cname)s(PyGPointer *self%(extraparams)s)\n'
+        '{\n'
+        '%(varlist)s'
+        '%(parseargs)s'
+        '%(codebefore)s'
+        '    self->gtype = %(typecode)s;\n'
+        '    self->pointer = %(cname)s(%(arglist)s);\n'
+        '%(codeafter)s\n'
+        '    if (!self->pointer) {\n'
+        '        PyErr_SetString(PyExc_RuntimeError, '
+        '"could not create %(typename)s object");\n'
+        '        return -1;\n'
+        '    }\n'
+        '    return 0;\n'
+        '}\n\n'
+        )
+
+    method_tmpl = (
+        'static PyObject *\n'
+        '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n'
+        '{\n'
+        '%(varlist)s'
+        '%(parseargs)s'
+        '%(codebefore)s'
+        '    %(setreturn)s%(cname)s(pyg_pointer_get(self, '
+        '%(typename)s)%(arglist)s);\n'
+        '%(codeafter)s\n'
+        '}\n\n'
+        )
+
+    def get_initial_class_substdict(self):
+        return { 'tp_basicsize'      : 'PyGPointer',
+                 'tp_weaklistoffset' : '0',
+                 'tp_dictoffset'     : '0' }
+
+    def get_field_accessor(self, fieldname):
+        return 'pyg_pointer_get(self, %s)->%s' % (self.objinfo.c_name,
+                                                  fieldname)
+
+    def get_initial_constructor_substdict(self, constructor):
+        substdict = Wrapper.get_initial_constructor_substdict(
+            self, constructor)
+        substdict['typecode'] = self.objinfo.typecode
+        return substdict
+
+def write_headers(data, fp):
+    fp.write('/* -- THIS FILE IS GENERATED - DO NOT EDIT */')
+    fp.write('/* -*- Mode: C; c-basic-offset: 4 -*- */\n\n')
+    fp.write('#include <Python.h>\n\n\n')
+    fp.write(data)
+    fp.resetline()
+    fp.write('\n\n')
+
+def write_body(data, fp):
+    fp.write(data)
+    fp.resetline()
+    fp.write('\n\n')
+
+def write_imports(overrides, fp):
+    fp.write('/* ---------- types from other modules ---------- */\n')
+    for module, pyname, cname in overrides.get_imports():
+        fp.write('static PyTypeObject *_%s;\n' % cname)
+        fp.write('#define %s (*_%s)\n' % (cname, cname))
+    fp.write('\n\n')
+
+def write_type_declarations(parser, fp):
+    fp.write('/* ---------- forward type declarations ---------- */\n')
+    for obj in parser.boxes:
+        fp.write('PyTypeObject Py' + obj.c_name + '_Type;\n')
+    for obj in parser.objects:
+        fp.write('PyTypeObject Py' + obj.c_name + '_Type;\n')
+    for obj in parser.miniobjects:
+        fp.write('PyTypeObject Py' + obj.c_name + '_Type;\n')
+    for interface in parser.interfaces:
+        fp.write('PyTypeObject Py' + interface.c_name + '_Type;\n')
+    fp.write('\n')
+
+
+def sort_parent_children(objects):
+    objects = list(objects)
+    modified = True
+    while modified:
+        modified = False
+        parent_index = None
+        child_index = None
+        for i, obj in enumerate(objects):
+            if obj.parent == 'GObject':
+                continue
+            if obj.parent not in [info.c_name for info in objects[:i]]:
+                for j, info in enumerate(objects[i+1:]):
+                    if info.c_name == obj.parent:
+                        parent_index = i + 1 + j
+                        child_index = i
+                        break
+                else:
+                    continue
+                break
+        if child_index is not None and parent_index is not None:
+            if child_index != parent_index:
+                objects.insert(child_index, objects.pop(parent_index))
+                modified = True
+    return objects
+
+def write_classes(parser, overrides, fp):
+    ## Sort the objects, so that we generate code for the parent types
+    ## before their children.
+    objects = sort_parent_children(parser.objects)
+    for klass, items in ((GBoxedWrapper, parser.boxes),
+                         (GPointerWrapper, parser.pointers),
+                         (GObjectWrapper, objects),
+                         (GstMiniObjectWrapper, parser.miniobjects),
+                         (GInterfaceWrapper, parser.interfaces)):
+        for item in items:
+            instance = klass(parser, item, overrides, fp)
+            instance.write_class()
+            fp.write('\n')
+
+def write_enums(parser, overrides, prefix, fp=sys.stdout):
+    if not parser.enums:
+        return
+    fp.write('\n/* ----------- enums and flags ----------- */\n\n')
+    fp.write(
+        'void\n' + prefix +
+        '_add_constants(PyObject *module, const gchar *strip_prefix)\n{\n')
+
+    for enum in parser.enums:
+        if overrides.is_type_ignored(enum.c_name):
+            continue
+        if enum.typecode is None:
+            for nick, value in enum.values:
+                fp.write(
+                    '    PyModule_AddIntConstant(module, '
+                    '(char *) pyg_constant_strip_prefix("%s", strip_prefix), %s);\n'
+                    % (value, value))
+        else:
+            if enum.deftype == 'enum':
+                fp.write('  pyg_enum_add(module, "%s", strip_prefix, %s);\n'
+                         % (enum.name, enum.typecode))
+            else:
+                fp.write('  pyg_flags_add(module, "%s", strip_prefix, %s);\n'
+                         % (enum.name, enum.typecode))
+
+    fp.write('\n')
+    fp.write('  if (PyErr_Occurred())\n')
+    fp.write('    PyErr_Print();\n')
+    fp.write('}\n\n')
+
+def write_extension_init(overrides, prefix, fp):
+    fp.write('/* initialise stuff extension classes */\n')
+    fp.write('void\n' + prefix + '_register_classes(PyObject *d)\n{\n')
+    imports = overrides.get_imports()[:]
+    if imports:
+        bymod = {}
+        for module, pyname, cname in imports:
+            bymod.setdefault(module, []).append((pyname, cname))
+        fp.write('    PyObject *module;\n\n')
+        for module in bymod:
+            fp.write(
+                '    if ((module = PyImport_ImportModule("%s")) != NULL) {\n'
+                % module)
+            fp.write(
+                '        PyObject *moddict = PyModule_GetDict(module);\n\n')
+            for pyname, cname in bymod[module]:
+                fp.write(
+                    '        _%s = (PyTypeObject *)PyDict_GetItemString('
+                    'moddict, "%s");\n' % (cname, pyname))
+                fp.write('        if (_%s == NULL) {\n' % cname)
+                fp.write('            PyErr_SetString(PyExc_ImportError,\n')
+                fp.write('                "cannot import name %s from %s");\n'
+                         % (pyname, module))
+                fp.write('            return;\n')
+                fp.write('        }\n')
+            fp.write('    } else {\n')
+            fp.write('        PyErr_SetString(PyExc_ImportError,\n')
+            fp.write('            "could not import %s");\n' % module)
+            fp.write('        return;\n')
+            fp.write('    }\n')
+        fp.write('\n')
+    fp.write(overrides.get_init() + '\n')
+    fp.resetline()
+
+def write_registers(parser, overrides, fp):
+    for boxed in parser.boxes:
+        if overrides.is_type_ignored(boxed.c_name):
+            continue
+        fp.write('    pyg_register_boxed(d, "' + boxed.name +
+                 '", ' + boxed.typecode +
+                 ', &Py' + boxed.c_name +
+                 '_Type);\n')
+    for pointer in parser.pointers:
+        if overrides.is_type_ignored(pointer.c_name):
+            continue
+        fp.write('    pyg_register_pointer(d, "' + pointer.name +
+                 '", ' + pointer.typecode +
+                 ', &Py' + pointer.c_name + '_Type);\n')
+    for interface in parser.interfaces:
+        if overrides.is_type_ignored(interface.c_name):
+            continue
+        fp.write('    pyg_register_interface(d, "' + interface.name +
+                 '", '+ interface.typecode + ', &Py' + interface.c_name +
+                 '_Type);\n')
+        if interface.interface_info is not None:
+            fp.write('    pyg_register_interface_info(%s, &%s);\n' %
+                     (interface.typecode, interface.interface_info))
+
+    objects = parser.objects[:]
+    pos = 0
+    while pos < len(objects):
+        parent = objects[pos].parent
+        for i in range(pos+1, len(objects)):
+            if objects[i].c_name == parent:
+                objects.insert(i+1, objects[pos])
+                del objects[pos]
+                break
+        else:
+            pos = pos + 1
+    for obj in objects:
+        if overrides.is_type_ignored(obj.c_name):
+            continue
+        bases = []
+        if obj.parent != None:
+            bases.append(obj.parent)
+        bases = bases + obj.implements
+        if bases:
+            fp.write('    pygobject_register_class(d, "' + obj.c_name +
+                     '", ' + obj.typecode + ', &Py' + obj.c_name +
+                     '_Type, Py_BuildValue("(' + 'O' * len(bases) + ')", ' +
+                     string.join(map(lambda s: '&Py'+s+'_Type', bases), ', ') +
+                     '));\n')
+        else:
+            fp.write('    pygobject_register_class(d, "' + obj.c_name +
+                     '", ' + obj.typecode + ', &Py' + obj.c_name +
+                     '_Type, NULL);\n')
+        if obj.has_new_constructor_api:
+            fp.write('    pyg_set_object_has_new_constructor(%s);\n' %
+                     obj.typecode)
+        else:
+            print >> sys.stderr, (
+                "Warning: Constructor for %s needs to be updated to new API\n"
+                "         See http://live.gnome.org/PyGTK_2fWhatsNew28"
+                "#update-constructors") % obj.c_name
+        if obj.class_init_func is not None:
+            fp.write('    pyg_register_class_init(%s, %s);\n' %
+                     (obj.typecode, obj.class_init_func))
+    #TODO: register mini-objects
+    miniobjects = parser.miniobjects[:]
+    for obj in miniobjects:
+        bases = []
+        if obj.parent != None:
+            bases.append(obj.parent)
+        bases = bases + obj.implements
+        if bases:
+            fp.write('    pygstminiobject_register_class(d, "' + obj.c_name +
+                     '", ' + obj.typecode + ', &Py' + obj.c_name +
+                     '_Type, Py_BuildValue("(' + 'O' * len(bases) + ')", ' +
+                     string.join(map(lambda s: '&Py'+s+'_Type', bases), ', ') +
+                     '));\n')
+        else:
+            fp.write('    pygstminiobject_register_class(d, "' + obj.c_name +
+                     '", ' + obj.typecode + ', &Py' + obj.c_name +
+                     '_Type, NULL);\n')
+       
+    fp.write('}\n')
+
+def write_source(parser, overrides, prefix, fp=FileOutput(sys.stdout)):
+    write_headers(overrides.get_headers(), fp)
+    write_imports(overrides, fp)
+    write_type_declarations(parser, fp)
+    write_body(overrides.get_body(), fp)
+    write_classes(parser, overrides, fp)
+
+    wrapper = Wrapper(parser, None, overrides, fp)
+    wrapper.write_functions(prefix)
+
+    write_enums(parser, overrides, prefix, fp)
+    write_extension_init(overrides, prefix, fp)
+    write_registers(parser, overrides, fp)
+
+def register_types(parser):
+    for boxed in parser.boxes:
+        argtypes.matcher.register_boxed(boxed.c_name, boxed.typecode)
+    for pointer in parser.pointers:
+        argtypes.matcher.register_pointer(pointer.c_name, pointer.typecode)
+    for obj in parser.objects:
+        argtypes.matcher.register_object(obj.c_name, obj.parent, obj.typecode)
+    for obj in parser.miniobjects:
+        argtypes.matcher.register_miniobject(obj.c_name, obj.parent, obj.typecode)
+    for obj in parser.interfaces:
+        argtypes.matcher.register_object(obj.c_name, None, obj.typecode)
+    for enum in parser.enums:
+        if enum.deftype == 'flags':
+            argtypes.matcher.register_flag(enum.c_name, enum.typecode)
+        else:
+            argtypes.matcher.register_enum(enum.c_name, enum.typecode)
+
+usage = 'usage: codegen.py [-o overridesfile] [-p prefix] defsfile'
+def main(argv):
+    o = override.Overrides()
+    prefix = 'pygtk'
+    outfilename = None
+    errorfilename = None
+    extendpath = []
+    opts, args = getopt.getopt(argv[1:], "o:p:r:t:D:x",
+                        ["override=", "prefix=", "register=", "outfilename=",
+                         "load-types=", "errorfilename=", "extendpath="])
+    defines = {} # -Dkey[=val] options
+
+    for opt, arg in opts:
+        if opt in ('-x', '--extendpath'):
+            extendpath.append(arg)
+    extendpath.insert(0, os.getcwd())
+    o = override.Overrides(path=extendpath)
+    
+    for opt, arg in opts:
+        if opt in ('-o', '--override'):
+            o = override.Overrides(arg, path=extendpath)
+        elif opt in ('-p', '--prefix'):
+            prefix = arg
+        elif opt in ('-r', '--register'):
+            # Warning: user has to make sure all -D options appear before -r
+            p = defsparser.DefsParser(arg, defines)
+            p.startParsing()
+            register_types(p)
+            del p
+        elif opt == '--outfilename':
+            outfilename = arg
+        elif opt == '--errorfilename':
+            errorfilename = arg
+        elif opt in ('-t', '--load-types'):
+            globals = {}
+            execfile(arg, globals)
+        elif opt == '-D':
+            nameval = arg.split('=')
+            try:
+                defines[nameval[0]] = nameval[1]
+            except IndexError:
+                defines[nameval[0]] = None
+    if len(args) < 1:
+        print >> sys.stderr, usage
+        return 1
+    if errorfilename:
+        sys.stderr = open(errorfilename, "w")
+    p = defsparser.DefsParser(args[0], defines)
+    if not outfilename:
+        outfilename = os.path.splitext(args[0])[0] + '.c'
+
+    p.startParsing()
+
+    register_types(p)
+    write_source(p, o, prefix, FileOutput(sys.stdout, outfilename))
+
+    functions_coverage.printstats()
+    methods_coverage.printstats()
+    vproxies_coverage.printstats()
+    vaccessors_coverage.printstats()
+    iproxies_coverage.printstats()
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
diff --git a/bindings/python/codegen/definitions.py b/bindings/python/codegen/definitions.py
new file mode 100644 (file)
index 0000000..911c8dd
--- /dev/null
@@ -0,0 +1,607 @@
+# -*- 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, keeprefcount = False):
+        self.ptype = ptype
+        self.pname = pname
+        self.pdflt = pdflt
+        self.pnull = pnull
+       self.pdir = pdir
+        self.keeprefcount = keeprefcount
+        
+    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
+
+# Parameter for property based constructors
+class Property(object):
+    def __init__(self, pname, optional, argname):
+        self.pname = pname
+        self.optional = optional
+        self.argname = argname
+
+    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:
+    docstring = "NULL"
+    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 MiniObjectDef(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 = []
+       for arg in args:
+           if type(arg) != type(()) or len(arg) < 2:
+               continue
+           if arg[0] == 'in-module':
+               self.module = 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':
+                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
+                   pdir = None
+                    keeprefcount = False
+                    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]
+                        elif farg[0] == 'keep-refcount':
+                            keeprefcount = True
+                    self.params.append(Parameter(ptype, pname, pdflt, pnull, pdir,
+                                                 keeprefcount=keeprefcount))
+            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
+                    keeprefcount = False
+                    for farg in parg[2:]:
+                        if farg[0] == 'default':
+                            pdflt = farg[1]
+                        elif farg[0] == 'null-ok':
+                            pnull = 1
+                        elif farg[0] == 'keep-refcount':
+                            keeprefcount = True
+                    self.params.append(Parameter(ptype, pname, pdflt, pnull,
+                                                 keeprefcount = keeprefcount))
+           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/bindings/python/codegen/defsparser.py b/bindings/python/codegen/defsparser.py
new file mode 100644 (file)
index 0000000..e24a969
--- /dev/null
@@ -0,0 +1,143 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+import os, sys
+import scmexpr
+from definitions import BoxedDef, EnumDef, FlagsDef, FunctionDef, \
+     InterfaceDef, MethodDef, ObjectDef, MiniObjectDef, PointerDef, \
+     VirtualDef
+
+class IncludeParser(scmexpr.Parser):
+    """A simple parser that follows include statements automatically"""
+    def include(self, filename):
+        if not os.path.isabs(filename):
+            filename = os.path.join(os.path.dirname(self.filename), filename)
+
+        # set self.filename to the include name, to handle recursive includes
+        oldfile = self.filename
+        self.filename = filename
+        self.startParsing()
+        self.filename = oldfile
+
+class DefsParser(IncludeParser):
+    def __init__(self, arg, defines={}):
+       IncludeParser.__init__(self, arg)
+       self.objects = []
+        self.miniobjects = []
+        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
+    # TODO: define_mini_object
+    def define_miniobject(self, *args):
+        odef = apply(MiniObjectDef, args)
+        self.miniobjects.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)
+        # TODO: Add miniobject
+        for obj in self.miniobjects:
+            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 not found'
+
+    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:]:
+                self.handle(arg)
+
+    def ifndef(self, *args):
+        if args[0] not in self.defines:
+            for arg in args[1:]:
+                self.handle(arg)
diff --git a/bindings/python/codegen/docextract.py b/bindings/python/codegen/docextract.py
new file mode 100644 (file)
index 0000000..e6c6505
--- /dev/null
@@ -0,0 +1,185 @@
+# -*- 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
+
+__all__ = ['extract']
+
+class FunctionDoc:
+    def __init__(self):
+        self.name = None
+        self.params = []
+        self.description = ''
+        self.ret = ''
+    def set_name(self, name):
+        self.name = name
+    def add_param(self, name, description):
+        if name == '...':
+            name = 'Varargs'
+        self.params.append((name, description))
+    def append_to_last_param(self, extra):
+        self.params[-1] = (self.params[-1][0], self.params[-1][1] + extra)
+    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)
+                return
+        # fall through to adding extra parameter ...
+        self.add_param(name, extra)
+    def append_description(self, extra):
+        self.description = self.description + extra
+    def append_return(self, extra):
+        self.ret = self.ret + extra
+
+    def get_param_description(self, name):
+        for param, description in self.params:
+            if param == name:
+                return description
+        else:
+            return ''
+
+comment_start_pat = re.compile(r'^\s*/\*\*\s')
+comment_end_pat = re.compile(r'^\s*\*+/')
+comment_line_lead = re.compile(r'^\s*\*\s*')
+funcname_pat = re.compile(r'^(\w+)\s*:?')
+return_pat = re.compile(r'^(returns:|return\s+value:|returns\s*)(.*\n?)$',
+                        re.IGNORECASE)
+param_pat = re.compile(r'^@(\S+)\s*:(.*\n?)$')
+
+def parse_file(fp, doc_dict):
+    line = fp.readline()
+    in_comment_block = 0
+    while line:
+        if not in_comment_block:
+            if comment_start_pat.match(line):
+                in_comment_block = 1
+                cur_doc = FunctionDoc()
+                in_description = 0
+                in_return = 0
+            line = fp.readline()
+            continue
+
+        # we are inside a comment block ...
+        if comment_end_pat.match(line):
+            if not cur_doc.name:
+                sys.stderr.write("no function name found in doc comment\n")
+            else:
+                doc_dict[cur_doc.name] = cur_doc
+            in_comment_block = 0
+            line = fp.readline()
+            continue
+
+        # inside a comment block, and not the end of the block ...
+        line = comment_line_lead.sub('', line)
+        if not line: line = '\n'
+
+        if not cur_doc.name:
+            match = funcname_pat.match(line)
+            if match:
+                cur_doc.set_name(match.group(1))
+        elif in_return:
+            match = return_pat.match(line)
+            if match:
+                # assume the last return statement was really part of the
+                # description
+                return_start = match.group(1)
+                cur_doc.ret = match.group(2)
+                cur_doc.description = cur_doc.description + return_start + \
+                                      cur_doc.ret
+            else:
+                cur_doc.append_return(line)
+        elif in_description:
+            if line[:12] == 'Description:':
+                line = line[12:]
+            match = return_pat.match(line)
+            if match:
+                in_return = 1
+                return_start = match.group(1)
+                cur_doc.append_return(match.group(2))
+            else:
+                cur_doc.append_description(line)
+        elif line == '\n':
+            # end of parameters
+            in_description = 1
+        else:
+            match = param_pat.match(line)
+            if match:
+                param = match.group(1)
+                desc = match.group(2)
+                if param == 'returns':
+                    cur_doc.ret = desc
+                else:
+                    cur_doc.add_param(param, desc)
+            else:
+                # must be continuation
+                try:
+                    if param == 'returns':
+                        cur_doc.append_return(line)
+                    else:
+                        cur_doc.append_to_last_param(line)
+                except:
+                    sys.stderr.write('something weird while reading param\n')
+        line = fp.readline()
+
+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':
+            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_pat = re.compile(r'^<!-- ##### (\w+) (\w+) ##### -->$')
+def parse_tmpl(fp, doc_dict):
+    cur_doc = None
+
+    line = fp.readline()
+    while line:
+        match = tmpl_section_pat.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 = FunctionDoc()
+                    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_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_description(line)
+            else:
+                cur_doc.append_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/bindings/python/codegen/docgen.py b/bindings/python/codegen/docgen.py
new file mode 100644 (file)
index 0000000..6905a14
--- /dev/null
@@ -0,0 +1,752 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+import sys, os, string, re, getopt
+
+import defsparser
+import definitions
+import override
+import docextract
+
+class Node:
+    def __init__(self, name, interfaces=[]):
+        self.name = name
+        self.interfaces = interfaces
+        self.subclasses = []
+    def add_child(self, node):
+        self.subclasses.append(node)
+
+def build_object_tree(parser):
+    # reorder objects so that parent classes come first ...
+    objects = parser.objects[:]
+    pos = 0
+    while pos < len(objects):
+        parent = objects[pos].parent
+        for i in range(pos+1, len(objects)):
+            if objects[i].c_name == parent:
+                objects.insert(i+1, objects[pos])
+                del objects[pos]
+                break
+        else:
+            pos = pos + 1
+
+    root = Node(None)
+    nodes = { None: root }
+    for obj_def in objects:
+        print obj_def.name
+        parent_node = nodes[obj_def.parent]
+        node = Node(obj_def.c_name, obj_def.implements)
+        parent_node.add_child(node)
+        nodes[node.name] = node
+
+    if parser.interfaces:
+        interfaces = Node('gobject.GInterface')
+        root.add_child(interfaces)
+        nodes[interfaces.name] = interfaces
+        for obj_def in parser.interfaces:
+            node = Node(obj_def.c_name)
+            interfaces.add_child(node)
+            nodes[node.name] = node
+
+    if parser.boxes:
+        boxed = Node('gobject.GBoxed')
+        root.add_child(boxed)
+        nodes[boxed.name] = boxed
+        for obj_def in parser.boxes:
+            node = Node(obj_def.c_name)
+            boxed.add_child(node)
+            nodes[node.name] = node
+
+    if parser.pointers:
+        pointers = Node('gobject.GPointer')
+        root.add_child(pointers)
+        nodes[pointers.name] = pointers
+        for obj_def in parser.pointers:
+            node = Node(obj_def.c_name)
+            pointers.add_child(node)
+            nodes[node.name] = node
+
+    return root
+
+class DocWriter:
+    def __init__(self):
+        # parse the defs file
+        self.parser = defsparser.DefsParser(())
+        self.overrides = override.Overrides()
+        self.classmap = {}
+        self.docs = {}
+
+    def add_sourcedirs(self, source_dirs):
+        self.docs = docextract.extract(source_dirs, self.docs)
+    def add_tmpldirs(self, tmpl_dirs):
+        self.docs = docextract.extract_tmpl(tmpl_dirs, self.docs)
+
+    def add_docs(self, defs_file, overrides_file, module_name):
+        '''parse information about a given defs file'''
+        self.parser.filename = defs_file
+        self.parser.startParsing(defs_file)
+        if overrides_file:
+            self.overrides.handle_file(overrides_file)
+
+        for obj in self.parser.objects:
+            if not self.classmap.has_key(obj.c_name):
+                self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
+        for obj in self.parser.interfaces:
+            if not self.classmap.has_key(obj.c_name):
+                self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
+        for obj in self.parser.boxes:
+            if not self.classmap.has_key(obj.c_name):
+                self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
+        for obj in self.parser.pointers:
+            if not self.classmap.has_key(obj.c_name):
+                self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
+
+    def pyname(self, name):
+        return self.classmap.get(name, name)
+
+    def __compare(self, obja, objb):
+        return cmp(self.pyname(obja.c_name), self.pyname(objb.c_name))
+    def output_docs(self, output_prefix):
+        files = []
+
+        # class hierarchy
+        hierarchy = build_object_tree(self.parser)
+        filename = self.create_filename('hierarchy', output_prefix)
+        fp = open(filename, 'w')
+        self.write_full_hierarchy(hierarchy, fp)
+        fp.close()
+
+        obj_defs = self.parser.objects + self.parser.interfaces + \
+                   self.parser.boxes + self.parser.pointers
+        obj_defs.sort(self.__compare)
+        for obj_def in obj_defs:
+            filename = self.create_filename(obj_def.c_name, output_prefix)
+            fp = open(filename, 'w')
+            if isinstance(obj_def, definitions.ObjectDef):
+                self.output_object_docs(obj_def, fp)
+            elif isinstance(obj_def, definitions.InterfaceDef):
+                self.output_interface_docs(obj_def, fp)
+            elif isinstance(obj_def, definitions.BoxedDef):
+                self.output_boxed_docs(obj_def, fp)
+            elif isinstance(obj_def, definitions.PointerDef):
+                self.output_boxed_docs(obj_def, fp)
+            fp.close()
+            files.append((os.path.basename(filename), obj_def))
+
+        if files:
+            filename = self.create_toc_filename(output_prefix)
+            fp = open(filename, 'w')
+            self.output_toc(files, fp)
+            fp.close()
+
+    def output_object_docs(self, obj_def, fp=sys.stdout):
+        self.write_class_header(obj_def.c_name, fp)
+
+        self.write_heading('Synopsis', fp)
+        self.write_synopsis(obj_def, fp)
+        self.close_section(fp)
+
+        # construct the inheritence hierarchy ...
+        ancestry = [ (obj_def.c_name, obj_def.implements) ]
+        try:
+            parent = obj_def.parent
+            while parent != None:
+                if parent == 'GObject':
+                    ancestry.append(('GObject', []))
+                    parent = None
+                else:
+                    parent_def = self.parser.find_object(parent)
+                    ancestry.append((parent_def.c_name, parent_def.implements))
+                    parent = parent_def.parent
+        except ValueError:
+            pass
+        ancestry.reverse()
+        self.write_heading('Ancestry', fp)
+        self.write_hierarchy(obj_def.c_name, ancestry, fp)
+        self.close_section(fp)
+
+        constructor = self.parser.find_constructor(obj_def, self.overrides)
+        if constructor:
+            self.write_heading('Constructor', fp)
+            self.write_constructor(constructor,
+                                   self.docs.get(constructor.c_name, None),
+                                   fp)
+            self.close_section(fp)
+
+        methods = self.parser.find_methods(obj_def)
+        methods = filter(lambda meth, self=self:
+                         not self.overrides.is_ignored(meth.c_name), methods)
+        if methods:
+            self.write_heading('Methods', fp)
+            for method in methods:
+                self.write_method(method, self.docs.get(method.c_name, None), fp)
+            self.close_section(fp)
+
+        self.write_class_footer(obj_def.c_name, fp)
+
+    def output_interface_docs(self, int_def, fp=sys.stdout):
+        self.write_class_header(int_def.c_name, fp)
+
+        self.write_heading('Synopsis', fp)
+        self.write_synopsis(int_def, fp)
+        self.close_section(fp)
+
+        methods = self.parser.find_methods(int_def)
+        methods = filter(lambda meth, self=self:
+                         not self.overrides.is_ignored(meth.c_name), methods)
+        if methods:
+            self.write_heading('Methods', fp)
+            for method in methods:
+                self.write_method(method, self.docs.get(method.c_name, None), fp)
+            self.close_section(fp)
+
+        self.write_class_footer(int_def.c_name, fp)
+
+    def output_boxed_docs(self, box_def, fp=sys.stdout):
+        self.write_class_header(box_def.c_name, fp)
+
+        self.write_heading('Synopsis', fp)
+        self.write_synopsis(box_def, fp)
+        self.close_section(fp)
+
+        constructor = self.parser.find_constructor(box_def, self.overrides)
+        if constructor:
+            self.write_heading('Constructor', fp)
+            self.write_constructor(constructor,
+                                   self.docs.get(constructor.c_name, None),
+                                   fp)
+            self.close_section(fp)
+
+        methods = self.parser.find_methods(box_def)
+        methods = filter(lambda meth, self=self:
+                         not self.overrides.is_ignored(meth.c_name), methods)
+        if methods:
+            self.write_heading('Methods', fp)
+            for method in methods:
+                self.write_method(method, self.docs.get(method.c_name, None), fp)
+            self.close_section(fp)
+
+        self.write_class_footer(box_def.c_name, fp)
+
+    def output_toc(self, files, fp=sys.stdout):
+        fp.write('TOC\n\n')
+        for filename, obj_def in files:
+            fp.write(obj_def.c_name + ' - ' + filename + '\n')
+
+    # override the following to create a more complex output format
+    def create_filename(self, obj_name, output_prefix):
+        '''Create output filename for this particular object'''
+        return output_prefix + '-' + string.lower(obj_name) + '.txt'
+    def create_toc_filename(self, output_prefix):
+        return self.create_filename(self, 'docs', output_prefix)
+
+    def write_full_hierarchy(self, hierarchy, fp):
+        def handle_node(node, fp, indent=''):
+            for child in node.subclasses:
+                fp.write(indent + node.name)
+                if node.interfaces:
+                    fp.write(' (implements ')
+                    fp.write(string.join(node.interfaces, ', '))
+                    fp.write(')\n')
+                else:
+                    fp.write('\n')
+                handle_node(child, fp, indent + '  ')
+        handle_node(hierarchy, fp)
+
+    # these need to handle default args ...
+    def create_constructor_prototype(self, func_def):
+        return func_def.is_constructor_of + '(' + \
+               string.join(map(lambda x: x[1], func_def.params), ', ') + \
+               ')'
+    def create_function_prototype(self, func_def):
+        return func_def.name + '(' + \
+               string.join(map(lambda x: x[1], func_def.params), ', ') + \
+               ')'
+    def create_method_prototype(self, meth_def):
+        return meth_def.of_object + '.' + \
+               meth_def.name + '(' + \
+               string.join(map(lambda x: x[1], meth_def.params), ', ') + \
+               ')'
+
+    def write_class_header(self, obj_name, fp):
+        fp.write('Class %s\n' % obj_name)
+        fp.write('======%s\n\n' % ('=' * len(obj_name)))
+    def write_class_footer(self, obj_name, fp):
+        pass
+    def write_heading(self, text, fp):
+        fp.write('\n' + text + '\n' + ('-' * len(text)) + '\n')
+    def close_section(self, fp):
+        pass
+    def write_synopsis(self, obj_def, fp):
+        fp.write('class %s' % obj_def.c_name)
+        if isinstance(obj_def, definitions.ObjectDef):
+            bases = []
+            if obj_def.parent: bases.append(obj_def.parent)
+            bases = bases = obj_def.implements
+            if bases:
+                fp.write('(%s)' % string.join(bases, ', '))
+        fp.write(':\n')
+
+        constructor = self.parser.find_constructor(obj_def, self.overrides)
+        if constructor:
+            prototype = self.create_constructor_prototype(constructor)
+            fp.write('    def %s\n' % prototype)
+        methods = self.parser.find_methods(obj_def)
+        methods = filter(lambda meth, self=self:
+                         not self.overrides.is_ignored(meth.c_name), methods)
+        for meth in methods:
+            prototype = self.create_method_prototype(meth)
+            fp.write('    def %s\n' % prototype)
+
+    def write_hierarchy(self, obj_name, ancestry, fp):
+        indent = ''
+        for name, interfaces in ancestry:
+            fp.write(indent + '+-- ' + name)
+            if interfaces:
+                fp.write(' (implements ')
+                fp.write(string.join(interfaces, ', '))
+                fp.write(')\n')
+            else:
+                fp.write('\n')
+            indent = indent + '  '
+        fp.write('\n')
+    def write_constructor(self, func_def, func_doc, fp):
+        prototype = self.create_constructor_prototype(func_def)
+        fp.write(prototype + '\n\n')
+        for type, name, dflt, null in func_def.params:
+            if func_doc:
+                descr = func_doc.get_param_description(name)
+            else:
+                descr = 'a ' + type
+            fp.write('  ' + name + ': ' + descr + '\n')
+        if func_def.ret and func_def.ret != 'none':
+            if func_doc and func_doc.ret:
+                descr = func_doc.ret
+            else:
+                descr = 'a ' + func_def.ret
+            fp.write('  Returns: ' + descr + '\n')
+        if func_doc and func_doc.description:
+            fp.write(func_doc.description)
+        fp.write('\n\n\n')
+    def write_method(self, meth_def, func_doc, fp):
+        prototype = self.create_method_prototype(meth_def)
+        fp.write(prototype + '\n\n')
+        for type, name, dflt, null in meth_def.params:
+            if func_doc:
+                descr = func_doc.get_param_description(name)
+            else:
+                descr = 'a ' + type
+            fp.write('  ' + name + ': ' + descr + '\n')
+        if meth_def.ret and meth_def.ret != 'none':
+            if func_doc and func_doc.ret:
+                descr = func_doc.ret
+            else:
+                descr = 'a ' + meth_def.ret
+            fp.write('  Returns: ' + descr + '\n')
+        if func_doc and func_doc.description:
+            fp.write('\n')
+            fp.write(func_doc.description)
+        fp.write('\n\n')
+
+class DocbookDocWriter(DocWriter):
+    def __init__(self, use_xml=0):
+        DocWriter.__init__(self)
+        self.use_xml = use_xml
+
+    def create_filename(self, obj_name, output_prefix):
+        '''Create output filename for this particular object'''
+        stem = output_prefix + '-' + string.lower(obj_name)
+        if self.use_xml:
+            return stem + '.xml'
+        else:
+            return stem + '.sgml'
+    def create_toc_filename(self, output_prefix):
+        if self.use_xml:
+            return self.create_filename('classes', output_prefix)
+        else:
+            return self.create_filename('docs', output_prefix)
+
+    # make string -> reference translation func
+    __transtable = [ '-' ] * 256
+    for digit in '0123456789':
+        __transtable[ord(digit)] = digit
+    for letter in 'abcdefghijklmnopqrstuvwxyz':
+        __transtable[ord(letter)] = letter
+        __transtable[ord(string.upper(letter))] = letter
+    __transtable = string.join(__transtable, '')
+
+    def make_class_ref(self, obj_name):
+        return 'class-' + string.translate(obj_name, self.__transtable)
+    def make_method_ref(self, meth_def):
+        return 'method-' + string.translate(meth_def.of_object,
+                                            self.__transtable) + \
+            '--' + string.translate(meth_def.name, self.__transtable)
+
+    __function_pat = re.compile(r'(\w+)\s*\(\)')
+    def __format_function(self, match):
+        info = self.parser.c_name.get(match.group(1), None)
+        if info:
+            if isinstance(info, defsparser.FunctionDef):
+                if info.is_constructor_of is not None:
+                    # should have a link here
+                    return '<function>%s()</function>' % \
+                           self.pyname(info.is_constructor_of)
+                else:
+                    return '<function>' + info.name + '()</function>'
+            if isinstance(info, defsparser.MethodDef):
+                return '<link linkend="' + self.make_method_ref(info) + \
+                       '"><function>' + self.pyname(info.of_object) + '.' + \
+                       info.name + '()</function></link>'
+        # fall through through
+        return '<function>' + match.group(1) + '()</function>'
+    __parameter_pat = re.compile(r'\@(\w+)')
+    def __format_param(self, match):
+        return '<parameter>' + match.group(1) + '</parameter>'
+    __constant_pat = re.compile(r'\%(-?\w+)')
+    def __format_const(self, match):
+        return '<literal>' + match.group(1) + '</literal>'
+    __symbol_pat = re.compile(r'#([\w-]+)')
+    def __format_symbol(self, match):
+        info = self.parser.c_name.get(match.group(1), None)
+        if info:
+            if isinstance(info, defsparser.FunctionDef):
+                if info.is_constructor_of is not None:
+                    # should have a link here
+                    return '<methodname>' + self.pyname(info.is_constructor_of) + \
+                           '</methodname>'
+                else:
+                    return '<function>' + info.name + '</function>'
+            if isinstance(info, defsparser.MethodDef):
+                return '<link linkend="' + self.make_method_ref(info) + \
+                       '"><methodname>' + self.pyname(info.of_object) + '.' + \
+                       info.name + '</methodname></link>'
+            if isinstance(info, defsparser.ObjectDef) or \
+                   isinstance(info, defsparser.InterfaceDef) or \
+                   isinstance(info, defsparser.BoxedDef) or \
+                   isinstance(info, defsparser.PointerDef):
+                return '<link linkend="' + self.make_class_ref(info.c_name) + \
+                       '"><classname>' + self.pyname(info.c_name) + \
+                       '</classname></link>'
+        # fall through through
+        return '<literal>' + match.group(1) + '</literal>'
+
+    def reformat_text(self, text, singleline=0):
+        # replace special strings ...
+        text = self.__function_pat.sub(self.__format_function, text)
+        text = self.__parameter_pat.sub(self.__format_param, text)
+        text = self.__constant_pat.sub(self.__format_const, text)
+        text = self.__symbol_pat.sub(self.__format_symbol, text)
+
+        # don't bother with <para> expansion for single line text.
+        if singleline: return text
+
+        lines = string.split(string.strip(text), '\n')
+        for index in range(len(lines)):
+            if string.strip(lines[index]) == '':
+                lines[index] = '</para>\n<para>'
+                continue
+        lines.insert(0, '<para>')
+        lines.append('</para>')
+        return string.join(lines, '\n')
+
+    # write out hierarchy
+    def write_full_hierarchy(self, hierarchy, fp):
+        def handle_node(node, fp, indent=''):
+            if node.name:
+                fp.write('%s<link linkend="%s">%s</link>' %
+                         (indent, self.make_class_ref(node.name),
+                          self.pyname(node.name)))
+                if node.interfaces:
+                    fp.write(' (implements ')
+                    for i in range(len(node.interfaces)):
+                        fp.write('<link linkend="%s">%s</link>' %
+                                 (self.make_class_ref(node.interfaces[i]),
+                                  self.pyname(node.interfaces[i])))
+                        if i != len(node.interfaces) - 1:
+                            fp.write(', ')
+                    fp.write(')\n')
+                else:
+                    fp.write('\n')
+
+                indent = indent + '  '
+            node.subclasses.sort(lambda a,b:
+                                 cmp(self.pyname(a.name), self.pyname(b.name)))
+            for child in node.subclasses:
+                handle_node(child, fp, indent)
+        if self.use_xml:
+            fp.write('<?xml version="1.0" standalone="no"?>\n')
+            fp.write('<!DOCTYPE synopsis PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
+            fp.write('    "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
+        fp.write('<synopsis>')
+        handle_node(hierarchy, fp)
+        fp.write('</synopsis>\n')
+
+    # these need to handle default args ...
+    def create_constructor_prototype(self, func_def):
+        sgml = [ '<constructorsynopsis language="python">\n']
+        sgml.append('    <methodname>__init__</methodname>\n')
+        for type, name, dflt, null in func_def.params:
+            sgml.append('    <methodparam><parameter>')
+            sgml.append(name)
+            sgml.append('</parameter>')
+            if dflt:
+                sgml.append('<initializer>')
+                sgml.append(dflt)
+                sgml.append('</initializer>')
+            sgml.append('</methodparam>\n')
+        if not func_def.params:
+            sgml.append('    <methodparam></methodparam>')
+        sgml.append('  </constructorsynopsis>')
+        return string.join(sgml, '')
+    def create_function_prototype(self, func_def):
+        sgml = [ '<funcsynopsis language="python">\n    <funcprototype>\n']
+        sgml.append('      <funcdef><function>')
+        sgml.append(func_def.name)
+        sgml.append('</function></funcdef>\n')
+        for type, name, dflt, null in func_def.params:
+            sgml.append('      <paramdef><parameter>')
+            sgml.append(name)
+            sgml.append('</parameter>')
+            if dflt:
+                sgml.append('<initializer>')
+                sgml.append(dflt)
+                sgml.append('</initializer>')
+            sgml.append('</paramdef>\n')
+        if not func_def.params:
+            sgml.append('      <paramdef></paramdef')
+        sgml.append('    </funcprototype>\n  </funcsynopsis>')
+        return string.join(sgml, '')
+    def create_method_prototype(self, meth_def, addlink=0):
+        sgml = [ '<methodsynopsis language="python">\n']
+        sgml.append('    <methodname>')
+        if addlink:
+            sgml.append('<link linkend="%s">' % self.make_method_ref(meth_def))
+        sgml.append(self.pyname(meth_def.name))
+        if addlink:
+            sgml.append('</link>')
+        sgml.append('</methodname>\n')
+        for type, name, dflt, null in meth_def.params:
+            sgml.append('    <methodparam><parameter>')
+            sgml.append(name)
+            sgml.append('</parameter>')
+            if dflt:
+                sgml.append('<initializer>')
+                sgml.append(dflt)
+                sgml.append('</initializer>')
+            sgml.append('</methodparam>\n')
+        if not meth_def.params:
+            sgml.append('    <methodparam></methodparam>')
+        sgml.append('  </methodsynopsis>')
+        return string.join(sgml, '')
+
+    def write_class_header(self, obj_name, fp):
+        if self.use_xml:
+            fp.write('<?xml version="1.0" standalone="no"?>\n')
+            fp.write('<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
+            fp.write('    "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
+        fp.write('<refentry id="' + self.make_class_ref(obj_name) + '">\n')
+        fp.write('  <refmeta>\n')
+        fp.write('    <refentrytitle>%s</refentrytitle>\n'
+                 % self.pyname(obj_name))
+        fp.write('    <manvolnum>3</manvolnum>\n')
+        fp.write('    <refmiscinfo>PyGTK Docs</refmiscinfo>\n')
+        fp.write('  </refmeta>\n\n')
+        fp.write('  <refnamediv>\n')
+        fp.write('    <refname>%s</refname><refpurpose></refpurpose>\n'
+                 % self.pyname(obj_name))
+        fp.write('  </refnamediv>\n\n')
+    def write_class_footer(self, obj_name, fp):
+        fp.write('</refentry>\n')
+    def write_heading(self, text, fp):
+        fp.write('  <refsect1>\n')
+        fp.write('    <title>' + text + '</title>\n\n')
+    def close_section(self, fp):
+        fp.write('  </refsect1>\n')
+
+    def write_synopsis(self, obj_def, fp):
+        fp.write('<classsynopsis language="python">\n')
+        fp.write('  <ooclass><classname>%s</classname></ooclass>\n'
+                 % self.pyname(obj_def.c_name))
+        if isinstance(obj_def, definitions.ObjectDef):
+            if obj_def.parent:
+                fp.write('  <ooclass><classname><link linkend="%s">%s'
+                         '</link></classname></ooclass>\n'
+                         % (self.make_class_ref(obj_def.parent),
+                            self.pyname(obj_def.parent)))
+            for base in obj_def.implements:
+                fp.write('  <ooclass><classname><link linkend="%s">%s'
+                         '</link></classname></ooclass>\n'
+                         % (self.make_class_ref(base), self.pyname(base)))
+        elif isinstance(obj_def, definitions.InterfaceDef):
+            fp.write('  <ooclass><classname>gobject.GInterface'
+                     '</classname></ooclass>\n')
+        elif isinstance(obj_def, definitions.BoxedDef):
+            fp.write('  <ooclass><classname>gobject.GBoxed'
+                     '</classname></ooclass>\n')
+        elif isinstance(obj_def, definitions.PointerDef):
+            fp.write('  <ooclass><classname>gobject.GPointer'
+                     '</classname></ooclass>\n')
+
+        constructor = self.parser.find_constructor(obj_def, self.overrides)
+        if constructor:
+            fp.write('%s\n' % self.create_constructor_prototype(constructor))
+        methods = self.parser.find_methods(obj_def)
+        methods = filter(lambda meth, self=self:
+                         not self.overrides.is_ignored(meth.c_name), methods)
+        for meth in methods:
+            fp.write('%s\n' % self.create_method_prototype(meth, addlink=1))
+        fp.write('</classsynopsis>\n\n')
+
+    def write_hierarchy(self, obj_name, ancestry, fp):
+        fp.write('<synopsis>')
+        indent = ''
+        for name, interfaces in ancestry:
+            fp.write(indent + '+-- <link linkend="' +
+                     self.make_class_ref(name) + '">'+ self.pyname(name) + '</link>')
+            if interfaces:
+                fp.write(' (implements ')
+                for i in range(len(interfaces)):
+                    fp.write('<link linkend="%s">%s</link>' %
+                             (self.make_class_ref(interfaces[i]),
+                              self.pyname(interfaces[i])))
+                    if i != len(interfaces) - 1:
+                        fp.write(', ')
+                fp.write(')\n')
+            else:
+                fp.write('\n')
+            indent = indent + '  '
+        fp.write('</synopsis>\n\n')
+
+    def write_params(self, params, ret, func_doc, fp):
+        if not params and (not ret or ret == 'none'):
+            return
+        fp.write('  <variablelist>\n')
+        for type, name, dflt, null in params:
+            if func_doc:
+                descr = string.strip(func_doc.get_param_description(name))
+            else:
+                descr = 'a ' + type
+            fp.write('    <varlistentry>\n')
+            fp.write('      <term><parameter>%s</parameter>&nbsp;:</term>\n' % name)
+            fp.write('      <listitem><simpara>%s</simpara></listitem>\n' %
+                     self.reformat_text(descr, singleline=1))
+            fp.write('    </varlistentry>\n')
+        if ret and ret != 'none':
+            if func_doc and func_doc.ret:
+                descr = string.strip(func_doc.ret)
+            else:
+                descr = 'a ' + ret
+            fp.write('    <varlistentry>\n')
+            fp.write('      <term><emphasis>Returns</emphasis>&nbsp;:</term>\n')
+            fp.write('      <listitem><simpara>%s</simpara></listitem>\n' %
+                     self.reformat_text(descr, singleline=1))
+            fp.write('    </varlistentry>\n')
+        fp.write('  </variablelist>\n')
+
+    def write_constructor(self, func_def, func_doc, fp):
+        prototype = self.create_constructor_prototype(func_def)
+        fp.write('<programlisting>%s</programlisting>\n' % prototype)
+        self.write_params(func_def.params, func_def.ret, func_doc, fp)
+
+        if func_doc and func_doc.description:
+            fp.write(self.reformat_text(func_doc.description))
+        fp.write('\n\n\n')
+
+    def write_method(self, meth_def, func_doc, fp):
+        fp.write('  <refsect2 id="' + self.make_method_ref(meth_def) + '">\n')
+        fp.write('    <title>' + self.pyname(meth_def.of_object) + '.' +
+                 meth_def.name + '</title>\n\n')
+        prototype = self.create_method_prototype(meth_def)
+        fp.write('<programlisting>%s</programlisting>\n' % prototype)
+        self.write_params(meth_def.params, meth_def.ret, func_doc, fp)
+        if func_doc and func_doc.description:
+            fp.write(self.reformat_text(func_doc.description))
+        fp.write('  </refsect2>\n\n\n')
+
+    def output_toc(self, files, fp=sys.stdout):
+        if self.use_xml:
+            fp.write('<?xml version="1.0" standalone="no"?>\n')
+            fp.write('<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
+            fp.write('    "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
+            #for filename, obj_def in files:
+            #    fp.write('  <!ENTITY ' + string.translate(obj_def.c_name,
+            #                                              self.__transtable) +
+            #             ' SYSTEM "' + filename + '" >\n')
+            #fp.write(']>\n\n')
+
+            #fp.write('<reference id="class-reference">\n')
+            #fp.write('  <title>Class Documentation</title>\n')
+            #for filename, obj_def in files:
+            #    fp.write('&' + string.translate(obj_def.c_name,
+            #                                    self.__transtable) + ';\n')
+            #fp.write('</reference>\n')
+
+            fp.write('<reference id="class-reference" xmlns:xi="http://www.w3.org/2001/XInclude">\n')
+            fp.write('  <title>Class Reference</title>\n')
+            for filename, obj_def in files:
+                fp.write('  <xi:include href="%s"/>\n' % filename)
+            fp.write('</reference>\n')
+        else:
+            fp.write('<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V4.1.2//EN" [\n')
+            for filename, obj_def in files:
+                fp.write('  <!ENTITY ' + string.translate(obj_def.c_name,
+                                                          self.__transtable) +
+                         ' SYSTEM "' + filename + '" >\n')
+            fp.write(']>\n\n')
+
+            fp.write('<book id="index">\n\n')
+            fp.write('  <bookinfo>\n')
+            fp.write('    <title>PyGTK Docs</title>\n')
+            fp.write('    <authorgroup>\n')
+            fp.write('      <author>\n')
+            fp.write('        <firstname>James</firstname>\n')
+            fp.write('        <surname>Henstridge</surname>\n')
+            fp.write('      </author>\n')
+            fp.write('    </authorgroup>\n')
+            fp.write('  </bookinfo>\n\n')
+
+            fp.write('  <chapter id="class-hierarchy">\n')
+            fp.write('    <title>Class Hierarchy</title>\n')
+            fp.write('    <para>Not done yet</para>\n')
+            fp.write('  </chapter>\n\n')
+
+            fp.write('  <reference id="class-reference">\n')
+            fp.write('    <title>Class Documentation</title>\n')
+            for filename, obj_def in files:
+                fp.write('&' + string.translate(obj_def.c_name,
+                                                self.__transtable) + ';\n')
+
+            fp.write('  </reference>\n')
+            fp.write('</book>\n')
+
+if __name__ == '__main__':
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "d:s:o:",
+                                   ["defs-file=", "override=", "source-dir=",
+                                    "output-prefix="])
+    except getopt.error, e:
+        sys.stderr.write('docgen.py: %s\n' % e)
+        sys.stderr.write(
+            'usage: docgen.py -d file.defs [-s /src/dir] [-o output-prefix]\n')
+        sys.exit(1)
+    defs_file = None
+    overrides_file = None
+    source_dirs = []
+    output_prefix = 'docs'
+    for opt, arg in opts:
+        if opt in ('-d', '--defs-file'):
+            defs_file = arg
+        if opt in ('--override',):
+            overrides_file = arg
+        elif opt in ('-s', '--source-dir'):
+            source_dirs.append(arg)
+        elif opt in ('-o', '--output-prefix'):
+            output_prefix = arg
+    if len(args) != 0 or not defs_file:
+        sys.stderr.write(
+            'usage: docgen.py -d file.defs [-s /src/dir] [-o output-prefix]\n')
+        sys.exit(1)
+
+    d = DocbookDocWriter()
+    d.add_sourcedirs(source_dirs)
+    d.add_docs(defs_file, overrides_file, 'gtk')
+    d.output_docs(output_prefix)
diff --git a/bindings/python/codegen/h2def.py b/bindings/python/codegen/h2def.py
new file mode 100755 (executable)
index 0000000..4da0dec
--- /dev/null
@@ -0,0 +1,539 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# Search through a header file looking for function prototypes.
+# For each prototype, generate a scheme style definition.
+# 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://www.gnome.org/mailing-lists/archives/gtk-devel-list/2000-January/0085.shtml
+# Updated to be PEP-8 compatible and refactored to use OOP
+
+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):
+    """create a typecode (eg. GTK_TYPE_WIDGET) from a typename"""
+    typename2 = to_upper_str(typename)
+    typename2 = string.replace(typename2, '_', "", 1)
+    typename2 = typename2[:3] + '_TYPE' + typename2[3:]
+    return typename2
+
+
+# ------------------ Find object definitions -----------------
+
+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, '')
+
+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)
+
+    maybeobjdefs = []  # contains all possible objects from file
+
+    # first find all structures that look like they may represent a GtkObject
+    pat = re.compile("struct _(" + 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(2)))
+        pos = m.end()
+
+    # now find all structures that look like they might represent a class:
+    pat = re.compile("struct _(" + 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 _(" + 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 _(" + 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)
+
+    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)
+
+    # 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 = string.replace(buf, 'G_CONST_RETURN ', 'const-')
+    buf = string.replace(buf, 'const ', 'const-')
+
+    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, verbose=False,
+                 defsfilter=None):
+        if not fp:
+            fp = sys.stdout
+
+        self.fp = fp
+        self.prefix = prefix
+        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] = func
+            for obj in filter.enums:
+                self._enums[obj.c_name] = func
+
+    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
+            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) + '")\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 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
+            m = split_prefix_pat.match(klass)
+            cmodule = None
+            cname = klass
+            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) + '")\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
+    defsfilter = None
+    opts, args = getopt.getopt(args[1:], 'vs:m:f:',
+                               ['onlyenums', 'onlyobjdefs',
+                                'modulename=', '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 ('-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, 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, 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/bindings/python/codegen/mergedefs.py b/bindings/python/codegen/mergedefs.py
new file mode 100755 (executable)
index 0000000..773e499
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+
+import optparse
+
+import defsparser
+
+parser = optparse.OptionParser(
+    usage="usage: %prog [options] generated-defs old-defs")
+parser.add_option("-p", "--merge-parameters",
+                  help="Merge changes in function/methods parameter lists",
+                  action="store_true", dest="parmerge", default=False)
+(options, args) = parser.parse_args()
+
+if len(args) != 2:
+    parser.error("wrong number of arguments")
+
+newp = defsparser.DefsParser(args[0])
+oldp = defsparser.DefsParser(args[1])
+
+newp.startParsing()
+oldp.startParsing()
+
+newp.merge(oldp, options.parmerge)
+
+newp.write_defs()
diff --git a/bindings/python/codegen/mkskel.py b/bindings/python/codegen/mkskel.py
new file mode 100755 (executable)
index 0000000..61f520b
--- /dev/null
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+
+import sys, os, getopt
+
+module_init_template = \
+'/* -*- Mode: C; c-basic-offset: 4 -*- */\n' + \
+'#ifdef HAVE_CONFIG_H\n' + \
+'#  include "config.h"\n' + \
+'#endif\n' + \
+'#include <Python.h>\n' + \
+'#include <pygtk.h>\n' + \
+'\n' + \
+'/* include any extra headers needed here */\n' + \
+'\n' + \
+'void %(prefix)s_register_classes(PyObject *d);\n' + \
+'extern PyMethodDef %(prefix)s_functions[];\n' + \
+'\n' + \
+'DL_EXPORT(void)\n' + \
+'init%(module)s(void)\n' + \
+'{\n' + \
+'    PyObject *m, *d;\n' + \
+'\n' + \
+'    /* perform any initialisation required by the library here */\n' + \
+'\n' + \
+'    m = Py_InitModule("%(module)s", %(prefix)s_functions);\n' + \
+'    d = PyModule_GetDict(m);\n' + \
+'\n' + \
+'    init_pygtk();\n' + \
+'\n' + \
+'    %(prefix)s_register_classes(d);\n' + \
+'\n' + \
+'    /* add anything else to the module dictionary (such as constants) */\n' +\
+'\n' + \
+'    if (PyErr_Occurred())\n' + \
+'        Py_FatalError("could not initialise module %(module)s");\n' + \
+'}\n'
+
+override_template = \
+'/* -*- Mode: C; c-basic-offset: 4 -*- */\n' + \
+'%%%%\n' + \
+'headers\n' + \
+'/* include any required headers here */\n' + \
+'%%%%\n' + \
+'init\n' + \
+'    /* include any code here that needs to be executed before the\n' + \
+'     * extension classes get initialised */\n' + \
+'%%%%\n' + \
+'\n' + \
+'/* you should add appropriate ignore, ignore-glob and\n' + \
+' * override sections here */\n'
+
+def open_with_backup(file):
+    if os.path.exists(file):
+        try:
+            os.rename(file, file+'~')
+        except OSError:
+            # fail silently if we can't make a backup
+            pass
+    return open(file, 'w')
+
+def write_skels(fileprefix, prefix, module):
+    fp = open_with_backup(fileprefix+'module.c')
+    fp.write(module_init_template % { 'prefix': prefix, 'module': module })
+    fp.close()
+    fp = open_with_backup(fileprefix+'.override')
+    fp.write(override_template % { 'prefix': prefix, 'module': module })
+    fp.close()
+
+if __name__ == '__main__':
+    opts, args = getopt.getopt(sys.argv[1:], 'f:p:m:h',
+                               ['file-prefix=', 'prefix=', 'module=', 'help'])
+    fileprefix = None
+    prefix = None
+    module = None
+    for opt, arg in opts:
+        if opt in ('-f', '--file-prefix'):
+            fileprefix = arg
+        elif opt in ('-p', '--prefix'):
+            prefix = arg
+        elif opt in ('-m', '--module'):
+            module = arg
+        elif opt in ('-h', '--help'):
+            print 'usage: mkskel.py -f fileprefix -p prefix -m module'
+            sys.exit(0)
+    if not fileprefix or not prefix or not module:
+        print 'usage: mkskel.py -f fileprefix -p prefix -m module'
+        sys.exit(1)
+    write_skels(fileprefix, prefix, module)
diff --git a/bindings/python/codegen/override.py b/bindings/python/codegen/override.py
new file mode 100644 (file)
index 0000000..2e8c6a4
--- /dev/null
@@ -0,0 +1,288 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+
+# this file contains code for loading up an override file.  The override file
+# provides implementations of functions where the code generator could not
+# do its job correctly.
+
+import fnmatch
+import os
+import re
+import string
+import sys
+
+def class2cname(klass, method):
+    c_name = ''
+    for c in klass:
+        if c.isupper():
+            c_name += '_' + c.lower()
+        else:
+            c_name += c
+    return c_name[1:] + '_'  + method
+
+import_pat = re.compile(r'\s*import\s+(\S+)\.([^\s.]+)\s+as\s+(\S+)')
+
+class Overrides:
+    def __init__(self, filename=None, path=[]):
+        self.modulename = None
+        self.ignores = {}
+        self.glob_ignores = []
+        self.type_ignores = {}
+        self.overrides = {}
+        self.overridden = {}
+        self.kwargs = {}
+        self.noargs = {}
+        self.onearg = {}
+        self.staticmethod = {}
+        self.classmethod = {}
+        self.startlines = {}
+        self.override_attrs = {}
+        self.override_slots = {}
+        self.headers = ''
+        self.body = ''
+        self.init = ''
+        self.imports = []
+        self.defines = {}
+        self.functions = {}
+       self.newstyle_constructors = {}
+        self.path = [os.path.abspath(x) for x in path]
+       if filename:
+            self.handle_file(filename)
+
+    def handle_file(self, filename):
+        oldpath = os.getcwd()
+
+        fp = None
+        for path in self.path:
+            os.chdir(oldpath)
+            os.chdir(path)
+            try:
+                fp = open(filename, 'r')
+                break
+            except:
+                os.chdir(oldpath)
+        if not fp:
+            raise Exception, "Couldn't find file %s" % filename
+        
+        dirname = path
+
+        if dirname != oldpath:
+            os.chdir(dirname)
+
+        # read all the components of the file ...
+        bufs = []
+        startline = 1
+        lines = []
+        line = fp.readline()
+        linenum = 1
+        while line:
+            if line == '%%\n' or line == '%%':
+                if lines:
+                    bufs.append((string.join(lines, ''), startline))
+                startline = linenum + 1
+                lines = []
+            else:
+                lines.append(line)
+            line = fp.readline()
+            linenum = linenum + 1
+        if lines:
+            bufs.append((string.join(lines, ''), startline))
+        if not bufs: return
+
+        for buf, startline in bufs:
+            self.__parse_override(buf, startline, filename)
+
+        os.chdir(oldpath)
+
+    def __parse_override(self, buffer, startline, filename):
+        pos = string.find(buffer, '\n')
+        if pos >= 0:
+            line = buffer[:pos]
+            rest = buffer[pos+1:]
+        else:
+            line = buffer ; rest = ''
+        words = string.split(line)
+        command = words[0]
+        if (command == 'ignore' or
+            command == 'ignore-' + sys.platform):
+            "ignore/ignore-platform [functions..]"
+            for func in words[1:]:
+                self.ignores[func] = 1
+            for func in string.split(rest):
+                self.ignores[func] = 1
+        elif (command == 'ignore-glob' or
+              command == 'ignore-glob-' + sys.platform):
+            "ignore-glob/ignore-glob-platform [globs..]"
+            for func in words[1:]:
+                self.glob_ignores.append(func)
+            for func in string.split(rest):
+                self.glob_ignores.append(func)
+        elif (command == 'ignore-type' or
+              command == 'ignore-type-' + sys.platform):
+            "ignore-type/ignore-type-platform [typenames..]"
+            for typename in words[1:]:
+                self.type_ignores[typename] = 1
+            for typename in string.split(rest):
+                self.type_ignores[typename] = 1
+        elif command == 'override':
+            "override function/method [kwargs|noargs|onearg] [staticmethod|classmethod]"
+            func = words[1]
+            if 'kwargs' in words[1:]:
+                self.kwargs[func] = 1
+            elif 'noargs' in words[1:]:
+                self.noargs[func] = 1
+            elif 'onearg' in words[1:]:
+                self.onearg[func] = True
+
+            if 'staticmethod' in words[1:]:
+                self.staticmethod[func] = True
+            elif 'classmethod' in words[1:]:
+                self.classmethod[func] = True
+            if func in self.overrides:
+                raise RuntimeError("Function %s is being overridden more than once" % (func,))
+            self.overrides[func] = rest
+            self.startlines[func] = (startline + 1, filename)
+        elif command == 'override-attr':
+            "override-slot Class.attr"
+            attr = words[1]
+            self.override_attrs[attr] = rest
+            self.startlines[attr] = (startline + 1, filename)
+        elif command == 'override-slot':
+            "override-slot Class.slot"
+            slot = words[1]
+            self.override_slots[slot] = rest
+            self.startlines[slot] = (startline + 1, filename)
+        elif command == 'headers':
+            "headers"
+            self.headers = '%s\n#line %d "%s"\n%s' % \
+                           (self.headers, startline + 1, filename, rest)
+        elif command == 'body':
+            "body"
+            self.body = '%s\n#line %d "%s"\n%s' % \
+                           (self.body, startline + 1, filename, rest)
+        elif command == 'init':
+            "init"
+            self.init = '%s\n#line %d "%s"\n%s' % \
+                        (self.init, startline + 1, filename, rest)
+        elif command == 'modulename':
+            "modulename name"
+            self.modulename = words[1]
+        elif command == 'include':
+            "include filename"
+            for filename in words[1:]:
+                self.handle_file(filename)
+            for filename in string.split(rest):
+                self.handle_file(filename)
+        elif command == 'import':
+            "import module1 [\n module2, \n module3 ...]"
+            for line in string.split(buffer, '\n'):
+                match = import_pat.match(line)
+                if match:
+                    self.imports.append(match.groups())
+        elif command == 'define':
+            "define funcname [kwargs|noargs|onearg] [classmethod|staticmethod]"
+            "define Class.method [kwargs|noargs|onearg] [classmethod|staticmethod]"
+            func = words[1]
+            klass = None
+            if func.find('.') != -1:
+                klass, func = func.split('.', 1)
+
+                if not self.defines.has_key(klass):
+                    self.defines[klass] = {}
+                self.defines[klass][func] = rest
+            else:
+                self.functions[func] = rest
+
+            if 'kwargs' in words[1:]:
+                self.kwargs[func] = 1
+            elif 'noargs' in words[1:]:
+                self.noargs[func] = 1
+            elif 'onearg' in words[1:]:
+                self.onearg[func] = 1
+
+            if 'staticmethod' in words[1:]:
+                self.staticmethod[func] = True
+            elif 'classmethod' in words[1:]:
+                self.classmethod[func] = True
+
+            self.startlines[func] = (startline + 1, filename)
+
+        elif command == 'new-constructor':
+            "new-constructor GType"
+            gtype, = words[1:]
+            self.newstyle_constructors[gtype] = True
+
+    def is_ignored(self, name):
+        if self.ignores.has_key(name):
+            return 1
+        for glob in self.glob_ignores:
+            if fnmatch.fnmatchcase(name, glob):
+                return 1
+        return 0
+
+    def is_type_ignored(self, name):
+        return name in self.type_ignores
+
+    def is_overriden(self, name):
+        return self.overrides.has_key(name)
+
+    def is_already_included(self, name):
+        return self.overridden.has_key(name)
+
+    def override(self, name):
+        self.overridden[name] = 1
+        return self.overrides[name]
+
+    def define(self, klass, name):
+        self.overridden[class2cname(klass, name)] = 1
+        return self.defines[klass][name]
+
+    def function(self, name):
+        return self.functions[name]
+
+    def getstartline(self, name):
+        return self.startlines[name]
+
+    def wants_kwargs(self, name):
+        return self.kwargs.has_key(name)
+
+    def wants_noargs(self, name):
+        return self.noargs.has_key(name)
+
+    def wants_onearg(self, name):
+        return self.onearg.has_key(name)
+
+    def is_staticmethod(self, name):
+        return self.staticmethod.has_key(name)
+
+    def is_classmethod(self, name):
+        return self.classmethod.has_key(name)
+
+    def attr_is_overriden(self, attr):
+        return self.override_attrs.has_key(attr)
+
+    def attr_override(self, attr):
+        return self.override_attrs[attr]
+
+    def slot_is_overriden(self, slot):
+        return self.override_slots.has_key(slot)
+
+    def slot_override(self, slot):
+        return self.override_slots[slot]
+
+    def get_headers(self):
+        return self.headers
+
+    def get_body(self):
+        return self.body
+
+    def get_init(self):
+        return self.init
+
+    def get_imports(self):
+        return self.imports
+
+    def get_defines_for(self, klass):
+        return self.defines.get(klass, {})
+
+    def get_functions(self):
+        return self.functions
diff --git a/bindings/python/codegen/reversewrapper.py b/bindings/python/codegen/reversewrapper.py
new file mode 100644 (file)
index 0000000..f528828
--- /dev/null
@@ -0,0 +1,771 @@
+### -*- python -*-
+### Code to generate "Reverse Wrappers", i.e. C->Python wrappers
+### (C) 2004 Gustavo Carneiro <gjc@gnome.org>
+import argtypes
+import os
+
+DEBUG_MODE = ('PYGTK_CODEGEN_DEBUG' in os.environ)
+
+def join_ctype_name(ctype, name):
+    '''Joins a C type and a variable name into a single string'''
+    if ctype[-1] != '*':
+        return " ".join((ctype, name))
+    else:
+        return "".join((ctype, name))
+
+
+class CodeSink(object):
+    def __init__(self):
+        self.indent_level = 0 # current indent level
+        self.indent_stack = [] # previous indent levels
+
+    def _format_code(self, code):
+        assert isinstance(code, str)
+        l = []
+        for line in code.split('\n'):
+            l.append(' '*self.indent_level + line)
+        if l[-1]:
+            l.append('')
+        return '\n'.join(l)
+
+    def writeln(self, line=''):
+        raise NotImplementedError
+
+    def indent(self, level=4):
+        '''Add a certain ammount of indentation to all lines written
+        from now on and until unindent() is called'''
+        self.indent_stack.append(self.indent_level)
+        self.indent_level += level
+
+    def unindent(self):
+        '''Revert indentation level to the value before last indent() call'''
+        self.indent_level = self.indent_stack.pop()
+
+
+class FileCodeSink(CodeSink):
+    def __init__(self, fp):
+        CodeSink.__init__(self)
+        assert isinstance(fp, file)
+        self.fp = fp
+
+    def writeln(self, line=''):
+        self.fp.write(self._format_code(line))
+
+class MemoryCodeSink(CodeSink):
+    def __init__(self):
+        CodeSink.__init__(self)
+        self.lines = []
+
+    def writeln(self, line=''):
+        self.lines.append(self._format_code(line))
+
+    def flush_to(self, sink):
+        assert isinstance(sink, CodeSink)
+        for line in self.lines:
+            sink.writeln(line.rstrip())
+        self.lines = []
+
+    def flush(self):
+        l = []
+        for line in self.lines:
+            l.append(self._format_code(line))
+        self.lines = []
+        return "".join(l)
+
+class ReverseWrapper(object):
+    '''Object that generates a C->Python wrapper'''
+    def __init__(self, cname, is_static=True):
+        assert isinstance(cname, str)
+
+        self.cname = cname
+        ## function object we will call, or object whose method we will call
+        self.called_pyobj = None
+        ## name of method of self.called_pyobj we will call
+        self.method_name = None
+        self.is_static = is_static
+
+        self.parameters = []
+        self.declarations = MemoryCodeSink()
+        self.post_return_code = MemoryCodeSink()
+        self.body = MemoryCodeSink()
+        self.cleanup_actions = []
+        self.pyargv_items = []
+        self.pyargv_optional_items = []
+        self.pyret_parse_items = [] # list of (format_spec, parameter)
+
+    def set_call_target(self, called_pyobj, method_name=None):
+        assert called_pyobj is not None
+        assert self.called_pyobj is None
+        self.called_pyobj = called_pyobj
+        self.method_name = method_name
+
+    def set_return_type(self, return_type):
+        assert isinstance(return_type, ReturnType)
+        self.return_type = return_type
+
+    def add_parameter(self, param):
+        assert isinstance(param, Parameter)
+        self.parameters.append(param)
+
+    def add_declaration(self, decl_code):
+        self.declarations.writeln(decl_code)
+
+    def add_pyargv_item(self, variable, optional=False):
+        if optional:
+            self.pyargv_optional_items.append(variable)
+        else:
+            self.pyargv_items.append(variable)
+
+    def add_pyret_parse_item(self, format_specifier, parameter, prepend=False):
+        if prepend:
+            self.pyret_parse_items.insert(0, (format_specifier, parameter))
+        else:
+            self.pyret_parse_items.append((format_specifier, parameter))
+
+    def write_code(self, code,
+                   cleanup=None,
+                   failure_expression=None,
+                   failure_cleanup=None,
+                   failure_exception=None,
+                   code_sink=None):
+        '''Add a chunk of code with cleanup and error handling
+
+        This method is to be used by TypeHandlers when generating code
+
+        Keywork arguments:
+        code -- code to add
+        cleanup -- code to cleanup any dynamic resources created by @code
+                   (except in case of failure) (default None)
+        failure_expression -- C boolean expression to indicate
+                              if anything failed (default None)
+        failure_cleanup -- code to cleanup any dynamic resources
+                           created by @code in case of failure (default None)
+        failure_exception -- code to raise an exception in case of
+                             failure (which will be immediately
+                             printed and cleared), (default None)
+        code_sink -- "code sink" to use; by default,
+                      ReverseWrapper.body is used, which writes the
+                      main body of the wrapper, before calling the
+                      python method.  Alternatively,
+                      ReverseWrapper.after_pyret_parse can be used, to
+                      write code after the PyArg_ParseTuple that
+                      parses the python method return value.
+        '''
+        if code_sink is None:
+            code_sink = self.body
+        if code is not None:
+            code_sink.writeln(code)
+        if failure_expression is not None:
+            code_sink.writeln("if (%s) {" % (failure_expression,))
+            code_sink.indent()
+            if failure_exception is None:
+                code_sink.writeln("if (PyErr_Occurred())")
+                code_sink.indent()
+                code_sink.writeln("PyErr_Print();")
+                code_sink.unindent()
+            else:
+                code_sink.writeln(failure_exception)
+                code_sink.writeln("PyErr_Print();")
+            if failure_cleanup is not None:
+                code_sink.writeln(failure_cleanup)
+            for cleanup_action in self.cleanup_actions:
+                code_sink.writeln(cleanup_action)
+            self.return_type.write_error_return()
+            code_sink.unindent()
+            code_sink.writeln("}")
+        if cleanup is not None:
+            self.cleanup_actions.insert(0, cleanup)
+
+    def generate(self, sink):
+        '''Generate the code into a CodeSink object'''
+        assert isinstance(sink, CodeSink)
+
+        if DEBUG_MODE:
+            self.declarations.writeln("/* begin declarations */")
+            self.body.writeln("/* begin main body */")
+            self.post_return_code.writeln("/* begin post-return code */")
+
+        self.add_declaration("PyGILState_STATE __py_state;")
+        self.write_code(code="__py_state = pyg_gil_state_ensure();",
+                        cleanup="pyg_gil_state_release(__py_state);")
+
+        for param in self.parameters:
+            param.convert_c2py()
+
+        assert self.called_pyobj is not None,\
+               "Parameters failed to provide a target function or method."
+
+        if self.is_static:
+            sink.writeln('static %s' % self.return_type.get_c_type())
+        else:
+            sink.writeln(self.return_type.get_c_type())
+        c_proto_params = map(Parameter.format_for_c_proto, self.parameters)
+        sink.writeln("%s(%s)\n{" % (self.cname, ", ".join(c_proto_params)))
+
+        self.return_type.write_decl()
+        self.add_declaration("PyObject *py_retval;")
+
+        ## Handle number of arguments
+        if self.pyargv_items:
+            self.add_declaration("PyObject *py_args;")
+            py_args = "py_args"
+            if self.pyargv_optional_items:
+                self.add_declaration("int argc = %i;" % len(self.pyargv_items))
+                argc = "argc"
+                for arg in self.pyargv_optional_items:
+                    self.body.writeln("if (%s)" % arg)
+                    self.body.indent()
+                    self.body.writeln("++argc;")
+                    self.body.unindent()
+            else:
+                argc = str(len(self.pyargv_items))
+        else:
+            if self.pyargv_optional_items:
+                self.add_declaration("PyObject *py_args;")
+                py_args = "py_args"
+                self.add_declaration("int argc = 0;")
+                argc = "argc"
+                for arg in self.pyargv_optional_items:
+                    self.body.writeln("if (%s)" % arg)
+                    self.body.indent()
+                    self.body.writeln("++argc;")
+                    self.body.unindent()
+            else:
+                py_args = "NULL"
+                argc = None
+
+        self.body.writeln()
+
+        if py_args != "NULL":
+            self.write_code("py_args = PyTuple_New(%s);" % argc,
+                            cleanup="Py_DECREF(py_args);")
+            pos = 0
+            for arg in self.pyargv_items:
+                try: # try to remove the Py_DECREF cleanup action, if we can
+                    self.cleanup_actions.remove("Py_DECREF(%s);" % arg)
+                except ValueError: # otherwise we have to Py_INCREF..
+                    self.body.writeln("Py_INCREF(%s);" % arg)
+                self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
+                pos += 1
+            for arg in self.pyargv_optional_items:
+                self.body.writeln("if (%s) {" % arg)
+                self.body.indent()
+                try: # try to remove the Py_DECREF cleanup action, if we can
+                    self.cleanup_actions.remove("Py_XDECREF(%s);" % arg)
+                except ValueError: # otherwise we have to Py_INCREF..
+                    self.body.writeln("Py_INCREF(%s);" % arg)
+                self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
+                self.body.unindent()
+                self.body.writeln("}")
+                pos += 1
+
+        self.body.writeln()
+
+        ## Call the python method
+        if self.method_name is None:
+            self.write_code("py_retval = PyObject_Call(%s, %s);"
+                            % (self.called_pyobj, py_args),
+                            cleanup="Py_DECREF(py_retval);",
+                            failure_expression="!py_retval")
+        else:
+            self.add_declaration("PyObject *py_method;")
+            self.write_code("py_method = PyObject_GetAttrString(%s, \"%s\");"
+                            % (self.called_pyobj, self.method_name),
+                            cleanup="Py_DECREF(py_method);",
+                            failure_expression="!py_method")
+            self.write_code("py_retval = PyObject_CallObject(py_method, %s);"
+                            % (py_args,),
+                            cleanup="Py_DECREF(py_retval);",
+                            failure_expression="!py_retval")
+
+        ## -- Handle the return value --
+
+        ## we need to check if the return_type object is prepared to cooperate with multiple return values
+        len_before = len(self.pyret_parse_items)
+        self.return_type.write_conversion()
+        len_after = len(self.pyret_parse_items)
+        assert (self.return_type.get_c_type() == 'void'
+                or not (len_before == len_after and len_after > 0)),\
+               ("Bug in reverse wrappers: return type handler %s"
+                " is not prepared to cooperate multiple return values") % (type(self.return_type),)
+
+        sink.indent()
+
+        if len(self.pyret_parse_items) == 1:
+            ## if retval is one item only, pack it in a tuple so we
+            ## can use PyArg_ParseTuple as usual..
+            self.write_code('py_retval = Py_BuildValue("(N)", py_retval);')
+        if len(self.pyret_parse_items) > 0:
+            ## Parse return values using PyArg_ParseTuple
+            self.write_code(code=None, failure_expression=(
+                '!PyArg_ParseTuple(py_retval, "%s", %s)' % (
+                "".join([format for format, param in self.pyret_parse_items]),
+                ", ".join([param for format, param in self.pyret_parse_items]))))
+
+        if DEBUG_MODE:
+            self.declarations.writeln("/* end declarations */")
+        self.declarations.flush_to(sink)
+        sink.writeln()
+        if DEBUG_MODE:
+            self.body.writeln("/* end main body */")
+        self.body.flush_to(sink)
+        sink.writeln()
+        if DEBUG_MODE:
+            self.post_return_code.writeln("/* end post-return code */")
+        self.post_return_code.flush_to(sink)
+        sink.writeln()
+
+        for cleanup_action in self.cleanup_actions:
+            sink.writeln(cleanup_action)
+        if self.return_type.get_c_type() != 'void':
+            sink.writeln()
+            sink.writeln("return retval;")
+        sink.unindent()
+        sink.writeln("}")
+
+class TypeHandler(object):
+    def __init__(self, wrapper, **props):
+        assert isinstance(wrapper, ReverseWrapper)
+        self.wrapper = wrapper
+        self.props = props
+
+class ReturnType(TypeHandler):
+
+    def get_c_type(self):
+        raise NotImplementedError
+
+    def write_decl(self):
+        raise NotImplementedError
+
+    def write_error_return(self):
+        '''Write "return <value>" code in case of error'''
+        raise NotImplementedError
+
+    def write_conversion(self):
+        '''Writes code to convert Python return value in 'py_retval'
+        into C 'retval'.  Returns a string with C boolean expression
+        that determines if anything went wrong. '''
+        raise NotImplementedError
+
+class Parameter(TypeHandler):
+
+    def __init__(self, wrapper, name, **props):
+        TypeHandler.__init__(self, wrapper, **props)
+        self.name = name
+
+    def get_c_type(self):
+        raise NotImplementedError
+
+    def convert_c2py(self):
+        '''Write some code before calling the Python method.'''
+        pass
+
+    def format_for_c_proto(self):
+        return join_ctype_name(self.get_c_type(), self.name)
+
+
+###---
+class StringParam(Parameter):
+
+    def get_c_type(self):
+        return self.props.get('c_type', 'char *').replace('const-', 'const ')
+
+    def convert_c2py(self):
+        if self.props.get('optional', False):
+            self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
+            self.wrapper.write_code(code=("if (%s)\n"
+                                          "    py_%s = PyString_FromString(%s);\n"
+                                          % (self.name, self.name, self.name)),
+                                    cleanup=("Py_XDECREF(py_%s);" % self.name))
+            self.wrapper.add_pyargv_item("py_%s" % self.name, optional=True)
+        else:
+            self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+            self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" %
+                                          (self.name, self.name)),
+                                    cleanup=("Py_DECREF(py_%s);" % self.name),
+                                    failure_expression=("!py_%s" % self.name))
+            self.wrapper.add_pyargv_item("py_%s" % self.name)
+
+for ctype in ('char*', 'gchar*', 'const-char*', 'char-const*', 'const-gchar*',
+              'gchar-const*', 'string', 'static_string'):
+    argtypes.matcher.register_reverse(ctype, StringParam)
+del ctype
+
+class StringReturn(ReturnType):
+
+    def get_c_type(self):
+        return "char *"
+
+    def write_decl(self):
+        self.wrapper.add_declaration("char *retval;")
+
+    def write_error_return(self):
+        self.wrapper.write_code("return NULL;")
+
+    def write_conversion(self):
+        self.wrapper.add_pyret_parse_item("s", "&retval", prepend=True)
+        self.wrapper.write_code("retval = g_strdup(retval);", code_sink=self.wrapper.post_return_code)
+
+for ctype in ('char*', 'gchar*'):
+    argtypes.matcher.register_reverse_ret(ctype, StringReturn)
+del ctype
+
+
+class VoidReturn(ReturnType):
+
+    def get_c_type(self):
+        return "void"
+
+    def write_decl(self):
+        pass
+
+    def write_error_return(self):
+        self.wrapper.write_code("return;")
+
+    def write_conversion(self):
+        self.wrapper.write_code(
+            code=None,
+            failure_expression="py_retval != Py_None",
+            failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be None");')
+
+argtypes.matcher.register_reverse_ret('void', VoidReturn)
+argtypes.matcher.register_reverse_ret('none', VoidReturn)
+
+class GObjectParam(Parameter):
+
+    def get_c_type(self):
+        return self.props.get('c_type', 'GObject *')
+
+    def convert_c2py(self):
+        self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
+        self.wrapper.write_code(code=("if (%s)\n"
+                                      "    py_%s = pygobject_new((GObject *) %s);\n"
+                                      "else {\n"
+                                      "    Py_INCREF(Py_None);\n"
+                                      "    py_%s = Py_None;\n"
+                                      "}"
+                                      % (self.name, self.name, self.name, self.name)),
+                                cleanup=("Py_DECREF(py_%s);" % self.name))
+        self.wrapper.add_pyargv_item("py_%s" % self.name)
+
+argtypes.matcher.register_reverse('GObject*', GObjectParam)
+
+class GObjectReturn(ReturnType):
+
+    def get_c_type(self):
+        return self.props.get('c_type', 'GObject *')
+
+    def write_decl(self):
+        self.wrapper.add_declaration("%s retval;" % self.get_c_type())
+
+    def write_error_return(self):
+        self.wrapper.write_code("return NULL;")
+
+    def write_conversion(self):
+        self.wrapper.write_code(
+            code=None,
+            failure_expression="!PyObject_TypeCheck(py_retval, &PyGObject_Type)",
+            failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be a GObject");')
+        self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);"
+                                % self.get_c_type())
+        self.wrapper.write_code("g_object_ref((GObject *) retval);")
+
+argtypes.matcher.register_reverse_ret('GObject*', GObjectReturn)
+
+
+
+class IntParam(Parameter):
+
+    def get_c_type(self):
+        return self.props.get('c_type', 'int')
+
+    def convert_c2py(self):
+        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+        self.wrapper.write_code(code=("py_%s = PyInt_FromLong(%s);" %
+                                      (self.name, self.name)),
+                                cleanup=("Py_DECREF(py_%s);" % self.name))
+        self.wrapper.add_pyargv_item("py_%s" % self.name)
+
+class IntReturn(ReturnType):
+    def get_c_type(self):
+        return self.props.get('c_type', 'int')
+    def write_decl(self):
+        self.wrapper.add_declaration("%s retval;" % self.get_c_type())
+    def write_error_return(self):
+        self.wrapper.write_code("return -G_MAXINT;")
+    def write_conversion(self):
+        self.wrapper.add_pyret_parse_item("i", "&retval", prepend=True)
+
+for argtype in ('int', 'gint', 'guint', 'short', 'gshort', 'gushort', 'long',
+                'glong', 'gsize', 'gssize', 'guint8', 'gint8', 'guint16',
+                'gint16', 'gint32', 'GTime'):
+    argtypes.matcher.register_reverse(argtype, IntParam)
+    argtypes.matcher.register_reverse_ret(argtype, IntReturn)
+del argtype
+
+class IntPtrParam(Parameter):
+    def __init__(self, wrapper, name, **props):
+        if "direction" not in props:
+            raise ValueError("cannot use int* parameter without direction")
+        if props["direction"] not in ("out", "inout"):
+            raise ValueError("cannot use int* parameter with direction '%s'" % (props["direction"],))
+        Parameter.__init__(self, wrapper, name, **props)
+    def get_c_type(self):
+        return self.props.get('c_type', 'int*')
+    def convert_c2py(self):
+        if self.props["direction"] == "inout":
+            self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+            self.wrapper.write_code(code=("py_%s = PyInt_FromLong(*%s);" %
+                                          (self.name, self.name)),
+                                    cleanup=("Py_DECREF(py_%s);" % self.name))
+            self.wrapper.add_pyargv_item("py_%s" % self.name)
+        self.wrapper.add_pyret_parse_item("i", self.name)
+for argtype in ('int*', 'gint*'):
+    argtypes.matcher.register_reverse(argtype, IntPtrParam)
+del argtype
+
+
+class GEnumReturn(IntReturn):
+    def write_conversion(self):
+        self.wrapper.write_code(
+            code=None,
+            failure_expression=("pyg_enum_get_value(%s, py_retval, (gint *)&retval)" %
+                                self.props['typecode']))
+
+argtypes.matcher.register_reverse_ret("GEnum", GEnumReturn)
+
+class GEnumParam(IntParam):
+    def convert_c2py(self):
+        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+        self.wrapper.write_code(code=("py_%s = pyg_enum_from_gtype(%s, %s);" %
+                                      (self.name, self.props['typecode'], self.name)),
+                                cleanup=("Py_DECREF(py_%s);" % self.name),
+                                failure_expression=("!py_%s" % self.name))
+        self.wrapper.add_pyargv_item("py_%s" % self.name)
+
+argtypes.matcher.register_reverse("GEnum", GEnumParam)
+
+class GFlagsReturn(IntReturn):
+    def write_conversion(self):
+        self.wrapper.write_code(
+            code=None,
+            failure_expression=("pyg_flags_get_value(%s, py_retval, (gint *)&retval)" %
+                                self.props['typecode']))
+
+argtypes.matcher.register_reverse_ret("GFlags", GFlagsReturn)
+
+class GFlagsParam(IntParam):
+    def convert_c2py(self):
+        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+        self.wrapper.write_code(code=("py_%s = pyg_flags_from_gtype(%s, %s);" %
+                                      (self.name, self.props['typecode'], self.name)),
+                                cleanup=("Py_DECREF(py_%s);" % self.name),
+                                failure_expression=("!py_%s" % self.name))
+        self.wrapper.add_pyargv_item("py_%s" % self.name)
+
+argtypes.matcher.register_reverse("GFlags", GFlagsParam)
+
+
+class GtkTreePathParam(IntParam):
+    def convert_c2py(self):
+        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+        self.wrapper.write_code(code=("py_%s = pygtk_tree_path_to_pyobject(%s);" %
+                                      (self.name, self.name)),
+                                cleanup=("Py_DECREF(py_%s);" % self.name),
+                                failure_expression=("!py_%s" % self.name))
+        self.wrapper.add_pyargv_item("py_%s" % self.name)
+
+argtypes.matcher.register_reverse("GtkTreePath*", GtkTreePathParam)
+
+
+class BooleanReturn(ReturnType):
+    def get_c_type(self):
+        return "gboolean"
+    def write_decl(self):
+        self.wrapper.add_declaration("gboolean retval;")
+        self.wrapper.add_declaration("PyObject *py_main_retval;")
+    def write_error_return(self):
+        self.wrapper.write_code("return FALSE;")
+    def write_conversion(self):
+        self.wrapper.add_pyret_parse_item("O", "&py_main_retval", prepend=True)
+        self.wrapper.write_code("retval = PyObject_IsTrue(py_main_retval)? TRUE : FALSE;",
+                                code_sink=self.wrapper.post_return_code)
+argtypes.matcher.register_reverse_ret("gboolean", BooleanReturn)
+
+class BooleanParam(Parameter):
+    def get_c_type(self):
+        return "gboolean"
+    def convert_c2py(self):
+        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+        self.wrapper.write_code("py_%s = %s? Py_True : Py_False;"
+                                % (self.name, self.name))
+        self.wrapper.add_pyargv_item("py_%s" % self.name)
+
+argtypes.matcher.register_reverse("gboolean", BooleanParam)
+
+
+class DoubleParam(Parameter):
+    def get_c_type(self):
+        return self.props.get('c_type', 'gdouble')
+    def convert_c2py(self):
+        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+        self.wrapper.write_code(code=("py_%s = PyFloat_FromDouble(%s);" %
+                                      (self.name, self.name)),
+                                cleanup=("Py_DECREF(py_%s);" % self.name))
+        self.wrapper.add_pyargv_item("py_%s" % self.name)
+
+class DoublePtrParam(Parameter):
+    def __init__(self, wrapper, name, **props):
+        if "direction" not in props:
+            raise ValueError("cannot use double* parameter without direction")
+        if props["direction"] not in ("out", ): # inout not yet implemented
+            raise ValueError("cannot use double* parameter with direction '%s'" % (props["direction"],))
+        Parameter.__init__(self, wrapper, name, **props)
+    def get_c_type(self):
+        return self.props.get('c_type', 'double*')
+    def convert_c2py(self):
+        self.wrapper.add_pyret_parse_item("d", self.name)
+for argtype in ('double*', 'gdouble*'):
+    argtypes.matcher.register_reverse(argtype, DoublePtrParam)
+del argtype
+
+class DoubleReturn(ReturnType):
+    def get_c_type(self):
+        return self.props.get('c_type', 'gdouble')
+    def write_decl(self):
+        self.wrapper.add_declaration("%s retval;" % self.get_c_type())
+    def write_error_return(self):
+        self.wrapper.write_code("return -G_MAXFLOAT;")
+    def write_conversion(self):
+        self.wrapper.write_code(
+            code=None,
+            failure_expression="!PyFloat_AsDouble(py_retval)",
+            failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a float");')
+        self.wrapper.write_code("retval = PyFloat_AsDouble(py_retval);")
+
+for argtype in ('float', 'double', 'gfloat', 'gdouble'):
+    argtypes.matcher.register_reverse(argtype, DoubleParam)
+    argtypes.matcher.register_reverse_ret(argtype, DoubleReturn)
+
+
+class GBoxedParam(Parameter):
+    def get_c_type(self):
+        return self.props.get('c_type').replace('const-', 'const ')
+    def convert_c2py(self):
+        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+        ctype = self.get_c_type()
+        if ctype.startswith('const '):
+            ctype_no_const = ctype[len('const '):]
+            self.wrapper.write_code(
+                code=('py_%s = pyg_boxed_new(%s, (%s) %s, TRUE, TRUE);' %
+                      (self.name, self.props['typecode'],
+                       ctype_no_const, self.name)),
+                cleanup=("Py_DECREF(py_%s);" % self.name))
+        else:
+            self.wrapper.write_code(
+                code=('py_%s = pyg_boxed_new(%s, %s, FALSE, FALSE);' %
+                      (self.name, self.props['typecode'], self.name)),
+                cleanup=("Py_DECREF(py_%s);" % self.name))
+        self.wrapper.add_pyargv_item("py_%s" % self.name)
+
+argtypes.matcher.register_reverse("GBoxed", GBoxedParam)
+
+class GBoxedReturn(ReturnType):
+    def get_c_type(self):
+        return self.props.get('c_type')
+    def write_decl(self):
+        self.wrapper.add_declaration("%s retval;" % self.get_c_type())
+    def write_error_return(self):
+        self.wrapper.write_code("return retval;")
+    def write_conversion(self):
+        self.wrapper.write_code(
+            failure_expression=("!pyg_boxed_check(py_retval, %s)" %
+                                (self.props['typecode'],)),
+            failure_cleanup=('PyErr_SetString(PyExc_TypeError, "retval should be a %s");'
+                             % (self.props['typename'],)))
+        self.wrapper.write_code('retval = pyg_boxed_get(py_retval, %s);' %
+                                self.props['typename'])
+
+argtypes.matcher.register_reverse_ret("GBoxed", GBoxedReturn)
+
+
+class GdkRectanglePtrParam(Parameter):
+    def get_c_type(self):
+        return self.props.get('c_type').replace('const-', 'const ')
+    def convert_c2py(self):
+        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+        self.wrapper.write_code(
+            code=('py_%s = pyg_boxed_new(GDK_TYPE_RECTANGLE, %s, TRUE, TRUE);' %
+                  (self.name, self.name)),
+            cleanup=("Py_DECREF(py_%s);" % self.name))
+        self.wrapper.add_pyargv_item("py_%s" % self.name)
+
+argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam)
+argtypes.matcher.register_reverse('GtkAllocation*', GdkRectanglePtrParam)
+
+
+class PyGObjectMethodParam(Parameter):
+    def __init__(self, wrapper, name, method_name, **props):
+        Parameter.__init__(self, wrapper, name, **props)
+        self.method_name = method_name
+
+    def get_c_type(self):
+        return self.props.get('c_type', 'GObject *')
+
+    def convert_c2py(self):
+        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+        self.wrapper.write_code(code=("py_%s = pygobject_new((GObject *) %s);" %
+                                      (self.name, self.name)),
+                                cleanup=("Py_DECREF(py_%s);" % self.name),
+                                failure_expression=("!py_%s" % self.name))
+        self.wrapper.set_call_target("py_%s" % self.name, self.method_name)
+
+class CallbackInUserDataParam(Parameter):
+    def __init__(self, wrapper, name, free_it, **props):
+        Parameter.__init__(self, wrapper, name, **props)
+        self.free_it = free_it
+
+    def get_c_type(self):
+        return "gpointer"
+
+    def convert_c2py(self):
+        self.wrapper.add_declaration("PyObject **_user_data;")
+        cleanup = self.free_it and ("g_free(%s);" % self.name) or None
+        self.wrapper.write_code(code=("_real_user_data = (PyObject **) %s;"
+                                      % self.name),
+                                cleanup=cleanup)
+
+        self.wrapper.add_declaration("PyObject *py_func;")
+        cleanup = self.free_it and "Py_DECREF(py_func);" or None
+        self.wrapper.write_code(code="py_func = _user_data[0];",
+                                cleanup=cleanup)
+        self.wrapper.set_call_target("py_func")
+
+        self.wrapper.add_declaration("PyObject *py_user_data;")
+        cleanup = self.free_it and "Py_XDECREF(py_user_data);" or None
+        self.wrapper.write_code(code="py_user_data = _user_data[1];",
+                                cleanup=cleanup)
+        self.wrapper.add_pyargv_item("py_user_data", optional=True)
+
+def _test():
+    import sys
+
+    if 1:
+        wrapper = ReverseWrapper("this_is_the_c_function_name", is_static=True)
+        wrapper.set_return_type(StringReturn(wrapper))
+        wrapper.add_parameter(PyGObjectMethodParam(wrapper, "self", method_name="do_xxx"))
+        wrapper.add_parameter(StringParam(wrapper, "param2", optional=True))
+        wrapper.add_parameter(GObjectParam(wrapper, "param3"))
+        #wrapper.add_parameter(InoutIntParam(wrapper, "param4"))
+        wrapper.generate(FileCodeSink(sys.stderr))
+
+    if 0:
+        wrapper = ReverseWrapper("this_a_callback_wrapper")
+        wrapper.set_return_type(VoidReturn(wrapper))
+        wrapper.add_parameter(StringParam(wrapper, "param1", optional=False))
+        wrapper.add_parameter(GObjectParam(wrapper, "param2"))
+        wrapper.add_parameter(CallbackInUserDataParam(wrapper, "data", free_it=True))
+        wrapper.generate(FileCodeSink(sys.stderr))
+
+if __name__ == '__main__':
+    _test()
diff --git a/bindings/python/codegen/scmexpr.py b/bindings/python/codegen/scmexpr.py
new file mode 100644 (file)
index 0000000..d08c517
--- /dev/null
@@ -0,0 +1,144 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+from __future__ import generators
+
+import string
+import types
+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`