configure.ac (PYGTK_CODEGEN): Use built in code generator again and don't require 2.3.91, 2.0.0 should do fine (FC1 o...

Original commit message from CVS:
* configure.ac (PYGTK_CODEGEN): Use built in code generator again
and don't require 2.3.91, 2.0.0 should do fine (FC1 ok, RH9 isn't)

* TODO: Update

* gst/interfaces.override, gst/play.override: Add typedef for
python < 2.3

* codegen/codegen.py: Readd :/
This commit is contained in:
Johan Dahlin 2004-04-16 16:53:29 +00:00
parent f203f4826c
commit 90579783ce
23 changed files with 4481 additions and 18 deletions

View file

@ -1,5 +1,15 @@
2004-04-16 Johan Dahlin <johan@gnome.org>
* configure.ac (PYGTK_CODEGEN): Use built in code generator again
and don't require 2.3.91, 2.0.0 should do fine (FC1 ok, RH9 isn't)
* TODO: Update
* gst/interfaces.override, gst/play.override: Add typedef for
python < 2.3
* codegen/codegen.py: Readd :/
* testsuite/pipeline.py (PipelineConstructor.testGoodConstructor)
(PipelineConstructor.testBadConstruct)
(ThreadConstructor.testCreate): New tests

2
TODO
View file

@ -1 +1 @@
This file will be autogenerated. Please read README-docs.
Add a pygst-private.h and put some common stuff in there.

1
codegen/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.pyc

15
codegen/__init__.py Normal file
View file

@ -0,0 +1,15 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
__all__ = [
'argtypes',
'codegen',
'definitions',
'defsparser',
'docextract',
'docgen',
'h2def',
'mergedefs',
'mkskel',
'override',
'scmexpr'
]

845
codegen/argtypes.py Normal file
View file

@ -0,0 +1,845 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
import sys
import string
import traceback
import keyword
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, 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, 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, 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, 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):
param_tmpl = (' if (py_%(name)s[1] != 0) {\n'
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a 1 character unicode string");\n'
' return NULL;\n'
' }\n'
' %(name)s = (gunichar)py_%(name)s[0];\n')
dflt_tmpl = (' if (py_%(name)s != NULL) {\n'
' if (py_%(name)s[1] != 0) {\n'
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a 1 character unicode string");\n'
' return NULL;\n'
' }\n'
' %(name)s = (gunichar)py_%(name)s[0];\n'
' }\n')
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, info):
if pdflt:
info.varlist.add('gunichar', pname + " = '" + pdflt + "'")
info.codebefore.append(self.dflt_tmpl % {'name':pname})
else:
info.varlist.add('gunichar', pname)
info.codebefore.append(self.param_tmpl % {'name':pname})
info.varlist.add('Py_UNICODE', '*py_' + pname + ' = NULL')
info.arglist.append(pname)
info.add_parselist('u', ['&py_' + 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, 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 BoolArg(IntArg):
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('int', 'ret')
info.varlist.add('PyObject', '*py_ret')
info.codeafter.append(' py_ret = ret ? Py_True : Py_False;\n'
' Py_INCREF(py_ret);\n'
' return py_ret;')
class TimeTArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, 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):
dflt = ' if (py_%(name)s)\n' \
' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n'
before = ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n'
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add('gulong', pname + ' = ' + pdflt)
info.codebefore.append(self.dflt % {'name':pname})
else:
info.varlist.add('gulong', pname)
info.codebefore.append(self.before % {'name':pname})
info.varlist.add('PyObject', "*py_" + pname + ' = NULL')
info.arglist.append(pname)
info.add_parselist('O!', ['&PyLong_Type', '&py_' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('gulong', 'ret')
info.codeafter.append(' return PyLong_FromUnsignedLong(ret);')
class Int64Arg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, 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):
dflt = ' if (py_%(name)s)\n' \
' %(name)s = PyLong_AsUnsignedLongLong(py_%(name)s);\n'
before = ' %(name)s = PyLong_AsUnsignedLongLong(py_%(name)s);\n'
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add('guint64', pname + ' = ' + pdflt)
info.codebefore.append(self.dflt % {'name':pname})
else:
info.varlist.add('guint64', pname)
info.codebefore.append(self.before % {'name':pname})
info.varlist.add('PyObject', "*py_" + pname + ' = NULL')
info.arglist.append(pname)
info.add_parselist('O!', ['&PyLong_Type', '&py_' + 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, 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, 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, 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 PyInt_FromLong(ret);')
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, 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 PyInt_FromLong(ret);')
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, 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})
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[-1] == '*': ptype = ptype[:-1]
info.varlist.add(ptype, '*ret')
if ownsreturn:
info.varlist.add('PyObject', '*py_ret')
info.codeafter.append(' py_ret = pygobject_new((GObject *)ret);\n'
' g_object_unref(ret);\n'
' return py_ret;')
else:
info.codeafter.append(' /* pygobject_new handles NULL checking */\n' +
' return pygobject_new((GObject *)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, 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, 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, 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):
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, info):
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.codeafter.append(' return PyGdkAtom_New(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, 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, 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')
null = (' if (PyTuple_Check(py_%(name)s))\n'
' %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n'
' else if (py_%(name)s != Py_None) {\n'
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a GtkTreePath or None");\n'
' return NULL;\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, 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, 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, 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 = {}
def register(self, ptype, handler):
self.argtypes[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)
if ptype == 'GdkPixmap':
# hack to handle GdkBitmap synonym.
self.register('GdkBitmap', oa)
self.register('GdkBitmap*', 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 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('guint', arg)
matcher.register('short', arg)
matcher.register('gshort', arg)
matcher.register('gushort', arg)
matcher.register('long', arg)
matcher.register('glong', arg)
matcher.register('gsize', arg)
matcher.register('gssize', arg)
matcher.register('guint8', arg)
matcher.register('gint8', arg)
matcher.register('guint16', arg)
matcher.register('gint16', arg)
matcher.register('gint32', arg)
arg = BoolArg()
matcher.register('gboolean', arg)
arg = TimeTArg()
matcher.register('time_t', arg)
# If the system maxint is smaller than unsigned int, we need to use
# Long objects with PyLong_AsUnsignedLong
if sys.maxint >= (1L << 32):
matcher.register('guint32', arg)
else:
arg = ULongArg()
matcher.register('guint32', arg)
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')
del arg

42
codegen/code-coverage.py Executable file
View file

@ -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()

843
codegen/codegen.py Normal file
View file

@ -0,0 +1,843 @@
import sys, os, string
import getopt, traceback, keyword
import defsparser, argtypes, override
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)0, /* 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)0, /* tp_getattro */\n' \
' (setattrofunc)0, /* tp_setattro */\n' \
' 0, /* tp_as_buffer */\n' \
' Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */\n' \
' NULL, /* Documentation string */\n' \
' (traverseproc)0, /* tp_traverse */\n' \
' (inquiry)0, /* 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' \
' %(tp_methods)s, /* tp_methods */\n' \
' 0, /* tp_members */\n' \
' %(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_compare', 'tp_repr',
'tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'tp_hash',
'tp_call', 'tp_str', 'tp_richcompare', 'tp_iter',
'tp_iternext', 'tp_descr_get', 'tp_descr_set', 'tp_init',
'tp_alloc', 'tp_new', 'tp_free', 'tp_is_gc']
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'
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' \
' %(setreturn)s%(cname)s(%(arglist)s);\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):
return { 'name': '%s.%s' % (self.objinfo.c_name, method.name) }
def write_class(self):
self.fp.write('\n/* ----------- ' + self.objinfo.c_name + ' ----------- */\n\n')
substdict = self.get_initial_class_substdict()
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
# 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:
if substdict.has_key(slot) and substdict[slot] != '0':
continue
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:
substdict[slot] = '0'
self.fp.write(self.type_tmpl % substdict)
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 ptype, pname, pdflt, pnull in function_obj.params:
if pdflt and '|' not in info.parsestr:
info.add_parselist('|', [], [])
handler = argtypes.matcher.get(ptype)
handler.write_param(ptype, pname, pdflt, pnull, 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)
if self.objinfo:
substdict['typename'] = self.objinfo.c_name
substdict['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 constructor:
funcname = constructor.c_name
try:
if self.overrides.is_overriden(funcname):
data = self.overrides.override(funcname)
self.write_function(funcname, data)
else:
# 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()))
# 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'
else:
# 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 get_methflags(self, funcname):
if self.overrides.wants_kwargs(funcname):
return 'METH_VARARGS|METH_KEYWORDS'
elif self.overrides.wants_noargs(funcname):
return 'METH_NOARGS'
else:
return 'METH_VARARGS'
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 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})
except:
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)
self.get_methflags(method_name)
methods.append(self.methdef_tmpl %
{ 'name': method_name,
'cname': '_wrap_' + c_name,
'flags': methflags})
except:
sys.stderr.write('Could not write method %s.%s: %s\n'
% (klass, meth.name, exc_info()))
if methods:
methoddefs = '_Py%s_methods' % self.objinfo.c_name
# write the PyMethodDef structure
methods.append(' { NULL, NULL, 0 }\n')
self.fp.write('static PyMethodDef %s[] = {\n' % methoddefs)
self.fp.write(string.join(methods, ''))
self.fp.write('};\n\n')
else:
methoddefs = 'NULL'
return methoddefs
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, fname in self.objinfo.fields:
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(fname),
'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 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 })
except:
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)
methflags = self.get_methflags(funcname)
functions.append(self.methdef_tmpl %
{ 'name': funcname,
'cname': '_wrap_' + funcname,
'flags': methflags })
except:
sys.stderr.write('Could not write function %s: %s\n'
% (funcname, exc_info()))
# write the PyMethodDef structure
functions.append(' { NULL, NULL, 0 }\n')
self.fp.write('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' \
' %(setreturn)s%(cname)s(%(cast)s(self->obj)%(arglist)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 argtypes.matcher.object_is_a(self.objinfo.c_name, 'GtkWindow'):
substdict['aftercreate'] = " g_object_ref(self->obj); /* we don't own the first reference of windows */\n"
elif argtypes.matcher.object_is_a(self.objinfo.c_name, 'GtkInvisible'):
substdict['aftercreate'] = " g_object_ref(self->obj); /* we don't own the first reference of invisibles */\n"
else:
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
class GInterfaceWrapper(GObjectWrapper):
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'
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' \
' %(setreturn)s%(cname)s(pyg_boxed_get(self, %(typename)s)%(arglist)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 GENERATE - 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_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 interface in parser.interfaces:
fp.write('PyTypeObject Py' + interface.c_name + '_Type;\n')
fp.write('\n')
def write_classes(parser, overrides, fp):
for klass, items in ((GBoxedWrapper, parser.boxes),
(GPointerWrapper, parser.pointers),
(GObjectWrapper, parser.objects),
(GInterfaceWrapper, parser.interfaces)):
for item in items:
instance = klass(parser, item, overrides, fp)
instance.write_class()
fp.write('\n')
def write_enums(parser, 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 enum.typecode is None:
for nick, value in enum.values:
fp.write(' PyModule_AddIntConstant(module, pyg_constant_strip_prefix("%s", strip_prefix), %s);\n'
% (value, value))
else:
if enum.deftype == 'enum':
fp.write(' pyg_enum_add_constants(module, %s, strip_prefix);\n'
% (enum.typecode,))
else:
fp.write(' pyg_flags_add_constants(module, %s, strip_prefix);\n'
% (enum.typecode,))
fp.write('}\n\n')
def write_extension_init(overrides, prefix, fp):
fp.write('/* intialise 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, fp):
for boxed in parser.boxes:
fp.write(' pyg_register_boxed(d, "' + boxed.name +
'", ' + boxed.typecode + ', &Py' + boxed.c_name + '_Type);\n')
for pointer in parser.pointers:
fp.write(' pyg_register_pointer(d, "' + pointer.name +
'", ' + pointer.typecode + ', &Py' + pointer.c_name + '_Type);\n')
for interface in parser.interfaces:
fp.write(' pyg_register_interface(d, "' + interface.name +
'", '+ interface.typecode + ', &Py' + interface.c_name +
'_Type);\n')
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:
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')
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_classes(parser, overrides, fp)
wrapper = Wrapper(parser, None, overrides, fp)
wrapper.write_functions(prefix)
write_enums(parser, prefix, fp)
write_extension_init(overrides, prefix, fp)
write_registers(parser, 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.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
opts, args = getopt.getopt(argv[1:], "o:p:r:t:D:",
["override=", "prefix=", "register=", "outfilename=",
"load-types=", "errorfilename="])
defines = {} # -Dkey[=val] options
for opt, arg in opts:
if opt in ('-o', '--override'):
o = override.Overrides(arg)
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))
if __name__ == '__main__':
sys.exit(main(sys.argv))

419
codegen/definitions.py Normal file
View file

@ -0,0 +1,419 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
import sys
class Definition:
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"
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 = []
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.fields = []
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] == 'c-name':
self.c_name = arg[1]
elif arg[0] == 'gtype-id':
self.typecode = arg[1]
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 args:
if type(arg) != type(()) or len(arg) < 2:
continue
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 args:
if type(arg) != type(()) or len(arg) < 2:
continue
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 args:
if type(arg) != type(()) or len(arg) < 2:
continue
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 MethodDef(Definition):
def __init__(self, name, *args):
dump = 0
self.name = name
self.ret = None
self.caller_owns_return = 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 args:
if type(arg) != type(()) or len(arg) < 2:
continue
if arg[0] == 'of-object':
self.of_object = 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] == 'parameters':
for parg in arg[1:]:
ptype = parg[0]
pname = parg[1]
pdflt = None
pnull = 0
for farg in parg[2:]:
if farg[0] == 'default':
pdflt = farg[1]
elif farg[0] == 'null-ok':
pnull = 1
self.params.append((ptype, pname, pdflt, pnull))
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:
if self.ret[:6] == 'const-':
self.caller_owns_return = 0
elif self.ret in ('char*', 'gchar*', 'string'):
self.caller_owns_return = 1
else:
self.caller_owns_return = 0
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 merge(self, old):
# here we merge extra parameter flags accross to the new object.
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):
fp.write('(define-method ' + self.name + '\n')
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.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')
fp.write(')\n\n')
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.c_name = None
self.typecode = None
self.params = [] # of form (type, name, default, nullok)
self.varargs = 0
self.deprecated = None
for arg in args:
if type(arg) != type(()) or len(arg) < 2:
continue
if arg[0] == 'in-module':
self.in_module = 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] == 'parameters':
for parg in arg[1:]:
ptype = parg[0]
pname = parg[1]
pdflt = None
pnull = 0
for farg in parg[2:]:
if farg[0] == 'default':
pdflt = farg[1]
elif farg[0] == 'null-ok':
pnull = 1
self.params.append((ptype, pname, pdflt, pnull))
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:
if self.ret[:6] == 'const-':
self.caller_owns_return = 0
elif self.is_constructor_of:
self.caller_owns_return = 1
elif self.ret in ('char*', 'gchar*', 'string'):
self.caller_owns_return = 1
else:
self.caller_owns_return = 0
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):
# here we merge extra parameter flags accross to the new object.
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
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.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')
fp.write(')\n\n')

130
codegen/defsconvert.py Normal file
View file

@ -0,0 +1,130 @@
import sys
import string, re
# ------------------ 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"""
return string.replace(to_upper_str(typename), '_', '_TYPE_', 1)
STATE_START = 0
STATE_OBJECT = 1
STATE_INTERFACE = 2
STATE_BOXED = 3
STATE_ENUM = 4
STATE_FLAGS = 5
STATE_METHOD = 6
STATE_FUNCTION = 7
def convert(infp=sys.stdin, outfp=sys.stdout):
state = STATE_START
seen_params = 0
line = infp.readline()
while line:
if line[:8] == '(object ':
state = STATE_OBJECT
seen_params = 0
outfp.write('(define-object ' + line[8:])
elif line[:11] == '(interface ':
state = STATE_INTERFACE
seen_params = 0
outfp.write('(define-interface ' + line[11:])
elif line[:7] == '(boxed ':
state = STATE_BOXED
seen_params = 0
outfp.write('(define-boxed ' + line[7:])
elif line[:6] == '(enum ':
state = STATE_ENUM
seen_params = 0
outfp.write('(define-enum ' + line[6:])
elif line[:7] == '(flags ':
state = STATE_FLAGS
seen_params = 0
outfp.write('(define-flags ' + line[7:])
elif line[:8] == '(method ':
state = STATE_METHOD
seen_params = 0
outfp.write('(define-method ' + line[8:])
elif line[:10] == '(function ':
state = STATE_FUNCTION
seen_params = 0
outfp.write('(define-function ' + line[10:])
elif line[:13] == ' (in-module ':
outfp.write(re.sub(r'^(\s+\(in-module\s+)(\w+)(.*)$',
r'\1"\2"\3', line))
elif line[:10] == ' (parent ':
outfp.write(re.sub(r'^(\s+\(parent\s+)(\w+)(\s+\((\w+)\))?(.*)$',
r'\1"\4\2"\5', line))
elif line[:14] == ' (implements ':
outfp.write(re.sub(r'^(\s+\(implements\s+)([^\s]+)(\s*\))$',
r'\1"\2"\3', line))
elif line[:13] == ' (of-object ':
outfp.write(re.sub(r'^(\s+\(of-object\s+)(\w+)(\s+\((\w+)\))?(.*)$',
r'\1"\4\2"\5', line))
elif line[:10] == ' (c-name ':
outfp.write(re.sub(r'^(\s+\(c-name\s+)([^\s]+)(\s*\))$',
r'\1"\2"\3', line))
if state in (STATE_OBJECT, STATE_INTERFACE, STATE_BOXED,
STATE_ENUM, STATE_FLAGS):
c_name = re.match(r'^\s+\(c-name\s+([^\s]+)\s*\)$',
line).group(1)
outfp.write(' (gtype-id "%s")\n' % typecode(c_name))
elif line[:15] == ' (return-type ':
outfp.write(re.sub(r'^(\s+\(return-type\s+)([^\s]+)(\s*\))$',
r'\1"\2"\3', line))
elif line[:13] == ' (copy-func ':
outfp.write(re.sub(r'^(\s+\(copy-func\s+)(\w+)(.*)$',
r'\1"\2"\3', line))
elif line[:16] == ' (release-func ':
outfp.write(re.sub(r'^(\s+\(release-func\s+)(\w+)(.*)$',
r'\1"\2"\3', line))
elif line[:9] == ' (field ':
if not seen_params:
outfp.write(' (fields\n')
seen_params = 1
outfp.write(re.sub(r'^\s+\(field\s+\(type-and-name\s+([^\s]+)\s+([^\s]+)\s*\)\s*\)$',
' \'("\\1" "\\2")', line))
elif line[:9] == ' (value ':
if not seen_params:
outfp.write(' (values\n')
seen_params = 1
outfp.write(re.sub(r'^\s+\(value\s+\(name\s+([^\s]+)\)\s+\(c-name\s+([^\s]+)\s*\)\s*\)$',
' \'("\\1" "\\2")', line))
elif line[:13] == ' (parameter ':
if not seen_params:
outfp.write(' (parameters\n')
seen_params = 1
outfp.write(re.sub(r'^\s+\(parameter\s+\(type-and-name\s+([^\s]+)\s+([^\s]+)\s*\)(\s*.*)\)$',
' \'("\\1" "\\2"\\3)', line))
elif line[:11] == ' (varargs ':
if seen_params:
outfp.write(' )\n')
seen_params = 0
outfp.write(' (varargs #t)\n')
elif line[0] == ')':
if seen_params:
outfp.write(' )\n')
seen_params = 0
state = STATE_START
outfp.write(line)
else:
outfp.write(line)
line = infp.readline()
if __name__ == '__main__':
convert()

122
codegen/defsparser.py Normal file
View file

@ -0,0 +1,122 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
import os, sys
import scmexpr
from definitions import *
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.interfaces = []
self.enums = [] # enums and flags
self.boxes = [] # boxed types
self.pointers = [] # pointer types
self.functions = [] # functions and methods
self.c_name = {} # hash of c names of functions
self.methods = {} # hash of methods of particular objects
self.defines = defines # -Dfoo=bar options, as dictionary
def define_object(self, *args):
odef = apply(ObjectDef, args)
self.objects.append(odef)
self.c_name[odef.c_name] = odef
def define_interface(self, *args):
idef = apply(InterfaceDef, args)
self.interfaces.append(idef)
self.c_name[idef.c_name] = idef
def define_enum(self, *args):
edef = apply(EnumDef, args)
self.enums.append(edef)
self.c_name[edef.c_name] = edef
def define_flags(self, *args):
fdef = apply(FlagsDef, args)
self.enums.append(fdef)
self.c_name[fdef.c_name] = fdef
def define_boxed(self, *args):
bdef = apply(BoxedDef, args)
self.boxes.append(bdef)
self.c_name[bdef.c_name] = bdef
def define_pointer(self, *args):
pdef = apply(PointerDef, args)
self.pointers.append(pdef)
self.c_name[pdef.c_name] = pdef
def define_function(self, *args):
fdef = apply(FunctionDef, args)
self.functions.append(fdef)
self.c_name[fdef.c_name] = fdef
def define_method(self, *args):
mdef = apply(MethodDef, args)
self.functions.append(mdef)
self.c_name[mdef.c_name] = mdef
def merge(self, old):
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])
def printMissing(self, old):
for obj in self.objects:
if not old.c_name.has_key(obj.c_name):
obj.write_defs()
for f in self.functions:
if not old.c_name.has_key(f.c_name):
f.write_defs()
def write_defs(self, fp=sys.stdout):
for obj in self.objects:
obj.write_defs(fp)
for enum in self.enums:
enum.write_defs(fp)
for boxed in self.boxes:
boxed.write_defs(fp)
for pointer in self.pointers:
pointer.write_defs(fp)
for func in self.functions:
func.write_defs(fp)
def find_object(self, c_name):
for obj in self.objects:
if obj.c_name == c_name:
return obj
else:
raise ValueError, 'object 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_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)

185
codegen/docextract.py Normal file
View file

@ -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
cur_doc.description = cur_doc.description + return_start + \
cur_doc.ret
return_start = match.group(1)
cur_doc.ret = match.group(2)
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

78
codegen/docextract_to_xml.py Executable file
View file

@ -0,0 +1,78 @@
#!/usr/bin/env python
# -*- Mode: Python; py-indent-offset: 4 -*-
#
# This litte script outputs the C doc comments to an XML format.
# So far it's only used by gtkmm (The C++ bindings). Murray Cumming.
# Usage example:
# # ./docextract_to_xml.py -s /gnome/head/cvs/gtk+/gtk/ -s /gnome/head/cvs/gtk+/docs/reference/gtk/tmpl/ > gtk_docs.xml
import sys, os, string, re, getopt
import docextract
import string
def escape_text(unescaped_text):
escaped_text = unescaped_text
escaped_text = string.replace(escaped_text, '<', '&lt;')
escaped_text = string.replace(escaped_text, '>', '&gt;')
escaped_text = string.replace(escaped_text, '&', '&amp;')
escaped_text = string.replace(escaped_text, '\'', '&apos;')
escaped_text = string.replace(escaped_text, '\"', '&quot;')
#Apparently this is an undefined symbol:
escaped_text = string.replace(escaped_text, '&mdash;', ' mdash ')
return escaped_text
if __name__ == '__main__':
try:
opts, args = getopt.getopt(sys.argv[1:], "d:s:o:",
["source-dir="])
except getopt.error, e:
sys.stderr.write('docgen.py: %s\n' % e)
sys.stderr.write(
'usage: docgen.py [-s /src/dir]\n')
sys.exit(1)
source_dirs = []
for opt, arg in opts:
if opt in ('-s', '--source-dir'):
source_dirs.append(arg)
if len(args) != 0:
sys.stderr.write(
'usage: docgen.py [-s /src/dir]\n')
sys.exit(1)
docs = docextract.extract(source_dirs);
docextract.extract_tmpl(source_dirs, docs); #Try the tmpl sgml files too.
# print d.docs
if docs:
print "<root>"
for name, value in docs.items():
print "<function name=\"" + escape_text(name) + "\">"
print "<description>"
#The value is a docextract.FunctionDoc
print escape_text(value.description)
print "</description>"
# Loop through the parameters:
print "<parameters>"
for name, description in value.params:
print "<parameter name=\"" + escape_text(name) + "\">"
print "<parameter_description>" + escape_text(description) + "</parameter_description>"
print "</parameter>"
print "</parameters>"
# Show the return-type:
print "<return>" + escape_text(value.ret) + "</return>"
print "</function>\n"
print "</root>"

751
codegen/docgen.py Normal file
View file

@ -0,0 +1,751 @@
#!/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:
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)

513
codegen/h2def.py Executable file
View file

@ -0,0 +1,513 @@
#!/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
import string, sys, re, types
# ------------------ 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"""
return string.replace(to_upper_str(typename), '_', '_TYPE_', 1)
# ------------------ 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
def write_obj_defs(objdefs, output):
if type(output)==types.StringType:
fp=open(output,'w')
elif type(output)==types.FileType:
fp=output
else:
fp=sys.stdout
fp.write(';; -*- scheme -*-\n')
fp.write('; object definitions ...\n')
for klass, parent in objdefs:
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')
# ------------------ 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()
def write_enum_defs(enums, output=None):
if type(output)==types.StringType:
fp=open(output,'w')
elif type(output)==types.FileType:
fp=output
else:
fp=sys.stdout
fp.write(';; Enumerations and flags ...\n\n')
trans = string.maketrans(string.uppercase + '_', string.lowercase + '-')
for cname, isflags, entries in enums:
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')
# ------------------ 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 (
(?P<args>.*?)[)] # group the function arguments
""", re.IGNORECASE|re.VERBOSE)
#"""
arg_split_pat = re.compile("\s*,\s*")
def define_func(buf,fp, prefix):
buf=clean_func(buf)
buf=string.split(buf,'\n')
for p in buf:
if len(p)==0: continue
m=proto_pat.match(p)
if m==None:
if verbose:
sys.stderr.write('No match:|%s|\n'%p)
continue
func = m.group('func')
if func[0] == '_':
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)
write_func(fp, func, ret, args, prefix)
get_type_pat = re.compile(r'(const-)?([A-Za-z0-9]+)\*?\s+')
pointer_pat = re.compile('.*\*$')
func_new_pat = re.compile('(\w+)_new$')
def write_func(fp, name, ret, args, prefix):
if len(args) >= 1:
# methods must have at least one argument
munged_name = string.replace(name, '_', '')
m = get_type_pat.match(args[0])
if m:
obj = m.group(2)
if munged_name[:len(obj)] == string.lower(obj):
regex = string.join(map(lambda x: x+'_?',string.lower(obj)),'')
mname = re.sub(regex, '', name)
if prefix:
l = len(prefix) + 1
if mname[:l] == prefix and mname[l+1] == '_':
mname = mname[l+1:]
fp.write('(define-method ' + mname + '\n')
fp.write(' (of-object "' + obj + '")\n')
fp.write(' (c-name "' + name + '")\n')
if ret != 'void':
fp.write(' (return-type "' + ret + '")\n')
else:
fp.write(' (return-type "none")\n')
is_varargs = 0
has_args = len(args) > 1
for arg in args[1:]:
if arg == '...':
is_varargs = 1
elif arg in ('void', 'void '):
has_args = 0
if has_args:
fp.write(' (parameters\n')
for arg in args[1:]:
if arg != '...':
tupleArg = tuple(string.split(arg))
if len(tupleArg) == 2:
fp.write(' \'("%s" "%s")\n' % tupleArg)
fp.write(' )\n')
if is_varargs:
fp.write(' (varargs #t)\n')
fp.write(')\n\n')
return
if prefix:
l = len(prefix)
if name[:l] == prefix and name[l] == '_':
fname = name[l+1:]
else:
fname = name
else:
fname = name
# it is either a constructor or normal function
fp.write('(define-function ' + fname + '\n')
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 != '':
fp.write(' (is-constructor-of "' + cname + '")\n')
if ret != 'void':
fp.write(' (return-type "' + ret + '")\n')
else:
fp.write(' (return-type "none")\n')
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:
fp.write(' (parameters\n')
for arg in args:
if arg != '...':
tupleArg = tuple(string.split(arg))
if len(tupleArg) == 2:
fp.write(' \'("%s" "%s")\n' % tupleArg)
fp.write(' )\n')
if is_varargs:
fp.write(' (varargs #t)\n')
fp.write(')\n\n')
def write_def(input,output=None, prefix=None):
fp = open(input)
buf = fp.read()
fp.close()
if type(output) == types.StringType:
fp = open(output,'w')
elif type(output) == types.FileType:
fp = output
else:
fp = sys.stdout
fp.write('\n;; From %s\n\n' % input)
buf = define_func(buf, fp, prefix)
fp.write('\n')
# ------------------ Main function -----------------
verbose=0
def main(args):
import getopt
global verbose
onlyenums = 0
onlyobjdefs = 0
separate = 0
modulename = None
opts, args = getopt.getopt(args[1:], 'vs:m:',
['onlyenums', 'onlyobjdefs',
'modulename=', 'separate='])
for o, v in opts:
if o == '-v':
verbose = 1
if o == '--onlyenums':
onlyenums = 1
if o == '--onlyobjdefs':
onlyobjdefs = 1
if o in ('-s', '--separate'):
separate = v
if o in ('-m', '--modulename'):
modulename = 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:
types = file(separate + '-types.defs', 'w')
methods = file(separate + '.defs', 'w')
write_obj_defs(objdefs,types)
write_enum_defs(enums,types)
types.close()
print "Wrote %s-types.defs" % separate
for filename in args:
write_def(filename,methods,prefix=modulename)
methods.close()
print "Wrote %s.defs" % separate
else:
if onlyenums:
write_enum_defs(enums,None)
elif onlyobjdefs:
write_obj_defs(objdefs,None)
else:
write_obj_defs(objdefs,None)
write_enum_defs(enums,None)
for filename in args:
write_def(filename,None,prefix=modulename)
if __name__ == '__main__':
sys.exit(main(sys.argv))

19
codegen/mergedefs.py Executable file
View file

@ -0,0 +1,19 @@
#!/usr/bin/env python
# -*- Mode: Python; py-indent-offset: 4 -*-
import sys
import defsparser
if len(sys.argv) < 3:
sys.stderr.write("Usage: mergedefs.py generated-defs old-defs\n")
sys.exit(1)
newp = defsparser.DefsParser(sys.argv[1])
oldp = defsparser.DefsParser(sys.argv[2])
newp.startParsing()
oldp.startParsing()
newp.merge(oldp)
newp.write_defs()

17
codegen/missingdefs.py Executable file
View file

@ -0,0 +1,17 @@
#!/usr/bin/env python
# -*- Mode: Python; py-indent-offset: 4 -*-
import sys
import defsparser
if len(sys.argv) < 3:
sys.stderr.write("Usage: missingdefs.py generated-defs old-defs\n")
sys.exit(1)
newp = defsparser.DefsParser(sys.argv[1])
oldp = defsparser.DefsParser(sys.argv[2])
newp.startParsing()
oldp.startParsing()
newp.printMissing(oldp)

89
codegen/mkskel.py Executable file
View file

@ -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)

223
codegen/override.py Normal file
View file

@ -0,0 +1,223 @@
# -*- 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):
self.modulename = None
self.ignores = {}
self.glob_ignores = []
self.overrides = {}
self.overridden = {}
self.kwargs = {}
self.noargs = {}
self.startlines = {}
self.override_attrs = {}
self.override_slots = {}
self.headers = ''
self.init = ''
self.imports = []
self.defines = {}
self.functions = {}
if filename:
self.handle_file(filename)
def handle_file(self, filename):
oldpath = os.getcwd()
fp = open(filename, 'r')
dirname = os.path.dirname(os.path.abspath(filename))
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 == 'override':
"override function/method [kwargs,noargs]"
func = words[1]
if 'kwargs' in words[1:]:
self.kwargs[func] = 1
elif 'noargs' in words[1:]:
self.noargs[func] = 1
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 == '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]"
"define Class.method [kwargs,noargs]"
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
self.startlines[func] = (startline + 1, filename)
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_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 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_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

144
codegen/scmexpr.py Normal file
View file

@ -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`

View file

@ -22,7 +22,7 @@ dnl Add parameters for aclocal
ACLOCAL="$ACLOCAL -I common/m4 $ACLOCAL_FLAGS"
dnl required versions of other packages
AC_SUBST(PYGTK_REQ, 2.3.91)
AC_SUBST(PYGTK_REQ, 2.0.0)
AC_SUBST(GLIB_REQ, 2.0.0)
AC_SUBST(GTK_REQ, 2.0.0)
AC_SUBST(GST_REQ, 0.8.0)
@ -71,11 +71,11 @@ AC_SUBST(PYGTK_H2DEF)
AC_MSG_RESULT($PYGTK_H2DEF)
dnl AC_MSG_CHECKING(for pygtk codegen)
PYGTK_CODEGEN="$PYTHON `$PKG_CONFIG --variable=codegendir pygtk-2.0`/codegen.py"
AC_SUBST(PYGTK_CODEGEN)
AC_MSG_RESULT($PYGTK_CODEGEN)
dnl PYGTK_CODEGEN="$PYTHON \$(top_srcdir)/codegen/codegen.py"
dnl PYGTK_CODEGEN="$PYTHON `$PKG_CONFIG --variable=codegendir pygtk-2.0`/codegen.py"
dnl AC_SUBST(PYGTK_CODEGEN)
dnl AC_MSG_RESULT($PYGTK_CODEGEN)
PYGTK_CODEGEN="$PYTHON \$(top_srcdir)/codegen/codegen.py"
AC_SUBST(PYGTK_CODEGEN)
AC_MSG_CHECKING(for GStreamer interfaces include dir)
PKG_CHECK_MODULES(GST_INTERFACES, gstreamer-interfaces-$GST_MAJORMINOR,

View file

@ -35,6 +35,9 @@ headers
#include <gst/gsttypefind.h>
#include <gst/gsttag.h>
#if PY_VERSION_HEX < 0x02030000
typedef destructor freefunc;
#endif
typedef struct {
PyGObject *pad;
PyObject *link_function;
@ -54,6 +57,13 @@ static PyObject *_wrap_gst_element_factory_make(PyObject *self, PyObject *args,
include
gstpad-handlers.override
%%
init
/* This is due to a bug in PyGTK 2.3.91, should be removed when we can require
* a newer version.
*/
PyGstPipeline_Type.tp_new = PyType_GenericNew;
PyGstThread_Type.tp_new = PyType_GenericNew;
%%
modulename gst
%%
import gobject.GObject as PyGObject_Type
@ -533,16 +543,24 @@ _wrap_gst_buffer_new(PyGBoxed *self, PyObject *args, PyObject *kwargs)
GST_BUFFER_SIZE (self->boxed) = size;
GST_BUFFER_DATA (self->boxed) = data;
// if (data)
// memcpy(GST_BUFFER_DATA (self->boxed), data, size);
#if 0
if (data)
memcpy(GST_BUFFER_DATA (self->boxed), data, size);
// gst_buffer_set_data (self->boxed, data, size);
// gst_buffer_ref (GST_BUFFER (self->boxed));
gst_buffer_set_data (self->boxed, data, size);
gst_buffer_ref (GST_BUFFER (self->boxed));
#endif
return 0;
}
%%
override-slot GstCaps.tp_str
static PyObject *
_wrap_gst_caps_tp_str(PyGObject *self)
{
return PyString_FromString(gst_caps_to_string((GstCaps*)self->obj));
}
%%
define GstTagList.keys noargs
void
tag_foreach_func_dict (const GstTagList *list,
@ -1058,10 +1076,3 @@ _wrap_gst_element_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
return _wrap_gst_element_factory_make(NULL, args, kwargs);
}
%%
init
/* This is due to a bug in PyGTK 2.3.91, should be removed when we can require
* a newer version.
*/
PyGstPipeline_Type.tp_new = PyType_GenericNew;
PyGstThread_Type.tp_new = PyType_GenericNew;

View file

@ -34,6 +34,9 @@ headers
#include <gst/tuner/tuner.h>
#include <gst/xwindowlistener/xwindowlistener.h>
#if PY_VERSION_HEX < 0x02030000
typedef destructor freefunc;
#endif
%%
modulename gst.interfaces
%%

View file

@ -27,6 +27,9 @@ headers
#include <gst/gst.h>
#include <gst/play/play.h>
#if PY_VERSION_HEX < 0x02030000
typedef destructor freefunc;
#endif
%%
modulename gst.play
%%