gstreamer/bindings/python/codegen/argtypes.py
2011-08-10 17:12:45 +02:00

1044 lines
44 KiB
Python

# -*- Mode: Python; py-indent-offset: 4 -*-
import string
import keyword
import struct
py_ssize_t_clean = False
class ArgTypeError(Exception):
pass
class ArgTypeNotFoundError(ArgTypeError):
pass
class ArgTypeConfigurationError(ArgTypeError):
pass
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 != None:
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)
if py_ssize_t_clean:
info.varlist.add('Py_ssize_t', pname + '_len')
else:
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):
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 + "'")
else:
info.varlist.add('gunichar', pname)
info.arglist.append(pname)
info.add_parselist('O&', ['pyg_pyobj_to_unichar_conv', '&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('gunichar', 'ret')
info.varlist.add('Py_UNICODE', 'py_ret')
info.codeafter.append(self.ret_tmpl)
class IntArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add('int', pname + ' = ' + pdflt)
else:
info.varlist.add('int', pname)
info.arglist.append(pname)
info.add_parselist('i', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('int', 'ret')
info.codeafter.append(' return PyInt_FromLong(ret);')
class UIntArg(ArgType):
dflt = (' if (py_%(name)s) {\n'
' if (PyLong_Check(py_%(name)s))\n'
' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n'
' else if (PyInt_Check(py_%(name)s))\n'
' %(name)s = PyInt_AsLong(py_%(name)s);\n'
' else\n'
' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n'
' if (PyErr_Occurred())\n'
' return NULL;\n'
' }\n')
before = (' if (PyLong_Check(py_%(name)s))\n'
' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n'
' else if (PyInt_Check(py_%(name)s))\n'
' %(name)s = PyInt_AsLong(py_%(name)s);\n'
' else\n'
' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n'
' if (PyErr_Occurred())\n'
' return NULL;\n')
def write_param(self, ptype, pname, pdflt, pnull, info):
if not pdflt:
pdflt = '0';
info.varlist.add(ptype, pname + ' = ' + pdflt)
info.codebefore.append(self.dflt % {'name':pname})
info.varlist.add('PyObject', "*py_" + pname + ' = NULL')
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add(ptype, 'ret')
info.codeafter.append(' return PyLong_FromUnsignedLong(ret);')
class SizeArg(ArgType):
if struct.calcsize('P') <= struct.calcsize('l'):
llp64 = True
else:
llp64 = False
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add(ptype, pname + ' = ' + pdflt)
else:
info.varlist.add(ptype, pname)
info.arglist.append(pname)
if self.llp64:
info.add_parselist('k', ['&' + pname], [pname])
else:
info.add_parselist('K', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add(ptype, 'ret')
if self.llp64:
info.codeafter.append(' return PyLong_FromUnsignedLongLong(ret);\n')
else:
info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n')
class SSizeArg(ArgType):
if struct.calcsize('P') <= struct.calcsize('l'):
llp64 = True
else:
llp64 = False
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add(ptype, pname + ' = ' + pdflt)
else:
info.varlist.add(ptype, pname)
info.arglist.append(pname)
if self.llp64:
info.add_parselist('l', ['&' + pname], [pname])
else:
info.add_parselist('L', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add(ptype, 'ret')
if self.llp64:
info.codeafter.append(' return PyLong_FromLongLong(ret);\n')
else:
info.codeafter.append(' return PyLong_FromLong(ret);\n')
class LongArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add(ptype, pname + ' = ' + pdflt)
else:
info.varlist.add(ptype, pname)
info.arglist.append(pname)
info.add_parselist('l', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add(ptype, 'ret')
info.codeafter.append(' return PyInt_FromLong(ret);\n')
class BoolArg(IntArg):
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('int', 'ret')
info.codeafter.append(' return PyBool_FromLong(ret);\n')
class TimeTArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add('time_t', pname + ' = ' + pdflt)
else:
info.varlist.add('time_t', pname)
info.arglist.append(pname)
info.add_parselist('i', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('time_t', 'ret')
info.codeafter.append(' return PyInt_FromLong(ret);')
class ULongArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add('unsigned long', pname + ' = ' + pdflt)
else:
info.varlist.add('unsigned long', pname)
info.arglist.append(pname)
info.add_parselist('k', ['&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add(ptype, 'ret')
info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n')
class UInt32Arg(ULongArg):
def write_param(self, ptype, pname, pdflt, pnull, info):
ULongArg.write_param(self, ptype, pname, pdflt, pnull, info)
## if sizeof(unsigned long) > sizeof(unsigned int), we need to
## check the value is within guint32 range
if struct.calcsize('L') > struct.calcsize('I'):
info.codebefore.append((
' if (%(pname)s > G_MAXUINT32) {\n'
' PyErr_SetString(PyExc_ValueError,\n'
' "Value out of range in conversion of"\n'
' " %(pname)s parameter to unsigned 32 bit integer");\n'
' return NULL;\n'
' }\n') % vars())
class Int64Arg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, 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, (gpointer)&%(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 pyg_enum_from_gtype(%s, ret);' % self.typecode)
class FlagsArg(ArgType):
flag = (' if (%(default)spyg_flags_get_value(%(typecode)s, py_%(name)s, (gpointer)&%(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 pyg_flags_from_gtype(%s, ret);' % self.typecode)
class ObjectArg(ArgType):
# should change these checks to more typesafe versions that check
# a little further down in the class heirachy.
nulldflt = (' if ((PyObject *)py_%(name)s == Py_None)\n'
' %(name)s = NULL;\n'
' else if (py_%(name)s && pygobject_check(py_%(name)s, &Py%(type)s_Type))\n'
' %(name)s = %(cast)s(py_%(name)s->obj);\n'
' else if (py_%(name)s) {\n'
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
' return NULL;\n'
' }\n')
null = (' if (py_%(name)s && pygobject_check(py_%(name)s, &Py%(type)s_Type))\n'
' %(name)s = %(cast)s(py_%(name)s->obj);\n'
' else if ((PyObject *)py_%(name)s != Py_None) {\n'
' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
' return NULL;\n'
' }\n')
dflt = ' if (py_%(name)s)\n' \
' %(name)s = %(cast)s(py_%(name)s->obj);\n'
def __init__(self, objname, parent, typecode):
self.objname = objname
self.cast = string.replace(typecode, '_TYPE_', '_', 1)
self.parent = parent
def write_param(self, ptype, pname, pdflt, pnull, info):
if pnull:
if pdflt:
info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
info.varlist.add('PyGObject', '*py_' + pname + ' = NULL')
info.codebefore.append(self.nulldflt % {'name':pname,
'cast':self.cast,
'type':self.objname})
else:
info.varlist.add(self.objname, '*' + pname + ' = NULL')
info.varlist.add('PyGObject', '*py_' + pname)
info.codebefore.append(self.null % {'name':pname,
'cast':self.cast,
'type':self.objname})
if ptype.endswith('*'):
typename = ptype[:-1]
try:
const, typename = typename.split('const-')
except ValueError:
const = ''
if typename != ptype:
info.arglist.append('(%s *) %s' % (ptype[:-1], pname))
else:
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
else:
if pdflt:
info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
info.varlist.add('PyGObject', '*py_' + pname + ' = NULL')
info.codebefore.append(self.dflt % {'name':pname,
'cast':self.cast})
info.arglist.append(pname)
info.add_parselist('O!', ['&Py%s_Type' % self.objname,
'&py_' + pname], [pname])
else:
info.varlist.add('PyGObject', '*' + pname)
info.arglist.append('%s(%s->obj)' % (self.cast, pname))
info.add_parselist('O!', ['&Py%s_Type' % self.objname,
'&' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
if ptype.endswith('*'):
typename = ptype[:-1]
try:
const, typename = typename.split('const-')
except ValueError:
const = ''
info.varlist.add(typename, '*ret')
if ownsreturn:
info.varlist.add('PyObject', '*py_ret')
info.codeafter.append(' py_ret = pygobject_new((GObject *)ret);\n'
' if (ret != NULL)\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] == '*':
decl_type = self.typename
ret = 'ret'
if ptype[:6] == 'const-':
decl_type = 'const ' + self.typename
ret = '(%s*) ret' % (self.typename,)
info.varlist.add(decl_type, '*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):
dflt = ' if (py_%(name)s) {\n' \
' %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n' \
' if (PyErr_Occurred())\n' \
' return NULL;\n' \
' }\n'
atom = (' %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n'
' if (PyErr_Occurred())\n'
' return NULL;\n')
def write_param(self, ptype, pname, pdflt, pnull, info):
if pdflt:
info.varlist.add('GdkAtom', pname + ' = ' + pdflt)
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
info.codebefore.append(self.dflt % {'name': pname})
else:
info.varlist.add('GdkAtom', pname)
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
info.codebefore.append(self.atom % {'name': pname})
info.arglist.append(pname)
info.add_parselist('O', ['&py_' + pname], [pname])
def write_return(self, ptype, ownsreturn, info):
info.varlist.add('GdkAtom', 'ret')
info.varlist.add('PyObject *', 'py_ret')
info.varlist.add('gchar *', 'name')
info.codeafter.append(' name = gdk_atom_name(ret);\n'
' py_ret = PyString_FromString(name);\n'
' g_free(name);\n'
' return py_ret;')
class GTypeArg(ArgType):
gtype = (' if ((%(name)s = pyg_type_from_object(py_%(name)s)) == 0)\n'
' return NULL;\n')
def write_param(self, ptype, pname, pdflt, pnull, 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')
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 CairoArg(ArgType):
def write_param(self, ptype, pname, pdflt, pnull, info):
info.varlist.add('PycairoContext', '*' + pname)
info.add_parselist('O!', ['&PycairoContext_Type', '&' + pname], [pname])
info.arglist.append('%s->ctx' % pname)
def write_return(self, ptype, ownsreturn, info):
info.varlist.add("cairo_t", "*ret")
if ownsreturn:
info.codeafter.append(' return PycairoContext_FromContext(ret, NULL, NULL);')
else:
info.codeafter.append(' cairo_reference(ret);\n'
' return PycairoContext_FromContext(ret, NULL, NULL);')
class ArgMatcher:
def __init__(self):
self.argtypes = {}
self.reverse_argtypes = {}
self.reverse_rettypes = {}
def register(self, ptype, handler, overwrite=False):
if not overwrite and ptype in self.argtypes:
return
self.argtypes[ptype] = handler
def register_reverse(self, ptype, handler):
self.reverse_argtypes[ptype] = handler
def register_reverse_ret(self, ptype, handler):
self.reverse_rettypes[ptype] = handler
def register_enum(self, ptype, typecode):
if typecode is None:
self.register(ptype, IntArg())
else:
self.register(ptype, EnumArg(ptype, typecode))
def register_flag(self, ptype, typecode):
if typecode is None:
self.register(ptype, IntArg())
else:
self.register(ptype, FlagsArg(ptype, typecode))
def register_object(self, ptype, parent, typecode):
oa = ObjectArg(ptype, parent, typecode)
self.register(ptype, oa) # in case I forget the * in the .defs
self.register(ptype+'*', oa)
self.register('const-'+ptype+'*', oa)
if ptype == 'GdkPixmap':
# hack to handle GdkBitmap synonym.
self.register('GdkBitmap', oa)
self.register('GdkBitmap*', oa)
def register_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 ArgTypeNotFoundError("No ArgType for %s" % (ptype,))
def _get_reverse_common(self, ptype, registry):
props = dict(c_type=ptype)
try:
return registry[ptype], props
except KeyError:
try:
handler = self.argtypes[ptype]
except KeyError:
if ptype.startswith('GdkEvent') and ptype.endswith('*'):
handler = self.argtypes['GdkEvent*']
else:
raise ArgTypeNotFoundError("No ArgType for %s" % (ptype,))
if isinstance(handler, ObjectArg):
return registry['GObject*'], props
elif isinstance(handler, EnumArg):
props['typecode'] = handler.typecode
props['enumname'] = handler.enumname
return registry['GEnum'], props
elif isinstance(handler, FlagsArg):
props['typecode'] = handler.typecode
props['flagname'] = handler.flagname
return registry['GFlags'], props
elif isinstance(handler, BoxedArg):
props['typecode'] = handler.typecode
props['typename'] = handler.typename
return registry['GBoxed'], props
else:
raise ArgTypeNotFoundError("No ArgType for %s" % (ptype,))
def get_reverse(self, ptype):
return self._get_reverse_common(ptype, self.reverse_argtypes)
def get_reverse_ret(self, ptype):
ret, props = self._get_reverse_common(ptype, self.reverse_rettypes)
if hasattr(ptype, 'optional') and ptype.optional:
if ret.supports_optional:
props['optional'] = True
else:
raise ArgTypeNotFoundError("Unsupported 'optional' for %s"
% (ptype,))
return ret, props
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('const-guint8*', arg)
matcher.register('guchar*', arg)
arg = CharArg()
matcher.register('char', arg)
matcher.register('gchar', arg)
matcher.register('guchar', arg)
arg = GUniCharArg()
matcher.register('gunichar', arg)
arg = IntArg()
matcher.register('int', arg)
matcher.register('gint', arg)
matcher.register('short', arg)
matcher.register('gshort', arg)
matcher.register('gushort', arg)
matcher.register('gsize', SizeArg())
matcher.register('gssize', SSizeArg())
matcher.register('guint8', arg)
matcher.register('gint8', arg)
matcher.register('guint16', arg)
matcher.register('gint16', arg)
matcher.register('gint32', arg)
matcher.register('GTime', arg)
matcher.register('GSeekType', arg) # Hack, but we have no python wrapper
arg = LongArg()
matcher.register('long', arg)
matcher.register('glong', arg)
arg = UIntArg()
matcher.register('guint', arg)
arg = BoolArg()
matcher.register('gboolean', arg)
arg = TimeTArg()
matcher.register('time_t', arg)
matcher.register('guint32', UInt32Arg())
arg = ULongArg()
matcher.register('gulong', arg)
arg = Int64Arg()
matcher.register('gint64', arg)
matcher.register('long-long', arg)
matcher.register('goffset', 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
matcher.register('cairo_t*', CairoArg())
matcher.register_boxed("GClosure", "G_TYPE_CLOSURE")