46e868e2b9540c0b1390fefc106d68822da1ae2b
[platform/upstream/pygobject2.git] / codegen / argtypes.py
1 # -*- Mode: Python; py-indent-offset: 4 -*-
2 import string
3 import keyword
4 import struct
5
6 py_ssize_t_clean = False
7
8 class ArgTypeError(Exception):
9     pass
10
11 class ArgTypeNotFoundError(ArgTypeError):
12     pass
13
14 class ArgTypeConfigurationError(ArgTypeError):
15     pass
16
17
18 class VarList:
19     """Nicely format a C variable list"""
20     def __init__(self):
21         self.vars = {}
22     def add(self, ctype, name):
23         if self.vars.has_key(ctype):
24             self.vars[ctype] = self.vars[ctype] + (name,)
25         else:
26             self.vars[ctype] = (name,)
27     def __str__(self):
28         ret = []
29         for type in self.vars.keys():
30             ret.append('    ')
31             ret.append(type)
32             ret.append(' ')
33             ret.append(string.join(self.vars[type], ', '))
34             ret.append(';\n')
35         if ret:
36             ret.append('\n')
37             return string.join(ret, '')
38         return ''
39
40 class WrapperInfo:
41     """A class that holds information about variable defs, code
42     snippets, etcd for use in writing out the function/method
43     wrapper."""
44     def __init__(self):
45         self.varlist = VarList()
46         self.parsestr = ''
47         self.parselist = ['', 'kwlist']
48         self.codebefore = []
49         self.codeafter = []
50         self.arglist = []
51         self.kwlist = []
52     def get_parselist(self):
53         return string.join(self.parselist, ', ')
54     def get_codebefore(self):
55         return string.join(self.codebefore, '')
56     def get_codeafter(self):
57         return string.join(self.codeafter, '')
58     def get_arglist(self):
59         return string.join(self.arglist, ', ')
60     def get_varlist(self):
61         return str(self.varlist)
62     def get_kwlist(self):
63         ret = '    static char *kwlist[] = { %s };\n' % \
64               string.join(self.kwlist + [ 'NULL' ], ', ')
65         if not self.get_varlist():
66             ret = ret + '\n'
67         return ret
68
69     def add_parselist(self, codes, parseargs, keywords):
70         self.parsestr = self.parsestr + codes
71         for arg in parseargs:
72             self.parselist.append(arg)
73         for kw in keywords:
74             if keyword.iskeyword(kw):
75                 kw = kw + '_'
76             self.kwlist.append('"%s"' % kw)
77
78 class ArgType:
79     def write_param(self, ptype, pname, pdflt, pnull, info):
80         """Add code to the WrapperInfo instance to handle
81         parameter."""
82         raise RuntimeError("write_param not implemented for %s"
83                            % self.__class__.__name__)
84     def write_return(self, ptype, ownsreturn, info):
85         """Adds a variable named ret of the return type to
86         info.varlist, and add any required code to info.codeafter to
87         convert the return value to a python object."""
88         raise RuntimeError("write_return not implemented for %s"
89                            % self.__class__.__name__)
90
91 class NoneArg(ArgType):
92     def write_return(self, ptype, ownsreturn, info):
93         info.codeafter.append('    Py_INCREF(Py_None);\n' +
94                               '    return Py_None;')
95
96 class StringArg(ArgType):
97     def write_param(self, ptype, pname, pdflt, pnull, info):
98         if pdflt != None:
99             if pdflt != 'NULL': pdflt = '"' + pdflt + '"'
100             info.varlist.add('char', '*' + pname + ' = ' + pdflt)
101         else:
102             info.varlist.add('char', '*' + pname)
103         info.arglist.append(pname)
104         if pnull:
105             info.add_parselist('z', ['&' + pname], [pname])
106         else:
107             info.add_parselist('s', ['&' + pname], [pname])
108     def write_return(self, ptype, ownsreturn, info):
109         if ownsreturn:
110             # have to free result ...
111             info.varlist.add('gchar', '*ret')
112             info.codeafter.append('    if (ret) {\n' +
113                                   '        PyObject *py_ret = PyString_FromString(ret);\n' +
114                                   '        g_free(ret);\n' +
115                                   '        return py_ret;\n' +
116                                   '    }\n' +
117                                   '    Py_INCREF(Py_None);\n' +
118                                   '    return Py_None;')
119         else:
120             info.varlist.add('const gchar', '*ret')
121             info.codeafter.append('    if (ret)\n' +
122                                   '        return PyString_FromString(ret);\n'+
123                                   '    Py_INCREF(Py_None);\n' +
124                                   '    return Py_None;')
125
126 class UCharArg(ArgType):
127     # allows strings with embedded NULLs.
128     def write_param(self, ptype, pname, pdflt, pnull, info):
129         if pdflt:
130             info.varlist.add('guchar', '*' + pname + ' = "' + pdflt + '"')
131         else:
132             info.varlist.add('guchar', '*' + pname)
133         if py_ssize_t_clean:
134             info.varlist.add('Py_ssize_t', pname + '_len')
135         else:
136             info.varlist.add('int', pname + '_len')
137         info.arglist.append(pname)
138         if pnull:
139             info.add_parselist('z#', ['&' + pname, '&' + pname + '_len'],
140                                [pname])
141         else:
142             info.add_parselist('s#', ['&' + pname, '&' + pname + '_len'],
143                                [pname])
144
145 class CharArg(ArgType):
146     def write_param(self, ptype, pname, pdflt, pnull, info):
147         if pdflt:
148             info.varlist.add('char', pname + " = '" + pdflt + "'")
149         else:
150             info.varlist.add('char', pname)
151         info.arglist.append(pname)
152         info.add_parselist('c', ['&' + pname], [pname])
153     def write_return(self, ptype, ownsreturn, info):
154         info.varlist.add('gchar', 'ret')
155         info.codeafter.append('    return PyString_FromStringAndSize(&ret, 1);')
156 class GUniCharArg(ArgType):
157     ret_tmpl = ('#if !defined(Py_UNICODE_SIZE) || Py_UNICODE_SIZE == 2\n'
158                 '    if (ret > 0xffff) {\n'
159                 '        PyErr_SetString(PyExc_RuntimeError, "returned character can not be represented in 16-bit unicode");\n'
160                 '        return NULL;\n'
161                 '    }\n'
162                 '#endif\n'
163                 '    py_ret = (Py_UNICODE)ret;\n'
164                 '    return PyUnicode_FromUnicode(&py_ret, 1);\n')
165     def write_param(self, ptype, pname, pdflt, pnull, info):
166         if pdflt:
167             info.varlist.add('gunichar', pname + " = '" + pdflt + "'")
168         else:
169             info.varlist.add('gunichar', pname)
170         info.arglist.append(pname)
171         info.add_parselist('O&', ['pyg_pyobj_to_unichar_conv', '&' + pname], [pname])
172     def write_return(self, ptype, ownsreturn, info):
173         info.varlist.add('gunichar', 'ret')
174         info.varlist.add('Py_UNICODE', 'py_ret')
175         info.codeafter.append(self.ret_tmpl)
176
177
178 class IntArg(ArgType):
179     def write_param(self, ptype, pname, pdflt, pnull, info):
180         if pdflt:
181             info.varlist.add('int', pname + ' = ' + pdflt)
182         else:
183             info.varlist.add('int', pname)
184         info.arglist.append(pname)
185         info.add_parselist('i', ['&' + pname], [pname])
186     def write_return(self, ptype, ownsreturn, info):
187         info.varlist.add('int', 'ret')
188         info.codeafter.append('    return PyInt_FromLong(ret);')
189
190 class UIntArg(ArgType):
191     dflt = ('    if (py_%(name)s) {\n'
192             '        if (PyLong_Check(py_%(name)s))\n'
193             '            %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n'
194             '        else if (PyInt_Check(py_%(name)s))\n'
195             '            %(name)s = PyInt_AsLong(py_%(name)s);\n'
196             '        else\n'
197             '            PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n'
198             '        if (PyErr_Occurred())\n'
199             '            return NULL;\n'
200             '    }\n')
201     before = ('    if (PyLong_Check(py_%(name)s))\n'
202               '        %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n'
203               '    else if (PyInt_Check(py_%(name)s))\n'
204               '        %(name)s = PyInt_AsLong(py_%(name)s);\n'
205               '    else\n'
206               '        PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n'
207               '    if (PyErr_Occurred())\n'
208               '        return NULL;\n')
209     def write_param(self, ptype, pname, pdflt, pnull, info):
210         if not pdflt:
211             pdflt = '0';
212
213         info.varlist.add(ptype, pname + ' = ' + pdflt)
214         info.codebefore.append(self.dflt % {'name':pname})
215         info.varlist.add('PyObject', "*py_" + pname + ' = NULL')
216         info.arglist.append(pname)
217         info.add_parselist('O', ['&py_' + pname], [pname])
218     def write_return(self, ptype, ownsreturn, info):
219         info.varlist.add(ptype, 'ret')
220         info.codeafter.append('    return PyLong_FromUnsignedLong(ret);')
221
222 class SizeArg(ArgType):
223
224     if struct.calcsize('P') <= struct.calcsize('l'):
225         llp64 = True
226     else:
227         llp64 = False
228
229     def write_param(self, ptype, pname, pdflt, pnull, info):
230         if pdflt:
231             info.varlist.add(ptype, pname + ' = ' + pdflt)
232         else:
233             info.varlist.add(ptype, pname)
234         info.arglist.append(pname)
235         if self.llp64:
236             info.add_parselist('k', ['&' + pname], [pname])
237         else:
238             info.add_parselist('K', ['&' + pname], [pname])
239     def write_return(self, ptype, ownsreturn, info):
240         info.varlist.add(ptype, 'ret')
241         if self.llp64:
242             info.codeafter.append('    return PyLong_FromUnsignedLongLong(ret);\n')
243         else:
244             info.codeafter.append('    return PyLong_FromUnsignedLong(ret);\n')
245
246 class SSizeArg(ArgType):
247
248     if struct.calcsize('P') <= struct.calcsize('l'):
249         llp64 = True
250     else:
251         llp64 = False
252
253     def write_param(self, ptype, pname, pdflt, pnull, info):
254         if pdflt:
255             info.varlist.add(ptype, pname + ' = ' + pdflt)
256         else:
257             info.varlist.add(ptype, pname)
258         info.arglist.append(pname)
259         if self.llp64:
260             info.add_parselist('l', ['&' + pname], [pname])
261         else:
262             info.add_parselist('L', ['&' + pname], [pname])
263     def write_return(self, ptype, ownsreturn, info):
264         info.varlist.add(ptype, 'ret')
265         if self.llp64:
266             info.codeafter.append('    return PyLong_FromLongLong(ret);\n')
267         else:
268             info.codeafter.append('    return PyLong_FromLong(ret);\n')
269
270 class LongArg(ArgType):
271     def write_param(self, ptype, pname, pdflt, pnull, info):
272         if pdflt:
273             info.varlist.add(ptype, pname + ' = ' + pdflt)
274         else:
275             info.varlist.add(ptype, pname)
276         info.arglist.append(pname)
277         info.add_parselist('l', ['&' + pname], [pname])
278     def write_return(self, ptype, ownsreturn, info):
279         info.varlist.add(ptype, 'ret')
280         info.codeafter.append('    return PyInt_FromLong(ret);\n')
281
282 class BoolArg(IntArg):
283     def write_return(self, ptype, ownsreturn, info):
284         info.varlist.add('int', 'ret')
285         info.codeafter.append('    return PyBool_FromLong(ret);\n')
286
287 class TimeTArg(ArgType):
288     def write_param(self, ptype, pname, pdflt, pnull, info):
289         if pdflt:
290             info.varlist.add('time_t', pname + ' = ' + pdflt)
291         else:
292             info.varlist.add('time_t', pname)
293         info.arglist.append(pname)
294         info.add_parselist('i', ['&' + pname], [pname])
295     def write_return(self, ptype, ownsreturn, info):
296         info.varlist.add('time_t', 'ret')
297         info.codeafter.append('    return PyInt_FromLong(ret);')
298
299 class ULongArg(ArgType):
300     def write_param(self, ptype, pname, pdflt, pnull, info):
301         if pdflt:
302             info.varlist.add('unsigned long', pname + ' = ' + pdflt)
303         else:
304             info.varlist.add('unsigned long', pname)
305         info.arglist.append(pname)
306         info.add_parselist('k', ['&' + pname], [pname])
307     def write_return(self, ptype, ownsreturn, info):
308         info.varlist.add(ptype, 'ret')
309         info.codeafter.append('    return PyLong_FromUnsignedLong(ret);\n')
310
311 class UInt32Arg(ULongArg):
312     def write_param(self, ptype, pname, pdflt, pnull, info):
313         ULongArg.write_param(self, ptype, pname, pdflt, pnull, info)
314         ## if sizeof(unsigned long) > sizeof(unsigned int), we need to
315         ## check the value is within guint32 range
316         if struct.calcsize('L') > struct.calcsize('I'):
317             info.codebefore.append((
318                 '    if (%(pname)s > G_MAXUINT32) {\n'
319                 '        PyErr_SetString(PyExc_ValueError,\n'
320                 '                        "Value out of range in conversion of"\n'
321                 '                        " %(pname)s parameter to unsigned 32 bit integer");\n'
322                 '        return NULL;\n'
323                 '    }\n') % vars())
324
325 class Int64Arg(ArgType):
326     def write_param(self, ptype, pname, pdflt, pnull, info):
327         if pdflt:
328             info.varlist.add('gint64', pname + ' = ' + pdflt)
329         else:
330             info.varlist.add('gint64', pname)
331         info.arglist.append(pname)
332         info.add_parselist('L', ['&' + pname], [pname])
333     def write_return(self, ptype, ownsreturn, info):
334         info.varlist.add('gint64', 'ret')
335         info.codeafter.append('    return PyLong_FromLongLong(ret);')
336
337 class UInt64Arg(ArgType):
338     dflt = '    if (py_%(name)s)\n' \
339            '        %(name)s = PyLong_AsUnsignedLongLong(py_%(name)s);\n'
340     before = '    %(name)s = PyLong_AsUnsignedLongLong(py_%(name)s);\n'
341     def write_param(self, ptype, pname, pdflt, pnull, info):
342         if pdflt:
343             info.varlist.add('guint64', pname + ' = ' + pdflt)
344             info.codebefore.append(self.dflt % {'name':pname})
345         else:
346             info.varlist.add('guint64', pname)
347             info.codebefore.append(self.before % {'name':pname})
348         info.varlist.add('PyObject', "*py_" + pname + ' = NULL')
349         info.arglist.append(pname)
350         info.add_parselist('O!', ['&PyLong_Type', '&py_' + pname], [pname])
351     def write_return(self, ptype, ownsreturn, info):
352         info.varlist.add('guint64', 'ret')
353         info.codeafter.append('    return PyLong_FromUnsignedLongLong(ret);')
354
355
356 class DoubleArg(ArgType):
357     def write_param(self, ptype, pname, pdflt, pnull, info):
358         if pdflt:
359             info.varlist.add('double', pname + ' = ' + pdflt)
360         else:
361             info.varlist.add('double', pname)
362         info.arglist.append(pname)
363         info.add_parselist('d', ['&' + pname], [pname])
364     def write_return(self, ptype, ownsreturn, info):
365         info.varlist.add('double', 'ret')
366         info.codeafter.append('    return PyFloat_FromDouble(ret);')
367
368 class FileArg(ArgType):
369     nulldflt = ('    if (py_%(name)s == Py_None)\n'
370                 '        %(name)s = NULL;\n'
371                 '    else if (py_%(name)s && PyFile_Check(py_%(name)s)\n'
372                 '        %s = PyFile_AsFile(py_%(name)s);\n'
373                 '    else if (py_%(name)s) {\n'
374                 '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a file object or None");\n'
375                 '        return NULL;\n'
376                 '    }')
377     null = ('    if (py_%(name)s && PyFile_Check(py_%(name)s)\n'
378             '        %(name)s = PyFile_AsFile(py_%(name)s);\n'
379             '    else if (py_%(name)s != Py_None) {\n'
380             '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a file object or None");\n'
381             '        return NULL;\n'
382             '    }\n')
383     dflt = ('    if (py_%(name)s)\n'
384             '        %(name)s = PyFile_AsFile(py_%(name)s);\n')
385     def write_param(self, ptype, pname, pdflt, pnull, info):
386         if pnull:
387             if pdflt:
388                 info.varlist.add('FILE', '*' + pname + ' = ' + pdflt)
389                 info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
390                 info.codebefore.append(self.nulldflt % {'name':pname})
391             else:
392                 info.varlist.add('FILE', '*' + pname + ' = NULL')
393                 info.varlist.add('PyObject', '*py_' + pname)
394                 info.codebefore.append(self.null & {'name':pname})
395             info.arglist.appned(pname)
396             info.add_parselist('O', ['&py_' + pname], [pname])
397         else:
398             if pdflt:
399                 info.varlist.add('FILE', '*' + pname + ' = ' + pdflt)
400                 info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
401                 info.codebefore.append(self.dflt % {'name':pname})
402                 info.arglist.append(pname)
403             else:
404                 info.varlist.add('PyObject', '*' + pname)
405                 info.arglist.append('PyFile_AsFile(' + pname + ')')
406             info.add_parselist('O!', ['&PyFile_Type', '&' + pname], [pname])
407     def write_return(self, ptype, ownsreturn, info):
408         info.varlist.add('FILE', '*ret')
409         info.codeafter.append('    if (ret)\n' +
410                               '        return PyFile_FromFile(ret, "", "", fclose);\n' +
411                               '    Py_INCREF(Py_None);\n' +
412                               '    return Py_None;')
413
414 class EnumArg(ArgType):
415     enum = ('    if (pyg_enum_get_value(%(typecode)s, py_%(name)s, (gpointer)&%(name)s))\n'
416             '        return NULL;\n')
417     def __init__(self, enumname, typecode):
418         self.enumname = enumname
419         self.typecode = typecode
420     def write_param(self, ptype, pname, pdflt, pnull, info):
421         if pdflt:
422             info.varlist.add(self.enumname, pname + ' = ' + pdflt)
423         else:
424             info.varlist.add(self.enumname, pname)
425         info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
426         info.codebefore.append(self.enum % { 'typecode': self.typecode,
427                                              'name': pname})
428         info.arglist.append(pname)
429         info.add_parselist('O', ['&py_' + pname], [pname]);
430     def write_return(self, ptype, ownsreturn, info):
431         info.varlist.add('gint', 'ret')
432         info.codeafter.append('    return pyg_enum_from_gtype(%s, ret);' % self.typecode)
433
434 class FlagsArg(ArgType):
435     flag = ('    if (%(default)spyg_flags_get_value(%(typecode)s, py_%(name)s, (gpointer)&%(name)s))\n'
436             '        return NULL;\n')
437     def __init__(self, flagname, typecode):
438         self.flagname = flagname
439         self.typecode = typecode
440     def write_param(self, ptype, pname, pdflt, pnull, info):
441         if pdflt:
442             info.varlist.add(self.flagname, pname + ' = ' + pdflt)
443             default = "py_%s && " % (pname,)
444         else:
445             info.varlist.add(self.flagname, pname)
446             default = ""
447         info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
448         info.codebefore.append(self.flag % {'default':default,
449                                             'typecode':self.typecode,
450                                             'name':pname})
451         info.arglist.append(pname)
452         info.add_parselist('O', ['&py_' + pname], [pname])
453     def write_return(self, ptype, ownsreturn, info):
454         info.varlist.add('guint', 'ret')
455         info.codeafter.append('    return pyg_flags_from_gtype(%s, ret);' % self.typecode)
456
457 class ObjectArg(ArgType):
458     # should change these checks to more typesafe versions that check
459     # a little further down in the class heirachy.
460     nulldflt = ('    if ((PyObject *)py_%(name)s == Py_None)\n'
461                 '        %(name)s = NULL;\n'
462                 '    else if (py_%(name)s && pygobject_check(py_%(name)s, &Py%(type)s_Type))\n'
463                 '        %(name)s = %(cast)s(py_%(name)s->obj);\n'
464                 '    else if (py_%(name)s) {\n'
465                 '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
466                 '        return NULL;\n'
467                 '    }\n')
468     null = ('    if (py_%(name)s && pygobject_check(py_%(name)s, &Py%(type)s_Type))\n'
469             '        %(name)s = %(cast)s(py_%(name)s->obj);\n'
470             '    else if ((PyObject *)py_%(name)s != Py_None) {\n'
471             '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
472             '        return NULL;\n'
473             '    }\n')
474     dflt = '    if (py_%(name)s)\n' \
475            '        %(name)s = %(cast)s(py_%(name)s->obj);\n'
476     def __init__(self, objname, parent, typecode):
477         self.objname = objname
478         self.cast = string.replace(typecode, '_TYPE_', '_', 1)
479         self.parent = parent
480     def write_param(self, ptype, pname, pdflt, pnull, info):
481         if pnull:
482             if pdflt:
483                 info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
484                 info.varlist.add('PyGObject', '*py_' + pname + ' = NULL')
485                 info.codebefore.append(self.nulldflt % {'name':pname,
486                                                         'cast':self.cast,
487                                                         'type':self.objname})
488             else:
489                 info.varlist.add(self.objname, '*' + pname + ' = NULL')
490                 info.varlist.add('PyGObject', '*py_' + pname)
491                 info.codebefore.append(self.null % {'name':pname,
492                                                     'cast':self.cast,
493                                                     'type':self.objname})
494             if ptype.endswith('*'):
495                 typename = ptype[:-1]
496                 try:
497                     const, typename = typename.split('const-')
498                 except ValueError:
499                     const = ''
500                 if typename != ptype:
501                     info.arglist.append('(%s *) %s' % (ptype[:-1], pname))
502                 else:
503                     info.arglist.append(pname)
504
505             info.add_parselist('O', ['&py_' + pname], [pname])
506         else:
507             if pdflt:
508                 info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
509                 info.varlist.add('PyGObject', '*py_' + pname + ' = NULL')
510                 info.codebefore.append(self.dflt % {'name':pname,
511                                                     'cast':self.cast})
512                 info.arglist.append(pname)
513                 info.add_parselist('O!', ['&Py%s_Type' % self.objname,
514                                          '&py_' + pname], [pname])
515             else:
516                 info.varlist.add('PyGObject', '*' + pname)
517                 info.arglist.append('%s(%s->obj)' % (self.cast, pname))
518                 info.add_parselist('O!', ['&Py%s_Type' % self.objname,
519                                           '&' + pname], [pname])
520     def write_return(self, ptype, ownsreturn, info):
521         if ptype.endswith('*'):
522             typename = ptype[:-1]
523             try:
524                 const, typename = typename.split('const-')
525             except ValueError:
526                 const = ''
527         info.varlist.add(typename, '*ret')
528         if ownsreturn:
529             info.varlist.add('PyObject', '*py_ret')
530             info.codeafter.append('    py_ret = pygobject_new((GObject *)ret);\n'
531                                   '    if (ret != NULL)\n'
532                                   '        g_object_unref(ret);\n'
533                                   '    return py_ret;')
534         else:
535             info.codeafter.append('    /* pygobject_new handles NULL checking */\n' +
536                                   '    return pygobject_new((GObject *)ret);')
537
538 class BoxedArg(ArgType):
539     # haven't done support for default args.  Is it needed?
540     check = ('    if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n'
541              '        %(name)s = pyg_boxed_get(py_%(name)s, %(typename)s);\n'
542              '    else {\n'
543              '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s");\n'
544              '        return NULL;\n'
545              '    }\n')
546     null = ('    if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n'
547             '        %(name)s = pyg_boxed_get(py_%(name)s, %(typename)s);\n'
548             '    else if (py_%(name)s != Py_None) {\n'
549             '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s or None");\n'
550             '        return NULL;\n'
551             '    }\n')
552     def __init__(self, ptype, typecode):
553         self.typename = ptype
554         self.typecode = typecode
555     def write_param(self, ptype, pname, pdflt, pnull, info):
556         if pnull:
557             info.varlist.add(self.typename, '*' + pname + ' = NULL')
558             info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
559             info.codebefore.append(self.null % {'name':  pname,
560                                                 'typename': self.typename,
561                                                 'typecode': self.typecode})
562         else:
563             info.varlist.add(self.typename, '*' + pname + ' = NULL')
564             info.varlist.add('PyObject', '*py_' + pname)
565             info.codebefore.append(self.check % {'name':  pname,
566                                                  'typename': self.typename,
567                                                  'typecode': self.typecode})
568         if ptype[-1] == '*':
569             typename = ptype[:-1]
570             if typename[:6] == 'const-': typename = typename[6:]
571             if typename != self.typename:
572                 info.arglist.append('(%s *)%s' % (ptype[:-1], pname))
573             else:
574                 info.arglist.append(pname)
575         else:
576             info.arglist.append(pname)
577         info.add_parselist('O', ['&py_' + pname], [pname])
578     ret_tmpl = '    /* pyg_boxed_new handles NULL checking */\n' \
579                '    return pyg_boxed_new(%(typecode)s, %(ret)s, %(copy)s, TRUE);'
580     def write_return(self, ptype, ownsreturn, info):
581         if ptype[-1] == '*':
582             decl_type = self.typename
583             ret = 'ret'
584             if ptype[:6] == 'const-':
585                 decl_type = 'const ' + self.typename
586                 ret = '(%s*) ret' % (self.typename,)
587             info.varlist.add(decl_type, '*ret')
588         else:
589             info.varlist.add(self.typename, 'ret')
590             ret = '&ret'
591             ownsreturn = 0 # of course it can't own a ref to a local var ...
592         info.codeafter.append(self.ret_tmpl %
593                               { 'typecode': self.typecode,
594                                 'ret': ret,
595                                 'copy': ownsreturn and 'FALSE' or 'TRUE'})
596
597 class CustomBoxedArg(ArgType):
598     # haven't done support for default args.  Is it needed?
599     null = ('    if (%(check)s(py_%(name)s))\n'
600             '        %(name)s = %(get)s(py_%(name)s);\n'
601             '    else if (py_%(name)s != Py_None) {\n'
602             '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
603             '        return NULL;\n'
604             '    }\n')
605     def __init__(self, ptype, pytype, getter, new):
606         self.pytype = pytype
607         self.getter = getter
608         self.checker = 'Py' + ptype + '_Check'
609         self.new = new
610     def write_param(self, ptype, pname, pdflt, pnull, info):
611         if pnull:
612             info.varlist.add(ptype[:-1], '*' + pname + ' = NULL')
613             info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
614             info.codebefore.append(self.null % {'name':  pname,
615                                                 'get':   self.getter,
616                                                 'check': self.checker,
617                                                 'type':  ptype[:-1]})
618             info.arglist.append(pname)
619             info.add_parselist('O', ['&py_' + pname], [pname])
620         else:
621             info.varlist.add('PyObject', '*' + pname)
622             info.arglist.append(self.getter + '(' + pname + ')')
623             info.add_parselist('O!', ['&' + self.pytype, '&' + pname], [pname])
624     def write_return(self, ptype, ownsreturn, info):
625         info.varlist.add(ptype[:-1], '*ret')
626         info.codeafter.append('    if (ret)\n' +
627                               '        return ' + self.new + '(ret);\n' +
628                               '    Py_INCREF(Py_None);\n' +
629                               '    return Py_None;')
630
631 class PointerArg(ArgType):
632     # haven't done support for default args.  Is it needed?
633     check = ('    if (pyg_pointer_check(py_%(name)s, %(typecode)s))\n'
634              '        %(name)s = pyg_pointer_get(py_%(name)s, %(typename)s);\n'
635              '    else {\n'
636              '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s");\n'
637              '        return NULL;\n'
638              '    }\n')
639     null = ('    if (pyg_pointer_check(py_%(name)s, %(typecode)s))\n'
640             '        %(name)s = pyg_pointer_get(py_%(name)s, %(typename)s);\n'
641             '    else if (py_%(name)s != Py_None) {\n'
642             '        PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s or None");\n'
643             '        return NULL;\n'
644             '    }\n')
645     def __init__(self, ptype, typecode):
646         self.typename = ptype
647         self.typecode = typecode
648     def write_param(self, ptype, pname, pdflt, pnull, info):
649         if pnull:
650             info.varlist.add(self.typename, '*' + pname + ' = NULL')
651             info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
652             info.codebefore.append(self.null % {'name':  pname,
653                                                 'typename': self.typename,
654                                                 'typecode': self.typecode})
655         else:
656             info.varlist.add(self.typename, '*' + pname + ' = NULL')
657             info.varlist.add('PyObject', '*py_' + pname)
658             info.codebefore.append(self.check % {'name':  pname,
659                                                  'typename': self.typename,
660                                                  'typecode': self.typecode})
661         info.arglist.append(pname)
662         info.add_parselist('O', ['&py_' + pname], [pname])
663     def write_return(self, ptype, ownsreturn, info):
664         if ptype[-1] == '*':
665             info.varlist.add(self.typename, '*ret')
666             info.codeafter.append('    /* pyg_pointer_new handles NULL checking */\n' +
667                                   '    return pyg_pointer_new(' + self.typecode + ', ret);')
668         else:
669             info.varlist.add(self.typename, 'ret')
670             info.codeafter.append('    /* pyg_pointer_new handles NULL checking */\n' +
671                                   '    return pyg_pointer_new(' + self.typecode + ', &ret);')
672
673 class AtomArg(IntArg):
674     dflt = '    if (py_%(name)s) {\n' \
675            '        %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n' \
676            '        if (PyErr_Occurred())\n' \
677            '            return NULL;\n' \
678            '    }\n'
679     atom = ('    %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n'
680             '    if (PyErr_Occurred())\n'
681             '        return NULL;\n')
682     def write_param(self, ptype, pname, pdflt, pnull, info):
683         if pdflt:
684             info.varlist.add('GdkAtom', pname + ' = ' + pdflt)
685             info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
686             info.codebefore.append(self.dflt % {'name': pname})
687         else:
688             info.varlist.add('GdkAtom', pname)
689             info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
690             info.codebefore.append(self.atom % {'name': pname})
691         info.arglist.append(pname)
692         info.add_parselist('O', ['&py_' + pname], [pname])
693     def write_return(self, ptype, ownsreturn, info):
694         info.varlist.add('GdkAtom', 'ret')
695         info.varlist.add('PyObject *', 'py_ret')
696         info.varlist.add('gchar *', 'name')
697         info.codeafter.append('    name = gdk_atom_name(ret);\n'
698                               '    py_ret = PyString_FromString(name);\n'
699                               '    g_free(name);\n'
700                               '    return py_ret;')
701
702 class GTypeArg(ArgType):
703     gtype = ('    if ((%(name)s = pyg_type_from_object(py_%(name)s)) == 0)\n'
704              '        return NULL;\n')
705     def write_param(self, ptype, pname, pdflt, pnull, info):
706         info.varlist.add('GType', pname)
707         info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
708         info.codebefore.append(self.gtype % {'name': pname})
709         info.arglist.append(pname)
710         info.add_parselist('O', ['&py_' + pname], [pname])
711     def write_return(self, ptype, ownsreturn, info):
712         info.varlist.add('GType', 'ret')
713         info.codeafter.append('    return pyg_type_wrapper_new(ret);')
714
715 # simple GError handler.
716 class GErrorArg(ArgType):
717     handleerror = ('    if (pyg_error_check(&%(name)s))\n'
718                    '        return NULL;\n')
719     def write_param(self, ptype, pname, pdflt, pnull, info):
720         info.varlist.add('GError', '*' + pname + ' = NULL')
721         info.arglist.append('&' + pname)
722         info.codeafter.append(self.handleerror % { 'name': pname })
723
724 class GtkTreePathArg(ArgType):
725     # haven't done support for default args.  Is it needed?
726     normal = ('    %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n'
727               '    if (!%(name)s) {\n'
728               '        PyErr_SetString(PyExc_TypeError, "could not convert %(name)s to a GtkTreePath");\n'
729               '        return NULL;\n'
730               '    }\n')
731     null = ('    if (py_%(name)s != Py_None) {\n'
732             '        %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n'
733             '        if (!%(name)s) {\n'
734             '            PyErr_SetString(PyExc_TypeError, "could not convert %(name)s to a GtkTreePath");\n'
735             '            return NULL;\n'
736             '        }\n'
737             '    }\n')
738     freepath = ('    if (%(name)s)\n'
739                 '        gtk_tree_path_free(%(name)s);\n')
740     def __init__(self):
741         pass
742     def write_param(self, ptype, pname, pdflt, pnull, info):
743         if pnull:
744             info.varlist.add('GtkTreePath', '*' + pname + ' = NULL')
745             info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
746             info.codebefore.append(self.null % {'name':  pname})
747             info.arglist.append(pname)
748             info.add_parselist('O', ['&py_' + pname], [pname])
749         else:
750             info.varlist.add('GtkTreePath', '*' + pname)
751             info.varlist.add('PyObject', '*py_' + pname)
752             info.codebefore.append(self.normal % {'name': pname})
753             info.arglist.append(pname)
754             info.add_parselist('O', ['&py_' + pname], [pname])
755         info.codeafter.append(self.freepath % {'name': pname})
756     def write_return(self, ptype, ownsreturn, info):
757         info.varlist.add('GtkTreePath', '*ret')
758         if ownsreturn:
759             info.codeafter.append('    if (ret) {\n'
760                                   '        PyObject *py_ret = pygtk_tree_path_to_pyobject(ret);\n'
761                                   '        gtk_tree_path_free(ret);\n'
762                                   '        return py_ret;\n'
763                                   '    }\n'
764                                   '    Py_INCREF(Py_None);\n'
765                                   '    return Py_None;')
766         else:
767             info.codeafter.append('    if (ret) {\n'
768                                   '        PyObject *py_ret = pygtk_tree_path_to_pyobject(ret);\n'
769                                   '        return py_ret;\n'
770                                   '    }\n'
771                                   '    Py_INCREF(Py_None);\n'
772                                   '    return Py_None;')
773
774 class GdkRectanglePtrArg(ArgType):
775     normal = ('    if (!pygdk_rectangle_from_pyobject(py_%(name)s, &%(name)s))\n'
776               '        return NULL;\n')
777     null =   ('    if (py_%(name)s == Py_None)\n'
778               '        %(name)s = NULL;\n'
779               '    else if (pygdk_rectangle_from_pyobject(py_%(name)s, &%(name)s_rect))\n'
780               '        %(name)s = &%(name)s_rect;\n'
781               '    else\n'
782               '            return NULL;\n')
783     def write_param(self, ptype, pname, pdflt, pnull, info):
784         if pnull:
785             info.varlist.add('GdkRectangle', pname + '_rect = { 0, 0, 0, 0 }')
786             info.varlist.add('GdkRectangle', '*' + pname)
787             info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
788             info.add_parselist('O', ['&py_' + pname], [pname])
789             info.arglist.append(pname)
790             info.codebefore.append(self.null % {'name':  pname})
791         else:
792             info.varlist.add('GdkRectangle', pname + ' = { 0, 0, 0, 0 }')
793             info.varlist.add('PyObject', '*py_' + pname)
794             info.add_parselist('O', ['&py_' + pname], [pname])
795             info.arglist.append('&' + pname)
796             info.codebefore.append(self.normal % {'name':  pname})
797
798 class GdkRectangleArg(ArgType):
799     def write_return(self, ptype, ownsreturn, info):
800         info.varlist.add('GdkRectangle', 'ret')
801         info.codeafter.append('    return pyg_boxed_new(GDK_TYPE_RECTANGLE, &ret, TRUE, TRUE);')
802
803 class PyObjectArg(ArgType):
804     def write_param(self, ptype, pname, pdflt, pnull, info):
805         info.varlist.add('PyObject', '*' + pname)
806         info.add_parselist('O', ['&' + pname], [pname])
807         info.arglist.append(pname)
808     def write_return(self, ptype, ownsreturn, info):
809         info.varlist.add("PyObject", "*ret")
810         if ownsreturn:
811             info.codeafter.append('    if (ret) {\n'
812                                   '       return ret;\n'
813                                   '    }\n'
814                                   '    Py_INCREF(Py_None);\n'
815                                   '    return Py_None;')
816         else:
817             info.codeafter.append('    if (!ret) ret = Py_None;\n'
818                                   '    Py_INCREF(ret);\n'
819                                   '    return ret;')
820
821 class CairoArg(ArgType):
822     def write_param(self, ptype, pname, pdflt, pnull, info):
823         info.varlist.add('PycairoContext', '*' + pname)
824         info.add_parselist('O!', ['&PycairoContext_Type', '&' + pname], [pname])
825         info.arglist.append('%s->ctx' % pname)
826     def write_return(self, ptype, ownsreturn, info):
827         info.varlist.add("cairo_t", "*ret")
828         if ownsreturn:
829             info.codeafter.append('    return PycairoContext_FromContext(ret, NULL, NULL);')
830         else:
831             info.codeafter.append('    cairo_reference(ret);\n'
832                                   '    return PycairoContext_FromContext(ret, NULL, NULL);')
833
834
835 class ArgMatcher:
836     def __init__(self):
837         self.argtypes = {}
838         self.reverse_argtypes = {}
839         self.reverse_rettypes = {}
840
841     def register(self, ptype, handler, overwrite=False):
842         if not overwrite and ptype in self.argtypes:
843             return
844         self.argtypes[ptype] = handler
845     def register_reverse(self, ptype, handler):
846         self.reverse_argtypes[ptype] = handler
847     def register_reverse_ret(self, ptype, handler):
848         self.reverse_rettypes[ptype] = handler
849
850     def register_enum(self, ptype, typecode):
851         if typecode is None:
852             self.register(ptype, IntArg())
853         else:
854             self.register(ptype, EnumArg(ptype, typecode))
855     def register_flag(self, ptype, typecode):
856         if typecode is None:
857             self.register(ptype, IntArg())
858         else:
859             self.register(ptype, FlagsArg(ptype, typecode))
860     def register_object(self, ptype, parent, typecode):
861         oa = ObjectArg(ptype, parent, typecode)
862         self.register(ptype, oa)  # in case I forget the * in the .defs
863         self.register(ptype+'*', oa)
864         self.register('const-'+ptype+'*', oa)
865         if ptype == 'GdkPixmap':
866             # hack to handle GdkBitmap synonym.
867             self.register('GdkBitmap', oa)
868             self.register('GdkBitmap*', oa)
869     def register_boxed(self, ptype, typecode):
870         if self.argtypes.has_key(ptype): return
871         arg = BoxedArg(ptype, typecode)
872         self.register(ptype, arg)
873         self.register(ptype+'*', arg)
874         self.register('const-'+ptype+'*', arg)
875     def register_custom_boxed(self, ptype, pytype, getter, new):
876         arg = CustomBoxedArg(ptype, pytype, getter, new)
877         self.register(ptype+'*', arg)
878         self.register('const-'+ptype+'*', arg)
879     def register_pointer(self, ptype, typecode):
880         arg = PointerArg(ptype, typecode)
881         self.register(ptype, arg)
882         self.register(ptype+'*', arg)
883         self.register('const-'+ptype+'*', arg)
884
885     def get(self, ptype):
886         try:
887             return self.argtypes[ptype]
888         except KeyError:
889             if ptype[:8] == 'GdkEvent' and ptype[-1] == '*':
890                 return self.argtypes['GdkEvent*']
891             raise ArgTypeNotFoundError("No ArgType for %s" % (ptype,))
892     def _get_reverse_common(self, ptype, registry):
893         props = dict(c_type=ptype)
894         try:
895             return registry[ptype], props
896         except KeyError:
897             try:
898                 handler = self.argtypes[ptype]
899             except KeyError:
900                 if ptype.startswith('GdkEvent') and ptype.endswith('*'):
901                     handler = self.argtypes['GdkEvent*']
902                 else:
903                     raise ArgTypeNotFoundError("No ArgType for %s" % (ptype,))
904             if isinstance(handler, ObjectArg):
905                 return registry['GObject*'], props
906             elif isinstance(handler, EnumArg):
907                 props['typecode'] = handler.typecode
908                 props['enumname'] = handler.enumname
909                 return registry['GEnum'], props
910             elif isinstance(handler, FlagsArg):
911                 props['typecode'] = handler.typecode
912                 props['flagname'] = handler.flagname
913                 return registry['GFlags'], props
914             elif isinstance(handler, BoxedArg):
915                 props['typecode'] = handler.typecode
916                 props['typename'] = handler.typename
917                 return registry['GBoxed'], props
918             else:
919                 raise ArgTypeNotFoundError("No ArgType for %s" % (ptype,))
920
921     def get_reverse(self, ptype):
922         return self._get_reverse_common(ptype, self.reverse_argtypes)
923
924     def get_reverse_ret(self, ptype):
925         ret, props = self._get_reverse_common(ptype, self.reverse_rettypes)
926         if hasattr(ptype, 'optional') and ptype.optional:
927             if ret.supports_optional:
928                 props['optional'] = True
929             else:
930                 raise ArgTypeNotFoundError("Unsupported 'optional' for %s"
931                                            % (ptype,))
932         return ret, props
933
934     def object_is_a(self, otype, parent):
935         if otype == None: return 0
936         if otype == parent: return 1
937         if not self.argtypes.has_key(otype): return 0
938         return self.object_is_a(self.get(otype).parent, parent)
939
940 matcher = ArgMatcher()
941
942 arg = NoneArg()
943 matcher.register(None, arg)
944 matcher.register('none', arg)
945
946 arg = StringArg()
947 matcher.register('char*', arg)
948 matcher.register('gchar*', arg)
949 matcher.register('const-char*', arg)
950 matcher.register('char-const*', arg)
951 matcher.register('const-gchar*', arg)
952 matcher.register('gchar-const*', arg)
953 matcher.register('string', arg)
954 matcher.register('static_string', arg)
955
956 arg = UCharArg()
957 matcher.register('unsigned-char*', arg)
958 matcher.register('const-guchar*', arg)
959 matcher.register('const-guint8*', arg)
960 matcher.register('guchar*', arg)
961
962 arg = CharArg()
963 matcher.register('char', arg)
964 matcher.register('gchar', arg)
965 matcher.register('guchar', arg)
966
967 arg = GUniCharArg()
968 matcher.register('gunichar', arg)
969
970 arg = IntArg()
971 matcher.register('int', arg)
972 matcher.register('gint', arg)
973 matcher.register('short', arg)
974 matcher.register('gshort', arg)
975 matcher.register('gushort', arg)
976 matcher.register('gsize', SizeArg())
977 matcher.register('gssize', SSizeArg())
978 matcher.register('guint8', arg)
979 matcher.register('gint8', arg)
980 matcher.register('guint16', arg)
981 matcher.register('gint16', arg)
982 matcher.register('gint32', arg)
983 matcher.register('GTime', arg)
984 matcher.register('GSeekType', arg) # Hack, but we have no python wrapper
985
986 arg = LongArg()
987 matcher.register('long', arg)
988 matcher.register('glong', arg)
989
990 arg = UIntArg()
991 matcher.register('guint', arg)
992
993 arg = BoolArg()
994 matcher.register('gboolean', arg)
995
996 arg = TimeTArg()
997 matcher.register('time_t', arg)
998
999 matcher.register('guint32', UInt32Arg())
1000
1001 arg = ULongArg()
1002 matcher.register('gulong', arg)
1003
1004 arg = Int64Arg()
1005 matcher.register('gint64', arg)
1006 matcher.register('long-long', arg)
1007 matcher.register('goffset', arg)
1008
1009 arg = UInt64Arg()
1010 matcher.register('guint64', arg)
1011 matcher.register('unsigned-long-long', arg)
1012
1013 arg = DoubleArg()
1014 matcher.register('double', arg)
1015 matcher.register('gdouble', arg)
1016 matcher.register('float', arg)
1017 matcher.register('gfloat', arg)
1018
1019 arg = FileArg()
1020 matcher.register('FILE*', arg)
1021
1022 # enums, flags, objects
1023
1024 matcher.register('GdkAtom', AtomArg())
1025
1026 matcher.register('GType', GTypeArg())
1027 matcher.register('GtkType', GTypeArg())
1028
1029 matcher.register('GError**', GErrorArg())
1030 matcher.register('GtkTreePath*', GtkTreePathArg())
1031 matcher.register('GdkRectangle*', GdkRectanglePtrArg())
1032 matcher.register('GtkAllocation*', GdkRectanglePtrArg())
1033 matcher.register('GdkRectangle', GdkRectangleArg())
1034 matcher.register('PyObject*', PyObjectArg())
1035
1036 matcher.register('GdkNativeWindow', ULongArg())
1037
1038 matcher.register_object('GObject', None, 'G_TYPE_OBJECT')
1039
1040 del arg
1041
1042 matcher.register('cairo_t*', CairoArg())
1043 matcher.register_boxed("GClosure", "G_TYPE_CLOSURE")