mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 04:46:13 +00:00
Add python bindings.
This commit is contained in:
parent
7bab61a10b
commit
3f7bd92022
27 changed files with 6908 additions and 1 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
*.[oa]
|
*.[oa]
|
||||||
|
*.pyc
|
||||||
*.gcda
|
*.gcda
|
||||||
*.gcno
|
*.gcno
|
||||||
*.la
|
*.la
|
||||||
|
@ -28,3 +29,5 @@ libtool
|
||||||
ltmain.sh
|
ltmain.sh
|
||||||
missing
|
missing
|
||||||
stamp-h1
|
stamp-h1
|
||||||
|
bindings/python/rtspserver.c
|
||||||
|
tags
|
||||||
|
|
|
@ -2,6 +2,7 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
gst \
|
gst \
|
||||||
|
bindings \
|
||||||
m4 \
|
m4 \
|
||||||
common \
|
common \
|
||||||
pkgconfig \
|
pkgconfig \
|
||||||
|
|
66
acinclude.m4
Normal file
66
acinclude.m4
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
## this one is commonly used with AM_PATH_PYTHONDIR ...
|
||||||
|
dnl AM_CHECK_PYMOD(MODNAME [,SYMBOL [,ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]]])
|
||||||
|
dnl Check if a module containing a given symbol is visible to python.
|
||||||
|
AC_DEFUN([AM_CHECK_PYMOD],
|
||||||
|
[AC_REQUIRE([AM_PATH_PYTHON])
|
||||||
|
py_mod_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'`
|
||||||
|
AC_MSG_CHECKING(for ifelse([$2],[],,[$2 in ])python module $1)
|
||||||
|
AC_CACHE_VAL(py_cv_mod_$py_mod_var, [
|
||||||
|
ifelse([$2],[], [prog="
|
||||||
|
import sys
|
||||||
|
try:
|
||||||
|
import $1
|
||||||
|
except ImportError:
|
||||||
|
sys.exit(1)
|
||||||
|
except:
|
||||||
|
sys.exit(0)
|
||||||
|
sys.exit(0)"], [prog="
|
||||||
|
import $1
|
||||||
|
$1.$2"])
|
||||||
|
if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC
|
||||||
|
then
|
||||||
|
eval "py_cv_mod_$py_mod_var=yes"
|
||||||
|
else
|
||||||
|
eval "py_cv_mod_$py_mod_var=no"
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
py_val=`eval "echo \`echo '$py_cv_mod_'$py_mod_var\`"`
|
||||||
|
if test "x$py_val" != xno; then
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
ifelse([$3], [],, [$3
|
||||||
|
])dnl
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
ifelse([$4], [],, [$4
|
||||||
|
])dnl
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl a macro to check for ability to create python extensions
|
||||||
|
dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE])
|
||||||
|
dnl function also defines PYTHON_INCLUDES
|
||||||
|
AC_DEFUN([AM_CHECK_PYTHON_HEADERS],
|
||||||
|
[AC_REQUIRE([AM_PATH_PYTHON])
|
||||||
|
AC_MSG_CHECKING(for headers required to compile python extensions)
|
||||||
|
dnl deduce PYTHON_INCLUDES
|
||||||
|
py_prefix=`$PYTHON -c "import sys; print sys.prefix"`
|
||||||
|
py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"`
|
||||||
|
if $PYTHON-config --help 2>/dev/null; then
|
||||||
|
PYTHON_INCLUDES=`$PYTHON-config --includes 2>/dev/null`
|
||||||
|
else
|
||||||
|
PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}"
|
||||||
|
if test "$py_prefix" != "$py_exec_prefix"; then
|
||||||
|
PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AC_SUBST(PYTHON_INCLUDES)
|
||||||
|
dnl check if the headers exist:
|
||||||
|
save_CPPFLAGS="$CPPFLAGS"
|
||||||
|
CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES"
|
||||||
|
AC_TRY_CPP([#include <Python.h>],dnl
|
||||||
|
[AC_MSG_RESULT(found)
|
||||||
|
$1],dnl
|
||||||
|
[AC_MSG_RESULT(not found)
|
||||||
|
$2])
|
||||||
|
CPPFLAGS="$save_CPPFLAGS"
|
||||||
|
])
|
45
bindings/python/Makefile.am
Normal file
45
bindings/python/Makefile.am
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
SUBDIRS = codegen
|
||||||
|
pkgpyexecdir = $(pyexecdir)/gst-$(GST_MAJORMINOR)/gst
|
||||||
|
|
||||||
|
# we install everything in pyexecdir; otherwise you end up with a mess for
|
||||||
|
# multilib
|
||||||
|
pygstrtspserverdir = $(pkgpyexecdir)
|
||||||
|
pygstrtspserver_PYTHON =
|
||||||
|
|
||||||
|
pygstrtspserverexecdir = $(pkgpyexecdir)
|
||||||
|
pygstrtspserverexec_LTLIBRARIES = rtspserver.la
|
||||||
|
|
||||||
|
DEFS = rtspserver-types.defs rtspserver.defs
|
||||||
|
defs_DATA = $(DEFS)
|
||||||
|
defsdir = $(pkgdatadir)/$(GST_MAJORMINOR)/defs
|
||||||
|
OVERRIDES = rtspserver.override
|
||||||
|
|
||||||
|
INCLUDES = $(PYTHON_INCLUDES)
|
||||||
|
|
||||||
|
rtspserver_la_CFLAGS = -I$(top_srcdir)/src \
|
||||||
|
$(PYGOBJECT_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
|
||||||
|
rtspserver_la_LDFLAGS = -export-symbols-regex "^(initrtspserver|_PyGObject_API).*" \
|
||||||
|
-module -avoid-version $(GST_PLUGIN_LDFLAGS)
|
||||||
|
rtspserver_la_LIBADD = $(top_builddir)/src/libgst-rtsp-server.a \
|
||||||
|
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
|
||||||
|
-lgstrtp-@GST_MAJORMINOR@ -lgstrtsp-@GST_MAJORMINOR@ \
|
||||||
|
-lgstsdp-@GST_MAJORMINOR@ $(GST_LIBS) $(LIBM)
|
||||||
|
rtspserver_la_SOURCES = rtspservermodule.c
|
||||||
|
nodist_rtspserver_la_SOURCES = rtspserver.c
|
||||||
|
|
||||||
|
EXTRA_DIST = $(defs_DATA) $(OVERRIDES) arg-types.py
|
||||||
|
|
||||||
|
CLEANFILES = rtspserver.c
|
||||||
|
|
||||||
|
rtspserver.c: $(DEFS) $(OVERRIDES) arg-types.py
|
||||||
|
|
||||||
|
.defs.c:
|
||||||
|
($(PYTHON) $(srcdir)/codegen/codegen.py \
|
||||||
|
--load-types $(srcdir)/arg-types.py \
|
||||||
|
--register $(srcdir)/rtspserver-types.defs \
|
||||||
|
--override $(srcdir)/$*.override \
|
||||||
|
--extendpath $(top_builddir)/gst/ \
|
||||||
|
--extendpath $(srcdir)/ \
|
||||||
|
--prefix pygst_rtsp_server $<) > gen-$*.c \
|
||||||
|
&& cp gen-$*.c $*.c \
|
||||||
|
&& rm -f gen-$*.c
|
376
bindings/python/arg-types.py
Normal file
376
bindings/python/arg-types.py
Normal file
|
@ -0,0 +1,376 @@
|
||||||
|
# -*- Mode: Python -*-
|
||||||
|
# vi:si:et:sw=4:sts=4:ts=4
|
||||||
|
#
|
||||||
|
# gst-python
|
||||||
|
# Copyright (C) 2002 David I. Lehn
|
||||||
|
# 2004 Johan Dahlin
|
||||||
|
#
|
||||||
|
# This library is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Library General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This library is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# Library General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Library General Public
|
||||||
|
# License along with this library; if not, write to the
|
||||||
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
# Boston, MA 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# Author: David I. Lehn <dlehn@users.sourceforge.net>
|
||||||
|
|
||||||
|
from argtypes import UInt64Arg, Int64Arg, PointerArg, ArgMatcher, ArgType, matcher
|
||||||
|
from reversewrapper import Parameter, ReturnType, GBoxedParam, GBoxedReturn, IntParam, IntReturn
|
||||||
|
|
||||||
|
class XmlNodeArg(ArgType):
|
||||||
|
"""libxml2 node generator"""
|
||||||
|
|
||||||
|
names = {"xobj":"xmlNode",
|
||||||
|
"xptr":"xmlNodePtr",
|
||||||
|
"xwrap":"libxml_xmlNodePtrWrap"}
|
||||||
|
|
||||||
|
parm = (' if(xml == NULL) return NULL;\n'
|
||||||
|
' xobj = PyObject_GetAttrString(xml, "%(xobj)s");\n'
|
||||||
|
' if(!PyObject_IsInstance(py%(name)s, xobj)) {\n'
|
||||||
|
' PyErr_Clear();\n'
|
||||||
|
' PyErr_SetString(PyExc_RuntimeError,"%(name)s is not a %(xobj)s instance");\n'
|
||||||
|
' Py_DECREF(xobj);Py_DECREF(xml);\n'
|
||||||
|
' return NULL;\n'
|
||||||
|
' }\n'
|
||||||
|
' o = PyObject_GetAttrString(py%(name)s, "_o");\n'
|
||||||
|
' %(name)s = PyCObject_AsVoidPtr(o);\n')
|
||||||
|
parmp = (' Py_DECREF(o); Py_DECREF(xobj);Py_DECREF(xml);\n')
|
||||||
|
|
||||||
|
ret = (' if(xml == NULL) return NULL;\n')
|
||||||
|
retp = (' xargs = PyTuple_New(1);\n'
|
||||||
|
' xobj = PyObject_GetAttrString(xml, "%(xobj)s");\n'
|
||||||
|
' o = %(xwrap)s(ret);\n'
|
||||||
|
' PyTuple_SetItem(xargs, 0, o);\n'
|
||||||
|
' return PyInstance_New(xobj, xargs, PyDict_New());\n')
|
||||||
|
|
||||||
|
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||||
|
info.varlist.add('PyObject', '*xml = _gst_get_libxml2_module()')
|
||||||
|
info.varlist.add('PyObject', '*o')
|
||||||
|
info.varlist.add('PyObject', '*xobj')
|
||||||
|
info.varlist.add('PyObject', '*py' + pname)
|
||||||
|
info.varlist.add(self.names["xptr"], pname)
|
||||||
|
#if pnull:
|
||||||
|
info.add_parselist('O', ['&py'+pname], [pname])
|
||||||
|
info.arglist.append(pname)
|
||||||
|
self.names["name"] = pname
|
||||||
|
info.codebefore.append(self.parm % self.names)
|
||||||
|
info.codeafter.append(self.parmp % self.names);
|
||||||
|
def write_return(self, ptype, ownsreturn, info):
|
||||||
|
info.varlist.add('PyObject', '*xml = _gst_get_libxml2_module()')
|
||||||
|
info.varlist.add('PyObject', '*xargs')
|
||||||
|
info.varlist.add('PyObject', '*xobj')
|
||||||
|
info.varlist.add('PyObject', '*o')
|
||||||
|
info.varlist.add(self.names["xptr"], 'ret')
|
||||||
|
info.codebefore.append(self.ret % self.names)
|
||||||
|
info.codeafter.append(self.retp % self.names)
|
||||||
|
|
||||||
|
class XmlDocArg(XmlNodeArg):
|
||||||
|
"""libxml2 doc generator"""
|
||||||
|
names = {"xobj":"xmlDoc",
|
||||||
|
"xptr":"xmlDocPtr",
|
||||||
|
"xwrap":"libxml_xmlDocPtrWrap"}
|
||||||
|
|
||||||
|
class GstCapsArg(ArgType):
|
||||||
|
"""GstCaps node generator"""
|
||||||
|
|
||||||
|
before = (' %(name)s = pygst_caps_from_pyobject (py_%(name)s, %(namecopy)s);\n'
|
||||||
|
' if (PyErr_Occurred())\n'
|
||||||
|
' return NULL;\n')
|
||||||
|
beforenull = (' if (py_%(name)s == Py_None || py_%(name)s == NULL)\n'
|
||||||
|
' %(name)s = NULL;\n'
|
||||||
|
' else\n'
|
||||||
|
' ' + before)
|
||||||
|
after = (' if (%(name)s && %(name)s_is_copy)\n'
|
||||||
|
' gst_caps_unref (%(name)s);\n')
|
||||||
|
|
||||||
|
def write_param(self, ptype, pname, pdflt, pnull, keeprefcount, info):
|
||||||
|
if ptype == 'const-GstCaps*':
|
||||||
|
self.write_const_param(pname, pdflt, pnull, info)
|
||||||
|
elif ptype == 'GstCaps*':
|
||||||
|
self.write_normal_param(pname, pdflt, pnull, info)
|
||||||
|
else:
|
||||||
|
raise RuntimeError, "write_param not implemented for %s" % ptype
|
||||||
|
|
||||||
|
def write_const_param(self, pname, pdflt, pnull, info):
|
||||||
|
if pdflt:
|
||||||
|
assert pdflt == 'NULL'
|
||||||
|
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
|
||||||
|
else:
|
||||||
|
info.varlist.add('PyObject', '*py_' + pname)
|
||||||
|
info.varlist.add('GstCaps', '*'+pname)
|
||||||
|
info.varlist.add('gboolean', pname+'_is_copy')
|
||||||
|
info.add_parselist('O', ['&py_'+pname], [pname])
|
||||||
|
info.arglist.append(pname)
|
||||||
|
if pnull:
|
||||||
|
info.codebefore.append (self.beforenull % { 'name' : pname, 'namecopy' : '&'+pname+'_is_copy' })
|
||||||
|
else:
|
||||||
|
info.codebefore.append (self.before % { 'name' : pname, 'namecopy' : '&'+pname+'_is_copy' })
|
||||||
|
info.codeafter.append (self.after % { 'name' : pname, 'namecopy' : '&'+pname+'_is_copy' })
|
||||||
|
|
||||||
|
def write_normal_param(self, pname, pdflt, pnull, info):
|
||||||
|
if pdflt:
|
||||||
|
assert pdflt == 'NULL'
|
||||||
|
info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
|
||||||
|
else:
|
||||||
|
info.varlist.add('PyObject', '*py_' + pname)
|
||||||
|
info.varlist.add('GstCaps', '*'+pname)
|
||||||
|
info.add_parselist('O', ['&py_'+pname], [pname])
|
||||||
|
info.arglist.append(pname)
|
||||||
|
if pnull:
|
||||||
|
info.codebefore.append (self.beforenull % { 'name' : pname, 'namecopy' : 'NULL' })
|
||||||
|
else:
|
||||||
|
info.codebefore.append (self.before % { 'name' : pname, 'namecopy' : 'NULL' })
|
||||||
|
|
||||||
|
def write_return(self, ptype, ownsreturn, info):
|
||||||
|
if ptype == 'GstCaps*':
|
||||||
|
info.varlist.add('GstCaps', '*ret')
|
||||||
|
copyval = 'FALSE'
|
||||||
|
elif ptype == 'const-GstCaps*':
|
||||||
|
info.varlist.add('const GstCaps', '*ret')
|
||||||
|
copyval = 'TRUE'
|
||||||
|
else:
|
||||||
|
raise RuntimeError, "write_return not implemented for %s" % ptype
|
||||||
|
info.codeafter.append(' return pyg_boxed_new (GST_TYPE_CAPS, ret, '+copyval+', TRUE);')
|
||||||
|
|
||||||
|
class GstIteratorArg(ArgType):
|
||||||
|
def write_return(self, ptype, ownsreturn, info):
|
||||||
|
info.varlist.add('GstIterator', '*ret')
|
||||||
|
info.codeafter.append(' return pygst_iterator_new(ret);')
|
||||||
|
|
||||||
|
class GstMiniObjectParam(Parameter):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'GstMiniObject *')
|
||||||
|
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("if (%s) {\n"
|
||||||
|
" py_%s = pygstminiobject_new((GstMiniObject *) %s);\n"
|
||||||
|
" gst_mini_object_unref ((GstMiniObject *) %s);\n"
|
||||||
|
"} else {\n"
|
||||||
|
" Py_INCREF(Py_None);\n"
|
||||||
|
" py_%s = Py_None;\n"
|
||||||
|
"}"
|
||||||
|
% (self.name, self.name, self.name, self.name, self.name)),
|
||||||
|
cleanup=("gst_mini_object_ref ((GstMiniObject *) %s);\nPy_DECREF(py_%s);" % (self.name, self.name)))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
matcher.register_reverse('GstMiniObject*', GstMiniObjectParam)
|
||||||
|
|
||||||
|
class GstMiniObjectReturn(ReturnType):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'GstMiniObject *')
|
||||||
|
|
||||||
|
def write_decl(self):
|
||||||
|
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
|
||||||
|
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return NULL;")
|
||||||
|
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.write_code("retval = (%s) pygstminiobject_get(py_retval);"
|
||||||
|
% self.get_c_type())
|
||||||
|
self.wrapper.write_code("gst_mini_object_ref((GstMiniObject *) retval);")
|
||||||
|
|
||||||
|
matcher.register_reverse_ret('GstMiniObject*', GstMiniObjectReturn)
|
||||||
|
|
||||||
|
class GstCapsParam(Parameter):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'GstCaps *')
|
||||||
|
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("if (%s)\n"
|
||||||
|
" py_%s = pyg_boxed_new (GST_TYPE_CAPS, %s, FALSE, TRUE);\n"
|
||||||
|
"else {\n"
|
||||||
|
" Py_INCREF(Py_None);\n"
|
||||||
|
" py_%s = Py_None;\n"
|
||||||
|
"}"
|
||||||
|
% (self.name, self.name, self.name, self.name)),
|
||||||
|
cleanup=("gst_caps_ref(%s);\nPy_DECREF(py_%s);" % (self.name, self.name)))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
matcher.register_reverse('GstCaps*', GstCapsParam)
|
||||||
|
|
||||||
|
class GstCapsReturn(ReturnType):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'GstCaps *')
|
||||||
|
|
||||||
|
def write_decl(self):
|
||||||
|
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
|
||||||
|
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return NULL;")
|
||||||
|
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.write_code("retval = (%s) pygst_caps_from_pyobject (py_retval, NULL);"
|
||||||
|
% self.get_c_type())
|
||||||
|
## self.wrapper.write_code("gst_mini_object_ref((GstMiniObject *) retval);")
|
||||||
|
|
||||||
|
matcher.register_reverse_ret('GstCaps*', GstCapsReturn)
|
||||||
|
|
||||||
|
|
||||||
|
class Int64Param(Parameter):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'gint64')
|
||||||
|
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("py_%s = PyLong_FromLongLong(%s);" %
|
||||||
|
(self.name, self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
class Int64Return(ReturnType):
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'gint64')
|
||||||
|
def write_decl(self):
|
||||||
|
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return -G_MAXINT;")
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.write_code(
|
||||||
|
code=None,
|
||||||
|
failure_expression="!PyLong_Check(py_retval)",
|
||||||
|
failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be an long");')
|
||||||
|
self.wrapper.write_code("retval = PyLong_AsLongLong(py_retval);")
|
||||||
|
|
||||||
|
class UInt64Param(Parameter):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'guint64')
|
||||||
|
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("py_%s = PyLong_FromUnsignedLongLong(%s);" %
|
||||||
|
(self.name, self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
class UInt64Return(ReturnType):
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'guint64')
|
||||||
|
def write_decl(self):
|
||||||
|
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return -G_MAXINT;")
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.write_code(
|
||||||
|
code=None,
|
||||||
|
failure_expression="!PyLong_Check(py_retval)",
|
||||||
|
failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be an long");')
|
||||||
|
self.wrapper.write_code("retval = PyLong_AsUnsignedLongLongMask(py_retval);")
|
||||||
|
|
||||||
|
class ULongParam(Parameter):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'gulong')
|
||||||
|
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("py_%s = PyLong_FromUnsignedLong(%s);" %
|
||||||
|
(self.name, self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
class ULongReturn(ReturnType):
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'gulong')
|
||||||
|
def write_decl(self):
|
||||||
|
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return -G_MAXINT;")
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.write_code(
|
||||||
|
code=None,
|
||||||
|
failure_expression="!PyLong_Check(py_retval)",
|
||||||
|
failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be an long");')
|
||||||
|
self.wrapper.write_code("retval = PyLong_AsUnsignedLongMask(py_retval);")
|
||||||
|
|
||||||
|
class ConstStringReturn(ReturnType):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return "const gchar *"
|
||||||
|
|
||||||
|
def write_decl(self):
|
||||||
|
self.wrapper.add_declaration("const gchar *retval;")
|
||||||
|
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return NULL;")
|
||||||
|
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.write_code(
|
||||||
|
code=None,
|
||||||
|
failure_expression="!PyString_Check(py_retval)",
|
||||||
|
failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a string");')
|
||||||
|
self.wrapper.write_code("retval = g_strdup(PyString_AsString(py_retval));")
|
||||||
|
|
||||||
|
class StringArrayArg(ArgType):
|
||||||
|
"""Arg type for NULL-terminated string pointer arrays (GStrv, aka gchar**)."""
|
||||||
|
def write_return(self, ptype, ownsreturn, info):
|
||||||
|
if ownsreturn:
|
||||||
|
raise NotImplementedError ()
|
||||||
|
else:
|
||||||
|
info.varlist.add("gchar", "**ret")
|
||||||
|
info.codeafter.append(" if (ret) {\n"
|
||||||
|
" guint size = g_strv_length(ret);\n"
|
||||||
|
" PyObject *py_ret = PyTuple_New(size);\n"
|
||||||
|
" gint i;\n"
|
||||||
|
" for (i = 0; i < size; i++)\n"
|
||||||
|
" PyTuple_SetItem(py_ret, i,\n"
|
||||||
|
" PyString_FromString(ret[i]));\n"
|
||||||
|
" return py_ret;\n"
|
||||||
|
" }\n"
|
||||||
|
" return PyTuple_New (0);\n")
|
||||||
|
|
||||||
|
matcher.register('GstClockTime', UInt64Arg())
|
||||||
|
matcher.register('GstClockTimeDiff', Int64Arg())
|
||||||
|
matcher.register('xmlNodePtr', XmlNodeArg())
|
||||||
|
matcher.register('xmlDocPtr', XmlDocArg())
|
||||||
|
matcher.register('GstCaps', GstCapsArg()) #FIXME: does this work?
|
||||||
|
matcher.register('GstCaps*', GstCapsArg()) #FIXME: does this work?
|
||||||
|
matcher.register('const-GstCaps*', GstCapsArg())
|
||||||
|
matcher.register('GstIterator*', GstIteratorArg())
|
||||||
|
|
||||||
|
arg = PointerArg('gpointer', 'G_TYPE_POINTER')
|
||||||
|
matcher.register('GstClockID', arg)
|
||||||
|
|
||||||
|
for typename in ["GstPlugin", "GstStructure", "GstTagList", "GError", "GstDate", "GstSegment"]:
|
||||||
|
matcher.register_reverse(typename, GBoxedParam)
|
||||||
|
matcher.register_reverse_ret(typename, GBoxedReturn)
|
||||||
|
|
||||||
|
for typename in ["GstBuffer*", "GstEvent*", "GstMessage*", "GstQuery*"]:
|
||||||
|
matcher.register_reverse(typename, GstMiniObjectParam)
|
||||||
|
matcher.register_reverse_ret(typename, GstMiniObjectReturn)
|
||||||
|
|
||||||
|
for typename in ["gint64", "GstClockTimeDiff"]:
|
||||||
|
matcher.register_reverse(typename, Int64Param)
|
||||||
|
matcher.register_reverse_ret(typename, Int64Return)
|
||||||
|
|
||||||
|
for typename in ["guint64", "GstClockTime"]:
|
||||||
|
matcher.register_reverse(typename, UInt64Param)
|
||||||
|
matcher.register_reverse_ret(typename, UInt64Return)
|
||||||
|
|
||||||
|
matcher.register_reverse_ret("const-gchar*", ConstStringReturn)
|
||||||
|
|
||||||
|
matcher.register_reverse("GType", IntParam)
|
||||||
|
matcher.register_reverse_ret("GType", IntReturn)
|
||||||
|
|
||||||
|
matcher.register_reverse("gulong", ULongParam)
|
||||||
|
matcher.register_reverse_ret("gulong", ULongReturn)
|
||||||
|
|
||||||
|
matcher.register("GStrv", StringArrayArg())
|
||||||
|
|
||||||
|
del arg
|
15
bindings/python/codegen/Makefile.am
Normal file
15
bindings/python/codegen/Makefile.am
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
EXTRA_DIST = \
|
||||||
|
argtypes.py \
|
||||||
|
code-coverage.py \
|
||||||
|
codegen.py \
|
||||||
|
definitions.py \
|
||||||
|
defsparser.py \
|
||||||
|
docextract.py \
|
||||||
|
docgen.py \
|
||||||
|
h2def.py \
|
||||||
|
__init__.py \
|
||||||
|
mergedefs.py \
|
||||||
|
mkskel.py \
|
||||||
|
override.py \
|
||||||
|
reversewrapper.py \
|
||||||
|
scmexpr.py
|
15
bindings/python/codegen/__init__.py
Normal file
15
bindings/python/codegen/__init__.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'argtypes',
|
||||||
|
'codegen',
|
||||||
|
'definitions',
|
||||||
|
'defsparser',
|
||||||
|
'docextract',
|
||||||
|
'docgen',
|
||||||
|
'h2def',
|
||||||
|
'mergedefs',
|
||||||
|
'mkskel',
|
||||||
|
'override',
|
||||||
|
'scmexpr'
|
||||||
|
]
|
1075
bindings/python/codegen/argtypes.py
Normal file
1075
bindings/python/codegen/argtypes.py
Normal file
File diff suppressed because it is too large
Load diff
42
bindings/python/codegen/code-coverage.py
Executable file
42
bindings/python/codegen/code-coverage.py
Executable 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()
|
1572
bindings/python/codegen/codegen.py
Normal file
1572
bindings/python/codegen/codegen.py
Normal file
File diff suppressed because it is too large
Load diff
607
bindings/python/codegen/definitions.py
Normal file
607
bindings/python/codegen/definitions.py
Normal file
|
@ -0,0 +1,607 @@
|
||||||
|
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||||
|
import copy
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def get_valid_scheme_definitions(defs):
|
||||||
|
return [x for x in defs if isinstance(x, tuple) and len(x) >= 2]
|
||||||
|
|
||||||
|
def unescape(s):
|
||||||
|
s = s.replace('\r\n', '\\r\\n').replace('\t', '\\t')
|
||||||
|
return s.replace('\r', '\\r').replace('\n', '\\n')
|
||||||
|
|
||||||
|
def make_docstring(lines):
|
||||||
|
return "(char *) " + '\n'.join(['"%s"' % unescape(s) for s in lines])
|
||||||
|
|
||||||
|
# New Parameter class, wich emulates a tuple for compatibility reasons
|
||||||
|
class Parameter(object):
|
||||||
|
def __init__(self, ptype, pname, pdflt, pnull, pdir=None, keeprefcount = False):
|
||||||
|
self.ptype = ptype
|
||||||
|
self.pname = pname
|
||||||
|
self.pdflt = pdflt
|
||||||
|
self.pnull = pnull
|
||||||
|
self.pdir = pdir
|
||||||
|
self.keeprefcount = keeprefcount
|
||||||
|
|
||||||
|
def __len__(self): return 4
|
||||||
|
def __getitem__(self, i):
|
||||||
|
return (self.ptype, self.pname, self.pdflt, self.pnull)[i]
|
||||||
|
|
||||||
|
def merge(self, old):
|
||||||
|
if old.pdflt is not None:
|
||||||
|
self.pdflt = old.pdflt
|
||||||
|
if old.pnull is not None:
|
||||||
|
self.pnull = old.pnull
|
||||||
|
|
||||||
|
# Parameter for property based constructors
|
||||||
|
class Property(object):
|
||||||
|
def __init__(self, pname, optional, argname):
|
||||||
|
self.pname = pname
|
||||||
|
self.optional = optional
|
||||||
|
self.argname = argname
|
||||||
|
|
||||||
|
def merge(self, old):
|
||||||
|
if old.optional is not None:
|
||||||
|
self.optional = old.optional
|
||||||
|
if old.argname is not None:
|
||||||
|
self.argname = old.argname
|
||||||
|
|
||||||
|
|
||||||
|
class Definition:
|
||||||
|
docstring = "NULL"
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""Create a new defs object of this type. The arguments are the
|
||||||
|
components of the definition"""
|
||||||
|
raise RuntimeError, "this is an abstract class"
|
||||||
|
def merge(self, old):
|
||||||
|
"""Merge in customisations from older version of definition"""
|
||||||
|
raise RuntimeError, "this is an abstract class"
|
||||||
|
def write_defs(self, fp=sys.stdout):
|
||||||
|
"""write out this definition in defs file format"""
|
||||||
|
raise RuntimeError, "this is an abstract class"
|
||||||
|
|
||||||
|
def guess_return_value_ownership(self):
|
||||||
|
"return 1 if caller owns return value"
|
||||||
|
if getattr(self, 'is_constructor_of', False):
|
||||||
|
self.caller_owns_return = True
|
||||||
|
elif self.ret in ('char*', 'gchar*', 'string'):
|
||||||
|
self.caller_owns_return = True
|
||||||
|
else:
|
||||||
|
self.caller_owns_return = False
|
||||||
|
|
||||||
|
|
||||||
|
class ObjectDef(Definition):
|
||||||
|
def __init__(self, name, *args):
|
||||||
|
self.name = name
|
||||||
|
self.module = None
|
||||||
|
self.parent = None
|
||||||
|
self.c_name = None
|
||||||
|
self.typecode = None
|
||||||
|
self.fields = []
|
||||||
|
self.implements = []
|
||||||
|
self.class_init_func = None
|
||||||
|
self.has_new_constructor_api = False
|
||||||
|
for arg in get_valid_scheme_definitions(args):
|
||||||
|
if arg[0] == 'in-module':
|
||||||
|
self.module = arg[1]
|
||||||
|
elif arg[0] == 'docstring':
|
||||||
|
self.docstring = make_docstring(arg[1:])
|
||||||
|
elif arg[0] == 'parent':
|
||||||
|
self.parent = arg[1]
|
||||||
|
elif arg[0] == 'c-name':
|
||||||
|
self.c_name = arg[1]
|
||||||
|
elif arg[0] == 'gtype-id':
|
||||||
|
self.typecode = arg[1]
|
||||||
|
elif arg[0] == 'fields':
|
||||||
|
for parg in arg[1:]:
|
||||||
|
self.fields.append((parg[0], parg[1]))
|
||||||
|
elif arg[0] == 'implements':
|
||||||
|
self.implements.append(arg[1])
|
||||||
|
def merge(self, old):
|
||||||
|
# currently the .h parser doesn't try to work out what fields of
|
||||||
|
# an object structure should be public, so we just copy the list
|
||||||
|
# from the old version ...
|
||||||
|
self.fields = old.fields
|
||||||
|
self.implements = old.implements
|
||||||
|
def write_defs(self, fp=sys.stdout):
|
||||||
|
fp.write('(define-object ' + self.name + '\n')
|
||||||
|
if self.module:
|
||||||
|
fp.write(' (in-module "' + self.module + '")\n')
|
||||||
|
if self.parent != (None, None):
|
||||||
|
fp.write(' (parent "' + self.parent + '")\n')
|
||||||
|
for interface in self.implements:
|
||||||
|
fp.write(' (implements "' + interface + '")\n')
|
||||||
|
if self.c_name:
|
||||||
|
fp.write(' (c-name "' + self.c_name + '")\n')
|
||||||
|
if self.typecode:
|
||||||
|
fp.write(' (gtype-id "' + self.typecode + '")\n')
|
||||||
|
if self.fields:
|
||||||
|
fp.write(' (fields\n')
|
||||||
|
for (ftype, fname) in self.fields:
|
||||||
|
fp.write(' \'("' + ftype + '" "' + fname + '")\n')
|
||||||
|
fp.write(' )\n')
|
||||||
|
fp.write(')\n\n')
|
||||||
|
|
||||||
|
class MiniObjectDef(Definition):
|
||||||
|
def __init__(self, name, *args):
|
||||||
|
self.name = name
|
||||||
|
self.module = None
|
||||||
|
self.parent = None
|
||||||
|
self.c_name = None
|
||||||
|
self.typecode = None
|
||||||
|
self.fields = []
|
||||||
|
self.implements = []
|
||||||
|
for arg in args:
|
||||||
|
if type(arg) != type(()) or len(arg) < 2:
|
||||||
|
continue
|
||||||
|
if arg[0] == 'in-module':
|
||||||
|
self.module = arg[1]
|
||||||
|
elif arg[0] == 'parent':
|
||||||
|
self.parent = arg[1]
|
||||||
|
elif arg[0] == 'c-name':
|
||||||
|
self.c_name = arg[1]
|
||||||
|
elif arg[0] == 'gtype-id':
|
||||||
|
self.typecode = arg[1]
|
||||||
|
elif arg[0] == 'fields':
|
||||||
|
for parg in arg[1:]:
|
||||||
|
self.fields.append((parg[0], parg[1]))
|
||||||
|
elif arg[0] == 'implements':
|
||||||
|
self.implements.append(arg[1])
|
||||||
|
def merge(self, old):
|
||||||
|
# currently the .h parser doesn't try to work out what fields of
|
||||||
|
# an object structure should be public, so we just copy the list
|
||||||
|
# from the old version ...
|
||||||
|
self.fields = old.fields
|
||||||
|
self.implements = old.implements
|
||||||
|
def write_defs(self, fp=sys.stdout):
|
||||||
|
fp.write('(define-object ' + self.name + '\n')
|
||||||
|
if self.module:
|
||||||
|
fp.write(' (in-module "' + self.module + '")\n')
|
||||||
|
if self.parent != (None, None):
|
||||||
|
fp.write(' (parent "' + self.parent + '")\n')
|
||||||
|
for interface in self.implements:
|
||||||
|
fp.write(' (implements "' + interface + '")\n')
|
||||||
|
if self.c_name:
|
||||||
|
fp.write(' (c-name "' + self.c_name + '")\n')
|
||||||
|
if self.typecode:
|
||||||
|
fp.write(' (gtype-id "' + self.typecode + '")\n')
|
||||||
|
if self.fields:
|
||||||
|
fp.write(' (fields\n')
|
||||||
|
for (ftype, fname) in self.fields:
|
||||||
|
fp.write(' \'("' + ftype + '" "' + fname + '")\n')
|
||||||
|
fp.write(' )\n')
|
||||||
|
fp.write(')\n\n')
|
||||||
|
|
||||||
|
|
||||||
|
class InterfaceDef(Definition):
|
||||||
|
def __init__(self, name, *args):
|
||||||
|
self.name = name
|
||||||
|
self.module = None
|
||||||
|
self.c_name = None
|
||||||
|
self.typecode = None
|
||||||
|
self.vtable = None
|
||||||
|
self.fields = []
|
||||||
|
self.interface_info = None
|
||||||
|
for arg in get_valid_scheme_definitions(args):
|
||||||
|
if arg[0] == 'in-module':
|
||||||
|
self.module = arg[1]
|
||||||
|
elif arg[0] == 'docstring':
|
||||||
|
self.docstring = make_docstring(arg[1:])
|
||||||
|
elif arg[0] == 'c-name':
|
||||||
|
self.c_name = arg[1]
|
||||||
|
elif arg[0] == 'gtype-id':
|
||||||
|
self.typecode = arg[1]
|
||||||
|
elif arg[0] == 'vtable':
|
||||||
|
self.vtable = arg[1]
|
||||||
|
if self.vtable is None:
|
||||||
|
self.vtable = self.c_name + "Iface"
|
||||||
|
def write_defs(self, fp=sys.stdout):
|
||||||
|
fp.write('(define-interface ' + self.name + '\n')
|
||||||
|
if self.module:
|
||||||
|
fp.write(' (in-module "' + self.module + '")\n')
|
||||||
|
if self.c_name:
|
||||||
|
fp.write(' (c-name "' + self.c_name + '")\n')
|
||||||
|
if self.typecode:
|
||||||
|
fp.write(' (gtype-id "' + self.typecode + '")\n')
|
||||||
|
fp.write(')\n\n')
|
||||||
|
|
||||||
|
class EnumDef(Definition):
|
||||||
|
def __init__(self, name, *args):
|
||||||
|
self.deftype = 'enum'
|
||||||
|
self.name = name
|
||||||
|
self.in_module = None
|
||||||
|
self.c_name = None
|
||||||
|
self.typecode = None
|
||||||
|
self.values = []
|
||||||
|
for arg in get_valid_scheme_definitions(args):
|
||||||
|
if arg[0] == 'in-module':
|
||||||
|
self.in_module = arg[1]
|
||||||
|
elif arg[0] == 'c-name':
|
||||||
|
self.c_name = arg[1]
|
||||||
|
elif arg[0] == 'gtype-id':
|
||||||
|
self.typecode = arg[1]
|
||||||
|
elif arg[0] == 'values':
|
||||||
|
for varg in arg[1:]:
|
||||||
|
self.values.append((varg[0], varg[1]))
|
||||||
|
def merge(self, old):
|
||||||
|
pass
|
||||||
|
def write_defs(self, fp=sys.stdout):
|
||||||
|
fp.write('(define-' + self.deftype + ' ' + self.name + '\n')
|
||||||
|
if self.in_module:
|
||||||
|
fp.write(' (in-module "' + self.in_module + '")\n')
|
||||||
|
fp.write(' (c-name "' + self.c_name + '")\n')
|
||||||
|
fp.write(' (gtype-id "' + self.typecode + '")\n')
|
||||||
|
if self.values:
|
||||||
|
fp.write(' (values\n')
|
||||||
|
for name, val in self.values:
|
||||||
|
fp.write(' \'("' + name + '" "' + val + '")\n')
|
||||||
|
fp.write(' )\n')
|
||||||
|
fp.write(')\n\n')
|
||||||
|
|
||||||
|
class FlagsDef(EnumDef):
|
||||||
|
def __init__(self, *args):
|
||||||
|
apply(EnumDef.__init__, (self,) + args)
|
||||||
|
self.deftype = 'flags'
|
||||||
|
|
||||||
|
class BoxedDef(Definition):
|
||||||
|
def __init__(self, name, *args):
|
||||||
|
self.name = name
|
||||||
|
self.module = None
|
||||||
|
self.c_name = None
|
||||||
|
self.typecode = None
|
||||||
|
self.copy = None
|
||||||
|
self.release = None
|
||||||
|
self.fields = []
|
||||||
|
for arg in get_valid_scheme_definitions(args):
|
||||||
|
if arg[0] == 'in-module':
|
||||||
|
self.module = arg[1]
|
||||||
|
elif arg[0] == 'c-name':
|
||||||
|
self.c_name = arg[1]
|
||||||
|
elif arg[0] == 'gtype-id':
|
||||||
|
self.typecode = arg[1]
|
||||||
|
elif arg[0] == 'copy-func':
|
||||||
|
self.copy = arg[1]
|
||||||
|
elif arg[0] == 'release-func':
|
||||||
|
self.release = arg[1]
|
||||||
|
elif arg[0] == 'fields':
|
||||||
|
for parg in arg[1:]:
|
||||||
|
self.fields.append((parg[0], parg[1]))
|
||||||
|
def merge(self, old):
|
||||||
|
# currently the .h parser doesn't try to work out what fields of
|
||||||
|
# an object structure should be public, so we just copy the list
|
||||||
|
# from the old version ...
|
||||||
|
self.fields = old.fields
|
||||||
|
def write_defs(self, fp=sys.stdout):
|
||||||
|
fp.write('(define-boxed ' + self.name + '\n')
|
||||||
|
if self.module:
|
||||||
|
fp.write(' (in-module "' + self.module + '")\n')
|
||||||
|
if self.c_name:
|
||||||
|
fp.write(' (c-name "' + self.c_name + '")\n')
|
||||||
|
if self.typecode:
|
||||||
|
fp.write(' (gtype-id "' + self.typecode + '")\n')
|
||||||
|
if self.copy:
|
||||||
|
fp.write(' (copy-func "' + self.copy + '")\n')
|
||||||
|
if self.release:
|
||||||
|
fp.write(' (release-func "' + self.release + '")\n')
|
||||||
|
if self.fields:
|
||||||
|
fp.write(' (fields\n')
|
||||||
|
for (ftype, fname) in self.fields:
|
||||||
|
fp.write(' \'("' + ftype + '" "' + fname + '")\n')
|
||||||
|
fp.write(' )\n')
|
||||||
|
fp.write(')\n\n')
|
||||||
|
|
||||||
|
class PointerDef(Definition):
|
||||||
|
def __init__(self, name, *args):
|
||||||
|
self.name = name
|
||||||
|
self.module = None
|
||||||
|
self.c_name = None
|
||||||
|
self.typecode = None
|
||||||
|
self.fields = []
|
||||||
|
for arg in get_valid_scheme_definitions(args):
|
||||||
|
if arg[0] == 'in-module':
|
||||||
|
self.module = arg[1]
|
||||||
|
elif arg[0] == 'c-name':
|
||||||
|
self.c_name = arg[1]
|
||||||
|
elif arg[0] == 'gtype-id':
|
||||||
|
self.typecode = arg[1]
|
||||||
|
elif arg[0] == 'fields':
|
||||||
|
for parg in arg[1:]:
|
||||||
|
self.fields.append((parg[0], parg[1]))
|
||||||
|
def merge(self, old):
|
||||||
|
# currently the .h parser doesn't try to work out what fields of
|
||||||
|
# an object structure should be public, so we just copy the list
|
||||||
|
# from the old version ...
|
||||||
|
self.fields = old.fields
|
||||||
|
def write_defs(self, fp=sys.stdout):
|
||||||
|
fp.write('(define-pointer ' + self.name + '\n')
|
||||||
|
if self.module:
|
||||||
|
fp.write(' (in-module "' + self.module + '")\n')
|
||||||
|
if self.c_name:
|
||||||
|
fp.write(' (c-name "' + self.c_name + '")\n')
|
||||||
|
if self.typecode:
|
||||||
|
fp.write(' (gtype-id "' + self.typecode + '")\n')
|
||||||
|
if self.fields:
|
||||||
|
fp.write(' (fields\n')
|
||||||
|
for (ftype, fname) in self.fields:
|
||||||
|
fp.write(' \'("' + ftype + '" "' + fname + '")\n')
|
||||||
|
fp.write(' )\n')
|
||||||
|
fp.write(')\n\n')
|
||||||
|
|
||||||
|
class MethodDefBase(Definition):
|
||||||
|
def __init__(self, name, *args):
|
||||||
|
dump = 0
|
||||||
|
self.name = name
|
||||||
|
self.ret = None
|
||||||
|
self.caller_owns_return = None
|
||||||
|
self.unblock_threads = None
|
||||||
|
self.c_name = None
|
||||||
|
self.typecode = None
|
||||||
|
self.of_object = None
|
||||||
|
self.params = [] # of form (type, name, default, nullok)
|
||||||
|
self.varargs = 0
|
||||||
|
self.deprecated = None
|
||||||
|
for arg in get_valid_scheme_definitions(args):
|
||||||
|
if arg[0] == 'of-object':
|
||||||
|
self.of_object = arg[1]
|
||||||
|
elif arg[0] == 'docstring':
|
||||||
|
self.docstring = make_docstring(arg[1:])
|
||||||
|
elif arg[0] == 'c-name':
|
||||||
|
self.c_name = arg[1]
|
||||||
|
elif arg[0] == 'gtype-id':
|
||||||
|
self.typecode = arg[1]
|
||||||
|
elif arg[0] == 'return-type':
|
||||||
|
self.ret = arg[1]
|
||||||
|
elif arg[0] == 'caller-owns-return':
|
||||||
|
self.caller_owns_return = arg[1] in ('t', '#t')
|
||||||
|
elif arg[0] == 'unblock-threads':
|
||||||
|
self.unblock_threads = arg[1] in ('t', '#t')
|
||||||
|
elif arg[0] == 'parameters':
|
||||||
|
for parg in arg[1:]:
|
||||||
|
ptype = parg[0]
|
||||||
|
pname = parg[1]
|
||||||
|
pdflt = None
|
||||||
|
pnull = 0
|
||||||
|
pdir = None
|
||||||
|
keeprefcount = False
|
||||||
|
for farg in parg[2:]:
|
||||||
|
assert isinstance(farg, tuple)
|
||||||
|
if farg[0] == 'default':
|
||||||
|
pdflt = farg[1]
|
||||||
|
elif farg[0] == 'null-ok':
|
||||||
|
pnull = 1
|
||||||
|
elif farg[0] == 'direction':
|
||||||
|
pdir = farg[1]
|
||||||
|
elif farg[0] == 'keep-refcount':
|
||||||
|
keeprefcount = True
|
||||||
|
self.params.append(Parameter(ptype, pname, pdflt, pnull, pdir,
|
||||||
|
keeprefcount=keeprefcount))
|
||||||
|
elif arg[0] == 'varargs':
|
||||||
|
self.varargs = arg[1] in ('t', '#t')
|
||||||
|
elif arg[0] == 'deprecated':
|
||||||
|
self.deprecated = arg[1]
|
||||||
|
else:
|
||||||
|
sys.stderr.write("Warning: %s argument unsupported.\n"
|
||||||
|
% (arg[0]))
|
||||||
|
dump = 1
|
||||||
|
if dump:
|
||||||
|
self.write_defs(sys.stderr)
|
||||||
|
|
||||||
|
if self.caller_owns_return is None and self.ret is not None:
|
||||||
|
self.guess_return_value_ownership()
|
||||||
|
|
||||||
|
def merge(self, old, parmerge):
|
||||||
|
self.caller_owns_return = old.caller_owns_return
|
||||||
|
self.varargs = old.varargs
|
||||||
|
# here we merge extra parameter flags accross to the new object.
|
||||||
|
if not parmerge:
|
||||||
|
self.params = copy.deepcopy(old.params)
|
||||||
|
return
|
||||||
|
for i in range(len(self.params)):
|
||||||
|
ptype, pname, pdflt, pnull = self.params[i]
|
||||||
|
for p2 in old.params:
|
||||||
|
if p2[1] == pname:
|
||||||
|
self.params[i] = (ptype, pname, p2[2], p2[3])
|
||||||
|
break
|
||||||
|
def _write_defs(self, fp=sys.stdout):
|
||||||
|
if self.of_object != (None, None):
|
||||||
|
fp.write(' (of-object "' + self.of_object + '")\n')
|
||||||
|
if self.c_name:
|
||||||
|
fp.write(' (c-name "' + self.c_name + '")\n')
|
||||||
|
if self.typecode:
|
||||||
|
fp.write(' (gtype-id "' + self.typecode + '")\n')
|
||||||
|
if self.caller_owns_return:
|
||||||
|
fp.write(' (caller-owns-return #t)\n')
|
||||||
|
if self.unblock_threads:
|
||||||
|
fp.write(' (unblock_threads #t)\n')
|
||||||
|
if self.ret:
|
||||||
|
fp.write(' (return-type "' + self.ret + '")\n')
|
||||||
|
if self.deprecated:
|
||||||
|
fp.write(' (deprecated "' + self.deprecated + '")\n')
|
||||||
|
if self.params:
|
||||||
|
fp.write(' (parameters\n')
|
||||||
|
for ptype, pname, pdflt, pnull in self.params:
|
||||||
|
fp.write(' \'("' + ptype + '" "' + pname +'"')
|
||||||
|
if pdflt: fp.write(' (default "' + pdflt + '")')
|
||||||
|
if pnull: fp.write(' (null-ok)')
|
||||||
|
fp.write(')\n')
|
||||||
|
fp.write(' )\n')
|
||||||
|
if self.varargs:
|
||||||
|
fp.write(' (varargs #t)\n')
|
||||||
|
fp.write(')\n\n')
|
||||||
|
|
||||||
|
|
||||||
|
class MethodDef(MethodDefBase):
|
||||||
|
def __init__(self, name, *args):
|
||||||
|
MethodDefBase.__init__(self, name, *args)
|
||||||
|
for item in ('c_name', 'of_object'):
|
||||||
|
if self.__dict__[item] == None:
|
||||||
|
self.write_defs(sys.stderr)
|
||||||
|
raise RuntimeError, "definition missing required %s" % (item,)
|
||||||
|
|
||||||
|
def write_defs(self, fp=sys.stdout):
|
||||||
|
fp.write('(define-method ' + self.name + '\n')
|
||||||
|
self._write_defs(fp)
|
||||||
|
|
||||||
|
class VirtualDef(MethodDefBase):
|
||||||
|
def write_defs(self, fp=sys.stdout):
|
||||||
|
fp.write('(define-virtual ' + self.name + '\n')
|
||||||
|
self._write_defs(fp)
|
||||||
|
|
||||||
|
class FunctionDef(Definition):
|
||||||
|
def __init__(self, name, *args):
|
||||||
|
dump = 0
|
||||||
|
self.name = name
|
||||||
|
self.in_module = None
|
||||||
|
self.is_constructor_of = None
|
||||||
|
self.ret = None
|
||||||
|
self.caller_owns_return = None
|
||||||
|
self.unblock_threads = None
|
||||||
|
self.c_name = None
|
||||||
|
self.typecode = None
|
||||||
|
self.params = [] # of form (type, name, default, nullok)
|
||||||
|
self.varargs = 0
|
||||||
|
self.deprecated = None
|
||||||
|
for arg in get_valid_scheme_definitions(args):
|
||||||
|
if arg[0] == 'in-module':
|
||||||
|
self.in_module = arg[1]
|
||||||
|
elif arg[0] == 'docstring':
|
||||||
|
self.docstring = make_docstring(arg[1:])
|
||||||
|
elif arg[0] == 'is-constructor-of':
|
||||||
|
self.is_constructor_of = arg[1]
|
||||||
|
elif arg[0] == 'c-name':
|
||||||
|
self.c_name = arg[1]
|
||||||
|
elif arg[0] == 'gtype-id':
|
||||||
|
self.typecode = arg[1]
|
||||||
|
elif arg[0] == 'return-type':
|
||||||
|
self.ret = arg[1]
|
||||||
|
elif arg[0] == 'caller-owns-return':
|
||||||
|
self.caller_owns_return = arg[1] in ('t', '#t')
|
||||||
|
elif arg[0] == 'unblock-threads':
|
||||||
|
self.unblock_threads = arg[1] in ('t', '#t')
|
||||||
|
elif arg[0] == 'parameters':
|
||||||
|
for parg in arg[1:]:
|
||||||
|
ptype = parg[0]
|
||||||
|
pname = parg[1]
|
||||||
|
pdflt = None
|
||||||
|
pnull = 0
|
||||||
|
keeprefcount = False
|
||||||
|
for farg in parg[2:]:
|
||||||
|
if farg[0] == 'default':
|
||||||
|
pdflt = farg[1]
|
||||||
|
elif farg[0] == 'null-ok':
|
||||||
|
pnull = 1
|
||||||
|
elif farg[0] == 'keep-refcount':
|
||||||
|
keeprefcount = True
|
||||||
|
self.params.append(Parameter(ptype, pname, pdflt, pnull,
|
||||||
|
keeprefcount = keeprefcount))
|
||||||
|
elif arg[0] == 'properties':
|
||||||
|
if self.is_constructor_of is None:
|
||||||
|
print >> sys.stderr, "Warning: (properties ...) "\
|
||||||
|
"is only valid for constructors"
|
||||||
|
for prop in arg[1:]:
|
||||||
|
pname = prop[0]
|
||||||
|
optional = False
|
||||||
|
argname = pname
|
||||||
|
for farg in prop[1:]:
|
||||||
|
if farg[0] == 'optional':
|
||||||
|
optional = True
|
||||||
|
elif farg[0] == 'argname':
|
||||||
|
argname = farg[1]
|
||||||
|
self.params.append(Property(pname, optional, argname))
|
||||||
|
elif arg[0] == 'varargs':
|
||||||
|
self.varargs = arg[1] in ('t', '#t')
|
||||||
|
elif arg[0] == 'deprecated':
|
||||||
|
self.deprecated = arg[1]
|
||||||
|
else:
|
||||||
|
sys.stderr.write("Warning: %s argument unsupported\n"
|
||||||
|
% (arg[0],))
|
||||||
|
dump = 1
|
||||||
|
if dump:
|
||||||
|
self.write_defs(sys.stderr)
|
||||||
|
|
||||||
|
if self.caller_owns_return is None and self.ret is not None:
|
||||||
|
self.guess_return_value_ownership()
|
||||||
|
for item in ('c_name',):
|
||||||
|
if self.__dict__[item] == None:
|
||||||
|
self.write_defs(sys.stderr)
|
||||||
|
raise RuntimeError, "definition missing required %s" % (item,)
|
||||||
|
|
||||||
|
_method_write_defs = MethodDef.__dict__['write_defs']
|
||||||
|
|
||||||
|
def merge(self, old, parmerge):
|
||||||
|
self.caller_owns_return = old.caller_owns_return
|
||||||
|
self.varargs = old.varargs
|
||||||
|
if not parmerge:
|
||||||
|
self.params = copy.deepcopy(old.params)
|
||||||
|
return
|
||||||
|
# here we merge extra parameter flags accross to the new object.
|
||||||
|
def merge_param(param):
|
||||||
|
for old_param in old.params:
|
||||||
|
if old_param.pname == param.pname:
|
||||||
|
if isinstance(old_param, Property):
|
||||||
|
# h2def never scans Property's, therefore if
|
||||||
|
# we have one it was manually written, so we
|
||||||
|
# keep it.
|
||||||
|
return copy.deepcopy(old_param)
|
||||||
|
else:
|
||||||
|
param.merge(old_param)
|
||||||
|
return param
|
||||||
|
raise RuntimeError, "could not find %s in old_parameters %r" % (
|
||||||
|
param.pname, [p.pname for p in old.params])
|
||||||
|
try:
|
||||||
|
self.params = map(merge_param, self.params)
|
||||||
|
except RuntimeError:
|
||||||
|
# parameter names changed and we can't find a match; it's
|
||||||
|
# safer to keep the old parameter list untouched.
|
||||||
|
self.params = copy.deepcopy(old.params)
|
||||||
|
|
||||||
|
if not self.is_constructor_of:
|
||||||
|
try:
|
||||||
|
self.is_constructor_of = old.is_constructor_of
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
if isinstance(old, MethodDef):
|
||||||
|
self.name = old.name
|
||||||
|
# transmogrify from function into method ...
|
||||||
|
self.write_defs = self._method_write_defs
|
||||||
|
self.of_object = old.of_object
|
||||||
|
del self.params[0]
|
||||||
|
def write_defs(self, fp=sys.stdout):
|
||||||
|
fp.write('(define-function ' + self.name + '\n')
|
||||||
|
if self.in_module:
|
||||||
|
fp.write(' (in-module "' + self.in_module + '")\n')
|
||||||
|
if self.is_constructor_of:
|
||||||
|
fp.write(' (is-constructor-of "' + self.is_constructor_of +'")\n')
|
||||||
|
if self.c_name:
|
||||||
|
fp.write(' (c-name "' + self.c_name + '")\n')
|
||||||
|
if self.typecode:
|
||||||
|
fp.write(' (gtype-id "' + self.typecode + '")\n')
|
||||||
|
if self.caller_owns_return:
|
||||||
|
fp.write(' (caller-owns-return #t)\n')
|
||||||
|
if self.unblock_threads:
|
||||||
|
fp.write(' (unblock-threads #t)\n')
|
||||||
|
if self.ret:
|
||||||
|
fp.write(' (return-type "' + self.ret + '")\n')
|
||||||
|
if self.deprecated:
|
||||||
|
fp.write(' (deprecated "' + self.deprecated + '")\n')
|
||||||
|
if self.params:
|
||||||
|
if isinstance(self.params[0], Parameter):
|
||||||
|
fp.write(' (parameters\n')
|
||||||
|
for ptype, pname, pdflt, pnull in self.params:
|
||||||
|
fp.write(' \'("' + ptype + '" "' + pname +'"')
|
||||||
|
if pdflt: fp.write(' (default "' + pdflt + '")')
|
||||||
|
if pnull: fp.write(' (null-ok)')
|
||||||
|
fp.write(')\n')
|
||||||
|
fp.write(' )\n')
|
||||||
|
elif isinstance(self.params[0], Property):
|
||||||
|
fp.write(' (properties\n')
|
||||||
|
for prop in self.params:
|
||||||
|
fp.write(' \'("' + prop.pname +'"')
|
||||||
|
if prop.optional: fp.write(' (optional)')
|
||||||
|
fp.write(')\n')
|
||||||
|
fp.write(' )\n')
|
||||||
|
else:
|
||||||
|
assert False, "strange parameter list %r" % self.params[0]
|
||||||
|
if self.varargs:
|
||||||
|
fp.write(' (varargs #t)\n')
|
||||||
|
|
||||||
|
fp.write(')\n\n')
|
143
bindings/python/codegen/defsparser.py
Normal file
143
bindings/python/codegen/defsparser.py
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||||
|
import os, sys
|
||||||
|
import scmexpr
|
||||||
|
from definitions import BoxedDef, EnumDef, FlagsDef, FunctionDef, \
|
||||||
|
InterfaceDef, MethodDef, ObjectDef, MiniObjectDef, PointerDef, \
|
||||||
|
VirtualDef
|
||||||
|
|
||||||
|
class IncludeParser(scmexpr.Parser):
|
||||||
|
"""A simple parser that follows include statements automatically"""
|
||||||
|
def include(self, filename):
|
||||||
|
if not os.path.isabs(filename):
|
||||||
|
filename = os.path.join(os.path.dirname(self.filename), filename)
|
||||||
|
|
||||||
|
# set self.filename to the include name, to handle recursive includes
|
||||||
|
oldfile = self.filename
|
||||||
|
self.filename = filename
|
||||||
|
self.startParsing()
|
||||||
|
self.filename = oldfile
|
||||||
|
|
||||||
|
class DefsParser(IncludeParser):
|
||||||
|
def __init__(self, arg, defines={}):
|
||||||
|
IncludeParser.__init__(self, arg)
|
||||||
|
self.objects = []
|
||||||
|
self.miniobjects = []
|
||||||
|
self.interfaces = []
|
||||||
|
self.enums = [] # enums and flags
|
||||||
|
self.boxes = [] # boxed types
|
||||||
|
self.pointers = [] # pointer types
|
||||||
|
self.functions = [] # functions and methods
|
||||||
|
self.virtuals = [] # virtual methods
|
||||||
|
self.c_name = {} # hash of c names of functions
|
||||||
|
self.methods = {} # hash of methods of particular objects
|
||||||
|
self.defines = defines # -Dfoo=bar options, as dictionary
|
||||||
|
|
||||||
|
def define_object(self, *args):
|
||||||
|
odef = apply(ObjectDef, args)
|
||||||
|
self.objects.append(odef)
|
||||||
|
self.c_name[odef.c_name] = odef
|
||||||
|
# TODO: define_mini_object
|
||||||
|
def define_miniobject(self, *args):
|
||||||
|
odef = apply(MiniObjectDef, args)
|
||||||
|
self.miniobjects.append(odef)
|
||||||
|
self.c_name[odef.c_name] = odef
|
||||||
|
def define_interface(self, *args):
|
||||||
|
idef = apply(InterfaceDef, args)
|
||||||
|
self.interfaces.append(idef)
|
||||||
|
self.c_name[idef.c_name] = idef
|
||||||
|
def define_enum(self, *args):
|
||||||
|
edef = apply(EnumDef, args)
|
||||||
|
self.enums.append(edef)
|
||||||
|
self.c_name[edef.c_name] = edef
|
||||||
|
def define_flags(self, *args):
|
||||||
|
fdef = apply(FlagsDef, args)
|
||||||
|
self.enums.append(fdef)
|
||||||
|
self.c_name[fdef.c_name] = fdef
|
||||||
|
def define_boxed(self, *args):
|
||||||
|
bdef = apply(BoxedDef, args)
|
||||||
|
self.boxes.append(bdef)
|
||||||
|
self.c_name[bdef.c_name] = bdef
|
||||||
|
def define_pointer(self, *args):
|
||||||
|
pdef = apply(PointerDef, args)
|
||||||
|
self.pointers.append(pdef)
|
||||||
|
self.c_name[pdef.c_name] = pdef
|
||||||
|
def define_function(self, *args):
|
||||||
|
fdef = apply(FunctionDef, args)
|
||||||
|
self.functions.append(fdef)
|
||||||
|
self.c_name[fdef.c_name] = fdef
|
||||||
|
def define_method(self, *args):
|
||||||
|
mdef = apply(MethodDef, args)
|
||||||
|
self.functions.append(mdef)
|
||||||
|
self.c_name[mdef.c_name] = mdef
|
||||||
|
def define_virtual(self, *args):
|
||||||
|
vdef = apply(VirtualDef, args)
|
||||||
|
self.virtuals.append(vdef)
|
||||||
|
def merge(self, old, parmerge):
|
||||||
|
for obj in self.objects:
|
||||||
|
if old.c_name.has_key(obj.c_name):
|
||||||
|
obj.merge(old.c_name[obj.c_name])
|
||||||
|
for f in self.functions:
|
||||||
|
if old.c_name.has_key(f.c_name):
|
||||||
|
f.merge(old.c_name[f.c_name], parmerge)
|
||||||
|
|
||||||
|
def printMissing(self, old):
|
||||||
|
for obj in self.objects:
|
||||||
|
if not old.c_name.has_key(obj.c_name):
|
||||||
|
obj.write_defs()
|
||||||
|
for f in self.functions:
|
||||||
|
if not old.c_name.has_key(f.c_name):
|
||||||
|
f.write_defs()
|
||||||
|
|
||||||
|
def write_defs(self, fp=sys.stdout):
|
||||||
|
for obj in self.objects:
|
||||||
|
obj.write_defs(fp)
|
||||||
|
# TODO: Add miniobject
|
||||||
|
for obj in self.miniobjects:
|
||||||
|
obj.write_defs(fp)
|
||||||
|
for enum in self.enums:
|
||||||
|
enum.write_defs(fp)
|
||||||
|
for boxed in self.boxes:
|
||||||
|
boxed.write_defs(fp)
|
||||||
|
for pointer in self.pointers:
|
||||||
|
pointer.write_defs(fp)
|
||||||
|
for func in self.functions:
|
||||||
|
func.write_defs(fp)
|
||||||
|
|
||||||
|
def find_object(self, c_name):
|
||||||
|
for obj in self.objects:
|
||||||
|
if obj.c_name == c_name:
|
||||||
|
return obj
|
||||||
|
else:
|
||||||
|
raise ValueError, 'object not found'
|
||||||
|
|
||||||
|
def find_constructor(self, obj, overrides):
|
||||||
|
for func in self.functions:
|
||||||
|
if isinstance(func, FunctionDef) and \
|
||||||
|
func.is_constructor_of == obj.c_name and \
|
||||||
|
not overrides.is_ignored(func.c_name):
|
||||||
|
return func
|
||||||
|
|
||||||
|
def find_methods(self, obj):
|
||||||
|
objname = obj.c_name
|
||||||
|
return filter(lambda func, on=objname: isinstance(func, MethodDef) and
|
||||||
|
func.of_object == on, self.functions)
|
||||||
|
|
||||||
|
def find_virtuals(self, obj):
|
||||||
|
objname = obj.c_name
|
||||||
|
retval = filter(lambda func, on=objname: isinstance(func, VirtualDef) and
|
||||||
|
func.of_object == on, self.virtuals)
|
||||||
|
return retval
|
||||||
|
|
||||||
|
def find_functions(self):
|
||||||
|
return filter(lambda func: isinstance(func, FunctionDef) and
|
||||||
|
not func.is_constructor_of, self.functions)
|
||||||
|
|
||||||
|
def ifdef(self, *args):
|
||||||
|
if args[0] in self.defines:
|
||||||
|
for arg in args[1:]:
|
||||||
|
self.handle(arg)
|
||||||
|
|
||||||
|
def ifndef(self, *args):
|
||||||
|
if args[0] not in self.defines:
|
||||||
|
for arg in args[1:]:
|
||||||
|
self.handle(arg)
|
185
bindings/python/codegen/docextract.py
Normal file
185
bindings/python/codegen/docextract.py
Normal 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
|
||||||
|
return_start = match.group(1)
|
||||||
|
cur_doc.ret = match.group(2)
|
||||||
|
cur_doc.description = cur_doc.description + return_start + \
|
||||||
|
cur_doc.ret
|
||||||
|
else:
|
||||||
|
cur_doc.append_return(line)
|
||||||
|
elif in_description:
|
||||||
|
if line[:12] == 'Description:':
|
||||||
|
line = line[12:]
|
||||||
|
match = return_pat.match(line)
|
||||||
|
if match:
|
||||||
|
in_return = 1
|
||||||
|
return_start = match.group(1)
|
||||||
|
cur_doc.append_return(match.group(2))
|
||||||
|
else:
|
||||||
|
cur_doc.append_description(line)
|
||||||
|
elif line == '\n':
|
||||||
|
# end of parameters
|
||||||
|
in_description = 1
|
||||||
|
else:
|
||||||
|
match = param_pat.match(line)
|
||||||
|
if match:
|
||||||
|
param = match.group(1)
|
||||||
|
desc = match.group(2)
|
||||||
|
if param == 'returns':
|
||||||
|
cur_doc.ret = desc
|
||||||
|
else:
|
||||||
|
cur_doc.add_param(param, desc)
|
||||||
|
else:
|
||||||
|
# must be continuation
|
||||||
|
try:
|
||||||
|
if param == 'returns':
|
||||||
|
cur_doc.append_return(line)
|
||||||
|
else:
|
||||||
|
cur_doc.append_to_last_param(line)
|
||||||
|
except:
|
||||||
|
sys.stderr.write('something weird while reading param\n')
|
||||||
|
line = fp.readline()
|
||||||
|
|
||||||
|
def parse_dir(dir, doc_dict):
|
||||||
|
for file in os.listdir(dir):
|
||||||
|
if file in ('.', '..'): continue
|
||||||
|
path = os.path.join(dir, file)
|
||||||
|
if os.path.isdir(path):
|
||||||
|
parse_dir(path, doc_dict)
|
||||||
|
if len(file) > 2 and file[-2:] == '.c':
|
||||||
|
parse_file(open(path, 'r'), doc_dict)
|
||||||
|
|
||||||
|
def extract(dirs, doc_dict=None):
|
||||||
|
if not doc_dict: doc_dict = {}
|
||||||
|
for dir in dirs:
|
||||||
|
parse_dir(dir, doc_dict)
|
||||||
|
return doc_dict
|
||||||
|
|
||||||
|
tmpl_section_pat = re.compile(r'^<!-- ##### (\w+) (\w+) ##### -->$')
|
||||||
|
def parse_tmpl(fp, doc_dict):
|
||||||
|
cur_doc = None
|
||||||
|
|
||||||
|
line = fp.readline()
|
||||||
|
while line:
|
||||||
|
match = tmpl_section_pat.match(line)
|
||||||
|
if match:
|
||||||
|
cur_doc = None # new input shouldn't affect the old doc dict
|
||||||
|
sect_type = match.group(1)
|
||||||
|
sect_name = match.group(2)
|
||||||
|
|
||||||
|
if sect_type == 'FUNCTION':
|
||||||
|
cur_doc = doc_dict.get(sect_name)
|
||||||
|
if not cur_doc:
|
||||||
|
cur_doc = FunctionDoc()
|
||||||
|
cur_doc.set_name(sect_name)
|
||||||
|
doc_dict[sect_name] = cur_doc
|
||||||
|
elif line == '<!-- # Unused Parameters # -->\n':
|
||||||
|
cur_doc = None # don't worry about unused params.
|
||||||
|
elif cur_doc:
|
||||||
|
if line[:10] == '@Returns: ':
|
||||||
|
if string.strip(line[10:]):
|
||||||
|
cur_doc.append_return(line[10:])
|
||||||
|
elif line[0] == '@':
|
||||||
|
pos = string.find(line, ':')
|
||||||
|
if pos >= 0:
|
||||||
|
cur_doc.append_to_named_param(line[1:pos], line[pos+1:])
|
||||||
|
else:
|
||||||
|
cur_doc.append_description(line)
|
||||||
|
else:
|
||||||
|
cur_doc.append_description(line)
|
||||||
|
|
||||||
|
line = fp.readline()
|
||||||
|
|
||||||
|
def extract_tmpl(dirs, doc_dict=None):
|
||||||
|
if not doc_dict: doc_dict = {}
|
||||||
|
for dir in dirs:
|
||||||
|
for file in os.listdir(dir):
|
||||||
|
if file in ('.', '..'): continue
|
||||||
|
path = os.path.join(dir, file)
|
||||||
|
if os.path.isdir(path):
|
||||||
|
continue
|
||||||
|
if len(file) > 2 and file[-2:] == '.sgml':
|
||||||
|
parse_tmpl(open(path, 'r'), doc_dict)
|
||||||
|
return doc_dict
|
752
bindings/python/codegen/docgen.py
Normal file
752
bindings/python/codegen/docgen.py
Normal file
|
@ -0,0 +1,752 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||||
|
import sys, os, string, re, getopt
|
||||||
|
|
||||||
|
import defsparser
|
||||||
|
import definitions
|
||||||
|
import override
|
||||||
|
import docextract
|
||||||
|
|
||||||
|
class Node:
|
||||||
|
def __init__(self, name, interfaces=[]):
|
||||||
|
self.name = name
|
||||||
|
self.interfaces = interfaces
|
||||||
|
self.subclasses = []
|
||||||
|
def add_child(self, node):
|
||||||
|
self.subclasses.append(node)
|
||||||
|
|
||||||
|
def build_object_tree(parser):
|
||||||
|
# reorder objects so that parent classes come first ...
|
||||||
|
objects = parser.objects[:]
|
||||||
|
pos = 0
|
||||||
|
while pos < len(objects):
|
||||||
|
parent = objects[pos].parent
|
||||||
|
for i in range(pos+1, len(objects)):
|
||||||
|
if objects[i].c_name == parent:
|
||||||
|
objects.insert(i+1, objects[pos])
|
||||||
|
del objects[pos]
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
pos = pos + 1
|
||||||
|
|
||||||
|
root = Node(None)
|
||||||
|
nodes = { None: root }
|
||||||
|
for obj_def in objects:
|
||||||
|
print obj_def.name
|
||||||
|
parent_node = nodes[obj_def.parent]
|
||||||
|
node = Node(obj_def.c_name, obj_def.implements)
|
||||||
|
parent_node.add_child(node)
|
||||||
|
nodes[node.name] = node
|
||||||
|
|
||||||
|
if parser.interfaces:
|
||||||
|
interfaces = Node('gobject.GInterface')
|
||||||
|
root.add_child(interfaces)
|
||||||
|
nodes[interfaces.name] = interfaces
|
||||||
|
for obj_def in parser.interfaces:
|
||||||
|
node = Node(obj_def.c_name)
|
||||||
|
interfaces.add_child(node)
|
||||||
|
nodes[node.name] = node
|
||||||
|
|
||||||
|
if parser.boxes:
|
||||||
|
boxed = Node('gobject.GBoxed')
|
||||||
|
root.add_child(boxed)
|
||||||
|
nodes[boxed.name] = boxed
|
||||||
|
for obj_def in parser.boxes:
|
||||||
|
node = Node(obj_def.c_name)
|
||||||
|
boxed.add_child(node)
|
||||||
|
nodes[node.name] = node
|
||||||
|
|
||||||
|
if parser.pointers:
|
||||||
|
pointers = Node('gobject.GPointer')
|
||||||
|
root.add_child(pointers)
|
||||||
|
nodes[pointers.name] = pointers
|
||||||
|
for obj_def in parser.pointers:
|
||||||
|
node = Node(obj_def.c_name)
|
||||||
|
pointers.add_child(node)
|
||||||
|
nodes[node.name] = node
|
||||||
|
|
||||||
|
return root
|
||||||
|
|
||||||
|
class DocWriter:
|
||||||
|
def __init__(self):
|
||||||
|
# parse the defs file
|
||||||
|
self.parser = defsparser.DefsParser(())
|
||||||
|
self.overrides = override.Overrides()
|
||||||
|
self.classmap = {}
|
||||||
|
self.docs = {}
|
||||||
|
|
||||||
|
def add_sourcedirs(self, source_dirs):
|
||||||
|
self.docs = docextract.extract(source_dirs, self.docs)
|
||||||
|
def add_tmpldirs(self, tmpl_dirs):
|
||||||
|
self.docs = docextract.extract_tmpl(tmpl_dirs, self.docs)
|
||||||
|
|
||||||
|
def add_docs(self, defs_file, overrides_file, module_name):
|
||||||
|
'''parse information about a given defs file'''
|
||||||
|
self.parser.filename = defs_file
|
||||||
|
self.parser.startParsing(defs_file)
|
||||||
|
if overrides_file:
|
||||||
|
self.overrides.handle_file(overrides_file)
|
||||||
|
|
||||||
|
for obj in self.parser.objects:
|
||||||
|
if not self.classmap.has_key(obj.c_name):
|
||||||
|
self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
|
||||||
|
for obj in self.parser.interfaces:
|
||||||
|
if not self.classmap.has_key(obj.c_name):
|
||||||
|
self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
|
||||||
|
for obj in self.parser.boxes:
|
||||||
|
if not self.classmap.has_key(obj.c_name):
|
||||||
|
self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
|
||||||
|
for obj in self.parser.pointers:
|
||||||
|
if not self.classmap.has_key(obj.c_name):
|
||||||
|
self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
|
||||||
|
|
||||||
|
def pyname(self, name):
|
||||||
|
return self.classmap.get(name, name)
|
||||||
|
|
||||||
|
def __compare(self, obja, objb):
|
||||||
|
return cmp(self.pyname(obja.c_name), self.pyname(objb.c_name))
|
||||||
|
def output_docs(self, output_prefix):
|
||||||
|
files = []
|
||||||
|
|
||||||
|
# class hierarchy
|
||||||
|
hierarchy = build_object_tree(self.parser)
|
||||||
|
filename = self.create_filename('hierarchy', output_prefix)
|
||||||
|
fp = open(filename, 'w')
|
||||||
|
self.write_full_hierarchy(hierarchy, fp)
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
obj_defs = self.parser.objects + self.parser.interfaces + \
|
||||||
|
self.parser.boxes + self.parser.pointers
|
||||||
|
obj_defs.sort(self.__compare)
|
||||||
|
for obj_def in obj_defs:
|
||||||
|
filename = self.create_filename(obj_def.c_name, output_prefix)
|
||||||
|
fp = open(filename, 'w')
|
||||||
|
if isinstance(obj_def, definitions.ObjectDef):
|
||||||
|
self.output_object_docs(obj_def, fp)
|
||||||
|
elif isinstance(obj_def, definitions.InterfaceDef):
|
||||||
|
self.output_interface_docs(obj_def, fp)
|
||||||
|
elif isinstance(obj_def, definitions.BoxedDef):
|
||||||
|
self.output_boxed_docs(obj_def, fp)
|
||||||
|
elif isinstance(obj_def, definitions.PointerDef):
|
||||||
|
self.output_boxed_docs(obj_def, fp)
|
||||||
|
fp.close()
|
||||||
|
files.append((os.path.basename(filename), obj_def))
|
||||||
|
|
||||||
|
if files:
|
||||||
|
filename = self.create_toc_filename(output_prefix)
|
||||||
|
fp = open(filename, 'w')
|
||||||
|
self.output_toc(files, fp)
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
def output_object_docs(self, obj_def, fp=sys.stdout):
|
||||||
|
self.write_class_header(obj_def.c_name, fp)
|
||||||
|
|
||||||
|
self.write_heading('Synopsis', fp)
|
||||||
|
self.write_synopsis(obj_def, fp)
|
||||||
|
self.close_section(fp)
|
||||||
|
|
||||||
|
# construct the inheritence hierarchy ...
|
||||||
|
ancestry = [ (obj_def.c_name, obj_def.implements) ]
|
||||||
|
try:
|
||||||
|
parent = obj_def.parent
|
||||||
|
while parent != None:
|
||||||
|
if parent == 'GObject':
|
||||||
|
ancestry.append(('GObject', []))
|
||||||
|
parent = None
|
||||||
|
else:
|
||||||
|
parent_def = self.parser.find_object(parent)
|
||||||
|
ancestry.append((parent_def.c_name, parent_def.implements))
|
||||||
|
parent = parent_def.parent
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
ancestry.reverse()
|
||||||
|
self.write_heading('Ancestry', fp)
|
||||||
|
self.write_hierarchy(obj_def.c_name, ancestry, fp)
|
||||||
|
self.close_section(fp)
|
||||||
|
|
||||||
|
constructor = self.parser.find_constructor(obj_def, self.overrides)
|
||||||
|
if constructor:
|
||||||
|
self.write_heading('Constructor', fp)
|
||||||
|
self.write_constructor(constructor,
|
||||||
|
self.docs.get(constructor.c_name, None),
|
||||||
|
fp)
|
||||||
|
self.close_section(fp)
|
||||||
|
|
||||||
|
methods = self.parser.find_methods(obj_def)
|
||||||
|
methods = filter(lambda meth, self=self:
|
||||||
|
not self.overrides.is_ignored(meth.c_name), methods)
|
||||||
|
if methods:
|
||||||
|
self.write_heading('Methods', fp)
|
||||||
|
for method in methods:
|
||||||
|
self.write_method(method, self.docs.get(method.c_name, None), fp)
|
||||||
|
self.close_section(fp)
|
||||||
|
|
||||||
|
self.write_class_footer(obj_def.c_name, fp)
|
||||||
|
|
||||||
|
def output_interface_docs(self, int_def, fp=sys.stdout):
|
||||||
|
self.write_class_header(int_def.c_name, fp)
|
||||||
|
|
||||||
|
self.write_heading('Synopsis', fp)
|
||||||
|
self.write_synopsis(int_def, fp)
|
||||||
|
self.close_section(fp)
|
||||||
|
|
||||||
|
methods = self.parser.find_methods(int_def)
|
||||||
|
methods = filter(lambda meth, self=self:
|
||||||
|
not self.overrides.is_ignored(meth.c_name), methods)
|
||||||
|
if methods:
|
||||||
|
self.write_heading('Methods', fp)
|
||||||
|
for method in methods:
|
||||||
|
self.write_method(method, self.docs.get(method.c_name, None), fp)
|
||||||
|
self.close_section(fp)
|
||||||
|
|
||||||
|
self.write_class_footer(int_def.c_name, fp)
|
||||||
|
|
||||||
|
def output_boxed_docs(self, box_def, fp=sys.stdout):
|
||||||
|
self.write_class_header(box_def.c_name, fp)
|
||||||
|
|
||||||
|
self.write_heading('Synopsis', fp)
|
||||||
|
self.write_synopsis(box_def, fp)
|
||||||
|
self.close_section(fp)
|
||||||
|
|
||||||
|
constructor = self.parser.find_constructor(box_def, self.overrides)
|
||||||
|
if constructor:
|
||||||
|
self.write_heading('Constructor', fp)
|
||||||
|
self.write_constructor(constructor,
|
||||||
|
self.docs.get(constructor.c_name, None),
|
||||||
|
fp)
|
||||||
|
self.close_section(fp)
|
||||||
|
|
||||||
|
methods = self.parser.find_methods(box_def)
|
||||||
|
methods = filter(lambda meth, self=self:
|
||||||
|
not self.overrides.is_ignored(meth.c_name), methods)
|
||||||
|
if methods:
|
||||||
|
self.write_heading('Methods', fp)
|
||||||
|
for method in methods:
|
||||||
|
self.write_method(method, self.docs.get(method.c_name, None), fp)
|
||||||
|
self.close_section(fp)
|
||||||
|
|
||||||
|
self.write_class_footer(box_def.c_name, fp)
|
||||||
|
|
||||||
|
def output_toc(self, files, fp=sys.stdout):
|
||||||
|
fp.write('TOC\n\n')
|
||||||
|
for filename, obj_def in files:
|
||||||
|
fp.write(obj_def.c_name + ' - ' + filename + '\n')
|
||||||
|
|
||||||
|
# override the following to create a more complex output format
|
||||||
|
def create_filename(self, obj_name, output_prefix):
|
||||||
|
'''Create output filename for this particular object'''
|
||||||
|
return output_prefix + '-' + string.lower(obj_name) + '.txt'
|
||||||
|
def create_toc_filename(self, output_prefix):
|
||||||
|
return self.create_filename(self, 'docs', output_prefix)
|
||||||
|
|
||||||
|
def write_full_hierarchy(self, hierarchy, fp):
|
||||||
|
def handle_node(node, fp, indent=''):
|
||||||
|
for child in node.subclasses:
|
||||||
|
fp.write(indent + node.name)
|
||||||
|
if node.interfaces:
|
||||||
|
fp.write(' (implements ')
|
||||||
|
fp.write(string.join(node.interfaces, ', '))
|
||||||
|
fp.write(')\n')
|
||||||
|
else:
|
||||||
|
fp.write('\n')
|
||||||
|
handle_node(child, fp, indent + ' ')
|
||||||
|
handle_node(hierarchy, fp)
|
||||||
|
|
||||||
|
# these need to handle default args ...
|
||||||
|
def create_constructor_prototype(self, func_def):
|
||||||
|
return func_def.is_constructor_of + '(' + \
|
||||||
|
string.join(map(lambda x: x[1], func_def.params), ', ') + \
|
||||||
|
')'
|
||||||
|
def create_function_prototype(self, func_def):
|
||||||
|
return func_def.name + '(' + \
|
||||||
|
string.join(map(lambda x: x[1], func_def.params), ', ') + \
|
||||||
|
')'
|
||||||
|
def create_method_prototype(self, meth_def):
|
||||||
|
return meth_def.of_object + '.' + \
|
||||||
|
meth_def.name + '(' + \
|
||||||
|
string.join(map(lambda x: x[1], meth_def.params), ', ') + \
|
||||||
|
')'
|
||||||
|
|
||||||
|
def write_class_header(self, obj_name, fp):
|
||||||
|
fp.write('Class %s\n' % obj_name)
|
||||||
|
fp.write('======%s\n\n' % ('=' * len(obj_name)))
|
||||||
|
def write_class_footer(self, obj_name, fp):
|
||||||
|
pass
|
||||||
|
def write_heading(self, text, fp):
|
||||||
|
fp.write('\n' + text + '\n' + ('-' * len(text)) + '\n')
|
||||||
|
def close_section(self, fp):
|
||||||
|
pass
|
||||||
|
def write_synopsis(self, obj_def, fp):
|
||||||
|
fp.write('class %s' % obj_def.c_name)
|
||||||
|
if isinstance(obj_def, definitions.ObjectDef):
|
||||||
|
bases = []
|
||||||
|
if obj_def.parent: bases.append(obj_def.parent)
|
||||||
|
bases = bases = obj_def.implements
|
||||||
|
if bases:
|
||||||
|
fp.write('(%s)' % string.join(bases, ', '))
|
||||||
|
fp.write(':\n')
|
||||||
|
|
||||||
|
constructor = self.parser.find_constructor(obj_def, self.overrides)
|
||||||
|
if constructor:
|
||||||
|
prototype = self.create_constructor_prototype(constructor)
|
||||||
|
fp.write(' def %s\n' % prototype)
|
||||||
|
methods = self.parser.find_methods(obj_def)
|
||||||
|
methods = filter(lambda meth, self=self:
|
||||||
|
not self.overrides.is_ignored(meth.c_name), methods)
|
||||||
|
for meth in methods:
|
||||||
|
prototype = self.create_method_prototype(meth)
|
||||||
|
fp.write(' def %s\n' % prototype)
|
||||||
|
|
||||||
|
def write_hierarchy(self, obj_name, ancestry, fp):
|
||||||
|
indent = ''
|
||||||
|
for name, interfaces in ancestry:
|
||||||
|
fp.write(indent + '+-- ' + name)
|
||||||
|
if interfaces:
|
||||||
|
fp.write(' (implements ')
|
||||||
|
fp.write(string.join(interfaces, ', '))
|
||||||
|
fp.write(')\n')
|
||||||
|
else:
|
||||||
|
fp.write('\n')
|
||||||
|
indent = indent + ' '
|
||||||
|
fp.write('\n')
|
||||||
|
def write_constructor(self, func_def, func_doc, fp):
|
||||||
|
prototype = self.create_constructor_prototype(func_def)
|
||||||
|
fp.write(prototype + '\n\n')
|
||||||
|
for type, name, dflt, null in func_def.params:
|
||||||
|
if func_doc:
|
||||||
|
descr = func_doc.get_param_description(name)
|
||||||
|
else:
|
||||||
|
descr = 'a ' + type
|
||||||
|
fp.write(' ' + name + ': ' + descr + '\n')
|
||||||
|
if func_def.ret and func_def.ret != 'none':
|
||||||
|
if func_doc and func_doc.ret:
|
||||||
|
descr = func_doc.ret
|
||||||
|
else:
|
||||||
|
descr = 'a ' + func_def.ret
|
||||||
|
fp.write(' Returns: ' + descr + '\n')
|
||||||
|
if func_doc and func_doc.description:
|
||||||
|
fp.write(func_doc.description)
|
||||||
|
fp.write('\n\n\n')
|
||||||
|
def write_method(self, meth_def, func_doc, fp):
|
||||||
|
prototype = self.create_method_prototype(meth_def)
|
||||||
|
fp.write(prototype + '\n\n')
|
||||||
|
for type, name, dflt, null in meth_def.params:
|
||||||
|
if func_doc:
|
||||||
|
descr = func_doc.get_param_description(name)
|
||||||
|
else:
|
||||||
|
descr = 'a ' + type
|
||||||
|
fp.write(' ' + name + ': ' + descr + '\n')
|
||||||
|
if meth_def.ret and meth_def.ret != 'none':
|
||||||
|
if func_doc and func_doc.ret:
|
||||||
|
descr = func_doc.ret
|
||||||
|
else:
|
||||||
|
descr = 'a ' + meth_def.ret
|
||||||
|
fp.write(' Returns: ' + descr + '\n')
|
||||||
|
if func_doc and func_doc.description:
|
||||||
|
fp.write('\n')
|
||||||
|
fp.write(func_doc.description)
|
||||||
|
fp.write('\n\n')
|
||||||
|
|
||||||
|
class DocbookDocWriter(DocWriter):
|
||||||
|
def __init__(self, use_xml=0):
|
||||||
|
DocWriter.__init__(self)
|
||||||
|
self.use_xml = use_xml
|
||||||
|
|
||||||
|
def create_filename(self, obj_name, output_prefix):
|
||||||
|
'''Create output filename for this particular object'''
|
||||||
|
stem = output_prefix + '-' + string.lower(obj_name)
|
||||||
|
if self.use_xml:
|
||||||
|
return stem + '.xml'
|
||||||
|
else:
|
||||||
|
return stem + '.sgml'
|
||||||
|
def create_toc_filename(self, output_prefix):
|
||||||
|
if self.use_xml:
|
||||||
|
return self.create_filename('classes', output_prefix)
|
||||||
|
else:
|
||||||
|
return self.create_filename('docs', output_prefix)
|
||||||
|
|
||||||
|
# make string -> reference translation func
|
||||||
|
__transtable = [ '-' ] * 256
|
||||||
|
for digit in '0123456789':
|
||||||
|
__transtable[ord(digit)] = digit
|
||||||
|
for letter in 'abcdefghijklmnopqrstuvwxyz':
|
||||||
|
__transtable[ord(letter)] = letter
|
||||||
|
__transtable[ord(string.upper(letter))] = letter
|
||||||
|
__transtable = string.join(__transtable, '')
|
||||||
|
|
||||||
|
def make_class_ref(self, obj_name):
|
||||||
|
return 'class-' + string.translate(obj_name, self.__transtable)
|
||||||
|
def make_method_ref(self, meth_def):
|
||||||
|
return 'method-' + string.translate(meth_def.of_object,
|
||||||
|
self.__transtable) + \
|
||||||
|
'--' + string.translate(meth_def.name, self.__transtable)
|
||||||
|
|
||||||
|
__function_pat = re.compile(r'(\w+)\s*\(\)')
|
||||||
|
def __format_function(self, match):
|
||||||
|
info = self.parser.c_name.get(match.group(1), None)
|
||||||
|
if info:
|
||||||
|
if isinstance(info, defsparser.FunctionDef):
|
||||||
|
if info.is_constructor_of is not None:
|
||||||
|
# should have a link here
|
||||||
|
return '<function>%s()</function>' % \
|
||||||
|
self.pyname(info.is_constructor_of)
|
||||||
|
else:
|
||||||
|
return '<function>' + info.name + '()</function>'
|
||||||
|
if isinstance(info, defsparser.MethodDef):
|
||||||
|
return '<link linkend="' + self.make_method_ref(info) + \
|
||||||
|
'"><function>' + self.pyname(info.of_object) + '.' + \
|
||||||
|
info.name + '()</function></link>'
|
||||||
|
# fall through through
|
||||||
|
return '<function>' + match.group(1) + '()</function>'
|
||||||
|
__parameter_pat = re.compile(r'\@(\w+)')
|
||||||
|
def __format_param(self, match):
|
||||||
|
return '<parameter>' + match.group(1) + '</parameter>'
|
||||||
|
__constant_pat = re.compile(r'\%(-?\w+)')
|
||||||
|
def __format_const(self, match):
|
||||||
|
return '<literal>' + match.group(1) + '</literal>'
|
||||||
|
__symbol_pat = re.compile(r'#([\w-]+)')
|
||||||
|
def __format_symbol(self, match):
|
||||||
|
info = self.parser.c_name.get(match.group(1), None)
|
||||||
|
if info:
|
||||||
|
if isinstance(info, defsparser.FunctionDef):
|
||||||
|
if info.is_constructor_of is not None:
|
||||||
|
# should have a link here
|
||||||
|
return '<methodname>' + self.pyname(info.is_constructor_of) + \
|
||||||
|
'</methodname>'
|
||||||
|
else:
|
||||||
|
return '<function>' + info.name + '</function>'
|
||||||
|
if isinstance(info, defsparser.MethodDef):
|
||||||
|
return '<link linkend="' + self.make_method_ref(info) + \
|
||||||
|
'"><methodname>' + self.pyname(info.of_object) + '.' + \
|
||||||
|
info.name + '</methodname></link>'
|
||||||
|
if isinstance(info, defsparser.ObjectDef) or \
|
||||||
|
isinstance(info, defsparser.InterfaceDef) or \
|
||||||
|
isinstance(info, defsparser.BoxedDef) or \
|
||||||
|
isinstance(info, defsparser.PointerDef):
|
||||||
|
return '<link linkend="' + self.make_class_ref(info.c_name) + \
|
||||||
|
'"><classname>' + self.pyname(info.c_name) + \
|
||||||
|
'</classname></link>'
|
||||||
|
# fall through through
|
||||||
|
return '<literal>' + match.group(1) + '</literal>'
|
||||||
|
|
||||||
|
def reformat_text(self, text, singleline=0):
|
||||||
|
# replace special strings ...
|
||||||
|
text = self.__function_pat.sub(self.__format_function, text)
|
||||||
|
text = self.__parameter_pat.sub(self.__format_param, text)
|
||||||
|
text = self.__constant_pat.sub(self.__format_const, text)
|
||||||
|
text = self.__symbol_pat.sub(self.__format_symbol, text)
|
||||||
|
|
||||||
|
# don't bother with <para> expansion for single line text.
|
||||||
|
if singleline: return text
|
||||||
|
|
||||||
|
lines = string.split(string.strip(text), '\n')
|
||||||
|
for index in range(len(lines)):
|
||||||
|
if string.strip(lines[index]) == '':
|
||||||
|
lines[index] = '</para>\n<para>'
|
||||||
|
continue
|
||||||
|
lines.insert(0, '<para>')
|
||||||
|
lines.append('</para>')
|
||||||
|
return string.join(lines, '\n')
|
||||||
|
|
||||||
|
# write out hierarchy
|
||||||
|
def write_full_hierarchy(self, hierarchy, fp):
|
||||||
|
def handle_node(node, fp, indent=''):
|
||||||
|
if node.name:
|
||||||
|
fp.write('%s<link linkend="%s">%s</link>' %
|
||||||
|
(indent, self.make_class_ref(node.name),
|
||||||
|
self.pyname(node.name)))
|
||||||
|
if node.interfaces:
|
||||||
|
fp.write(' (implements ')
|
||||||
|
for i in range(len(node.interfaces)):
|
||||||
|
fp.write('<link linkend="%s">%s</link>' %
|
||||||
|
(self.make_class_ref(node.interfaces[i]),
|
||||||
|
self.pyname(node.interfaces[i])))
|
||||||
|
if i != len(node.interfaces) - 1:
|
||||||
|
fp.write(', ')
|
||||||
|
fp.write(')\n')
|
||||||
|
else:
|
||||||
|
fp.write('\n')
|
||||||
|
|
||||||
|
indent = indent + ' '
|
||||||
|
node.subclasses.sort(lambda a,b:
|
||||||
|
cmp(self.pyname(a.name), self.pyname(b.name)))
|
||||||
|
for child in node.subclasses:
|
||||||
|
handle_node(child, fp, indent)
|
||||||
|
if self.use_xml:
|
||||||
|
fp.write('<?xml version="1.0" standalone="no"?>\n')
|
||||||
|
fp.write('<!DOCTYPE synopsis PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
|
||||||
|
fp.write(' "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
|
||||||
|
fp.write('<synopsis>')
|
||||||
|
handle_node(hierarchy, fp)
|
||||||
|
fp.write('</synopsis>\n')
|
||||||
|
|
||||||
|
# these need to handle default args ...
|
||||||
|
def create_constructor_prototype(self, func_def):
|
||||||
|
sgml = [ '<constructorsynopsis language="python">\n']
|
||||||
|
sgml.append(' <methodname>__init__</methodname>\n')
|
||||||
|
for type, name, dflt, null in func_def.params:
|
||||||
|
sgml.append(' <methodparam><parameter>')
|
||||||
|
sgml.append(name)
|
||||||
|
sgml.append('</parameter>')
|
||||||
|
if dflt:
|
||||||
|
sgml.append('<initializer>')
|
||||||
|
sgml.append(dflt)
|
||||||
|
sgml.append('</initializer>')
|
||||||
|
sgml.append('</methodparam>\n')
|
||||||
|
if not func_def.params:
|
||||||
|
sgml.append(' <methodparam></methodparam>')
|
||||||
|
sgml.append(' </constructorsynopsis>')
|
||||||
|
return string.join(sgml, '')
|
||||||
|
def create_function_prototype(self, func_def):
|
||||||
|
sgml = [ '<funcsynopsis language="python">\n <funcprototype>\n']
|
||||||
|
sgml.append(' <funcdef><function>')
|
||||||
|
sgml.append(func_def.name)
|
||||||
|
sgml.append('</function></funcdef>\n')
|
||||||
|
for type, name, dflt, null in func_def.params:
|
||||||
|
sgml.append(' <paramdef><parameter>')
|
||||||
|
sgml.append(name)
|
||||||
|
sgml.append('</parameter>')
|
||||||
|
if dflt:
|
||||||
|
sgml.append('<initializer>')
|
||||||
|
sgml.append(dflt)
|
||||||
|
sgml.append('</initializer>')
|
||||||
|
sgml.append('</paramdef>\n')
|
||||||
|
if not func_def.params:
|
||||||
|
sgml.append(' <paramdef></paramdef')
|
||||||
|
sgml.append(' </funcprototype>\n </funcsynopsis>')
|
||||||
|
return string.join(sgml, '')
|
||||||
|
def create_method_prototype(self, meth_def, addlink=0):
|
||||||
|
sgml = [ '<methodsynopsis language="python">\n']
|
||||||
|
sgml.append(' <methodname>')
|
||||||
|
if addlink:
|
||||||
|
sgml.append('<link linkend="%s">' % self.make_method_ref(meth_def))
|
||||||
|
sgml.append(self.pyname(meth_def.name))
|
||||||
|
if addlink:
|
||||||
|
sgml.append('</link>')
|
||||||
|
sgml.append('</methodname>\n')
|
||||||
|
for type, name, dflt, null in meth_def.params:
|
||||||
|
sgml.append(' <methodparam><parameter>')
|
||||||
|
sgml.append(name)
|
||||||
|
sgml.append('</parameter>')
|
||||||
|
if dflt:
|
||||||
|
sgml.append('<initializer>')
|
||||||
|
sgml.append(dflt)
|
||||||
|
sgml.append('</initializer>')
|
||||||
|
sgml.append('</methodparam>\n')
|
||||||
|
if not meth_def.params:
|
||||||
|
sgml.append(' <methodparam></methodparam>')
|
||||||
|
sgml.append(' </methodsynopsis>')
|
||||||
|
return string.join(sgml, '')
|
||||||
|
|
||||||
|
def write_class_header(self, obj_name, fp):
|
||||||
|
if self.use_xml:
|
||||||
|
fp.write('<?xml version="1.0" standalone="no"?>\n')
|
||||||
|
fp.write('<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
|
||||||
|
fp.write(' "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
|
||||||
|
fp.write('<refentry id="' + self.make_class_ref(obj_name) + '">\n')
|
||||||
|
fp.write(' <refmeta>\n')
|
||||||
|
fp.write(' <refentrytitle>%s</refentrytitle>\n'
|
||||||
|
% self.pyname(obj_name))
|
||||||
|
fp.write(' <manvolnum>3</manvolnum>\n')
|
||||||
|
fp.write(' <refmiscinfo>PyGTK Docs</refmiscinfo>\n')
|
||||||
|
fp.write(' </refmeta>\n\n')
|
||||||
|
fp.write(' <refnamediv>\n')
|
||||||
|
fp.write(' <refname>%s</refname><refpurpose></refpurpose>\n'
|
||||||
|
% self.pyname(obj_name))
|
||||||
|
fp.write(' </refnamediv>\n\n')
|
||||||
|
def write_class_footer(self, obj_name, fp):
|
||||||
|
fp.write('</refentry>\n')
|
||||||
|
def write_heading(self, text, fp):
|
||||||
|
fp.write(' <refsect1>\n')
|
||||||
|
fp.write(' <title>' + text + '</title>\n\n')
|
||||||
|
def close_section(self, fp):
|
||||||
|
fp.write(' </refsect1>\n')
|
||||||
|
|
||||||
|
def write_synopsis(self, obj_def, fp):
|
||||||
|
fp.write('<classsynopsis language="python">\n')
|
||||||
|
fp.write(' <ooclass><classname>%s</classname></ooclass>\n'
|
||||||
|
% self.pyname(obj_def.c_name))
|
||||||
|
if isinstance(obj_def, definitions.ObjectDef):
|
||||||
|
if obj_def.parent:
|
||||||
|
fp.write(' <ooclass><classname><link linkend="%s">%s'
|
||||||
|
'</link></classname></ooclass>\n'
|
||||||
|
% (self.make_class_ref(obj_def.parent),
|
||||||
|
self.pyname(obj_def.parent)))
|
||||||
|
for base in obj_def.implements:
|
||||||
|
fp.write(' <ooclass><classname><link linkend="%s">%s'
|
||||||
|
'</link></classname></ooclass>\n'
|
||||||
|
% (self.make_class_ref(base), self.pyname(base)))
|
||||||
|
elif isinstance(obj_def, definitions.InterfaceDef):
|
||||||
|
fp.write(' <ooclass><classname>gobject.GInterface'
|
||||||
|
'</classname></ooclass>\n')
|
||||||
|
elif isinstance(obj_def, definitions.BoxedDef):
|
||||||
|
fp.write(' <ooclass><classname>gobject.GBoxed'
|
||||||
|
'</classname></ooclass>\n')
|
||||||
|
elif isinstance(obj_def, definitions.PointerDef):
|
||||||
|
fp.write(' <ooclass><classname>gobject.GPointer'
|
||||||
|
'</classname></ooclass>\n')
|
||||||
|
|
||||||
|
constructor = self.parser.find_constructor(obj_def, self.overrides)
|
||||||
|
if constructor:
|
||||||
|
fp.write('%s\n' % self.create_constructor_prototype(constructor))
|
||||||
|
methods = self.parser.find_methods(obj_def)
|
||||||
|
methods = filter(lambda meth, self=self:
|
||||||
|
not self.overrides.is_ignored(meth.c_name), methods)
|
||||||
|
for meth in methods:
|
||||||
|
fp.write('%s\n' % self.create_method_prototype(meth, addlink=1))
|
||||||
|
fp.write('</classsynopsis>\n\n')
|
||||||
|
|
||||||
|
def write_hierarchy(self, obj_name, ancestry, fp):
|
||||||
|
fp.write('<synopsis>')
|
||||||
|
indent = ''
|
||||||
|
for name, interfaces in ancestry:
|
||||||
|
fp.write(indent + '+-- <link linkend="' +
|
||||||
|
self.make_class_ref(name) + '">'+ self.pyname(name) + '</link>')
|
||||||
|
if interfaces:
|
||||||
|
fp.write(' (implements ')
|
||||||
|
for i in range(len(interfaces)):
|
||||||
|
fp.write('<link linkend="%s">%s</link>' %
|
||||||
|
(self.make_class_ref(interfaces[i]),
|
||||||
|
self.pyname(interfaces[i])))
|
||||||
|
if i != len(interfaces) - 1:
|
||||||
|
fp.write(', ')
|
||||||
|
fp.write(')\n')
|
||||||
|
else:
|
||||||
|
fp.write('\n')
|
||||||
|
indent = indent + ' '
|
||||||
|
fp.write('</synopsis>\n\n')
|
||||||
|
|
||||||
|
def write_params(self, params, ret, func_doc, fp):
|
||||||
|
if not params and (not ret or ret == 'none'):
|
||||||
|
return
|
||||||
|
fp.write(' <variablelist>\n')
|
||||||
|
for type, name, dflt, null in params:
|
||||||
|
if func_doc:
|
||||||
|
descr = string.strip(func_doc.get_param_description(name))
|
||||||
|
else:
|
||||||
|
descr = 'a ' + type
|
||||||
|
fp.write(' <varlistentry>\n')
|
||||||
|
fp.write(' <term><parameter>%s</parameter> :</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> :</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)
|
12
bindings/python/codegen/fileprefix.override
Normal file
12
bindings/python/codegen/fileprefix.override
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/* -*- Mode: C; c-basic-offset: 4 -*- */
|
||||||
|
%%
|
||||||
|
headers
|
||||||
|
/* include any required headers here */
|
||||||
|
%%
|
||||||
|
init
|
||||||
|
/* include any code here that needs to be executed before the
|
||||||
|
* extension classes get initialised */
|
||||||
|
%%
|
||||||
|
|
||||||
|
/* you should add appropriate ignore, ignore-glob and
|
||||||
|
* override sections here */
|
31
bindings/python/codegen/fileprefixmodule.c
Normal file
31
bindings/python/codegen/fileprefixmodule.c
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/* -*- Mode: C; c-basic-offset: 4 -*- */
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
#include <Python.h>
|
||||||
|
#include <pygtk.h>
|
||||||
|
|
||||||
|
/* include any extra headers needed here */
|
||||||
|
|
||||||
|
void prefix_register_classes(PyObject *d);
|
||||||
|
extern PyMethodDef prefix_functions[];
|
||||||
|
|
||||||
|
DL_EXPORT(void)
|
||||||
|
initmodule(void)
|
||||||
|
{
|
||||||
|
PyObject *m, *d;
|
||||||
|
|
||||||
|
/* perform any initialisation required by the library here */
|
||||||
|
|
||||||
|
m = Py_InitModule("module", prefix_functions);
|
||||||
|
d = PyModule_GetDict(m);
|
||||||
|
|
||||||
|
init_pygtk();
|
||||||
|
|
||||||
|
prefix_register_classes(d);
|
||||||
|
|
||||||
|
/* add anything else to the module dictionary (such as constants) */
|
||||||
|
|
||||||
|
if (PyErr_Occurred())
|
||||||
|
Py_FatalError("could not initialise module module");
|
||||||
|
}
|
536
bindings/python/codegen/h2def.py
Executable file
536
bindings/python/codegen/h2def.py
Executable file
|
@ -0,0 +1,536 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||||
|
# Search through a header file looking for function prototypes.
|
||||||
|
# For each prototype, generate a scheme style definition.
|
||||||
|
# GPL'ed
|
||||||
|
# Toby D. Reeves <toby@max.rl.plh.af.mil>
|
||||||
|
#
|
||||||
|
# Modified by James Henstridge <james@daa.com.au> to output stuff in
|
||||||
|
# Havoc's new defs format. Info on this format can be seen at:
|
||||||
|
# http://www.gnome.org/mailing-lists/archives/gtk-devel-list/2000-January/0085.shtml
|
||||||
|
# Updated to be PEP-8 compatible and refactored to use OOP
|
||||||
|
|
||||||
|
import getopt
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import string
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import defsparser
|
||||||
|
|
||||||
|
# ------------------ Create typecodes from typenames ---------
|
||||||
|
|
||||||
|
_upperstr_pat1 = re.compile(r'([^A-Z])([A-Z])')
|
||||||
|
_upperstr_pat2 = re.compile(r'([A-Z][A-Z])([A-Z][0-9a-z])')
|
||||||
|
_upperstr_pat3 = re.compile(r'^([A-Z])([A-Z])')
|
||||||
|
|
||||||
|
def to_upper_str(name):
|
||||||
|
"""Converts a typename to the equivalent upercase and underscores
|
||||||
|
name. This is used to form the type conversion macros and enum/flag
|
||||||
|
name variables"""
|
||||||
|
name = _upperstr_pat1.sub(r'\1_\2', name)
|
||||||
|
name = _upperstr_pat2.sub(r'\1_\2', name)
|
||||||
|
name = _upperstr_pat3.sub(r'\1_\2', name, count=1)
|
||||||
|
return string.upper(name)
|
||||||
|
|
||||||
|
def typecode(typename):
|
||||||
|
"""create a typecode (eg. GTK_TYPE_WIDGET) from a typename"""
|
||||||
|
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
|
||||||
|
|
||||||
|
# ------------------ Find enum definitions -----------------
|
||||||
|
|
||||||
|
def find_enum_defs(buf, enums=[]):
|
||||||
|
# strip comments
|
||||||
|
# bulk comments
|
||||||
|
buf = strip_comments(buf)
|
||||||
|
|
||||||
|
buf = re.sub('\n', ' ', buf)
|
||||||
|
|
||||||
|
enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)')
|
||||||
|
splitter = re.compile(r'\s*,\s', re.MULTILINE)
|
||||||
|
pos = 0
|
||||||
|
while pos < len(buf):
|
||||||
|
m = enum_pat.search(buf, pos)
|
||||||
|
if not m: break
|
||||||
|
|
||||||
|
name = m.group(2)
|
||||||
|
vals = m.group(1)
|
||||||
|
isflags = string.find(vals, '<<') >= 0
|
||||||
|
entries = []
|
||||||
|
for val in splitter.split(vals):
|
||||||
|
if not string.strip(val): continue
|
||||||
|
entries.append(string.split(val)[0])
|
||||||
|
if name != 'GdkCursorType':
|
||||||
|
enums.append((name, isflags, entries))
|
||||||
|
|
||||||
|
pos = m.end()
|
||||||
|
|
||||||
|
# ------------------ Find function definitions -----------------
|
||||||
|
|
||||||
|
def clean_func(buf):
|
||||||
|
"""
|
||||||
|
Ideally would make buf have a single prototype on each line.
|
||||||
|
Actually just cuts out a good deal of junk, but leaves lines
|
||||||
|
where a regex can figure prototypes out.
|
||||||
|
"""
|
||||||
|
# bulk comments
|
||||||
|
buf = strip_comments(buf)
|
||||||
|
|
||||||
|
# compact continued lines
|
||||||
|
pat = re.compile(r"""\\\n""", re.MULTILINE)
|
||||||
|
buf = pat.sub('', buf)
|
||||||
|
|
||||||
|
# Preprocess directives
|
||||||
|
pat = re.compile(r"""^[#].*?$""", re.MULTILINE)
|
||||||
|
buf = pat.sub('', buf)
|
||||||
|
|
||||||
|
#typedefs, stucts, and enums
|
||||||
|
pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""",
|
||||||
|
re.MULTILINE)
|
||||||
|
buf = pat.sub('', buf)
|
||||||
|
|
||||||
|
#strip DECLS macros
|
||||||
|
pat = re.compile(r"""G_BEGIN_DECLS|BEGIN_LIBGTOP_DECLS""", re.MULTILINE)
|
||||||
|
buf = pat.sub('', buf)
|
||||||
|
|
||||||
|
#extern "C"
|
||||||
|
pat = re.compile(r"""^\s*(extern)\s+\"C\"\s+{""", re.MULTILINE)
|
||||||
|
buf = pat.sub('', buf)
|
||||||
|
|
||||||
|
#multiple whitespace
|
||||||
|
pat = re.compile(r"""\s+""", re.MULTILINE)
|
||||||
|
buf = pat.sub(' ', buf)
|
||||||
|
|
||||||
|
#clean up line ends
|
||||||
|
pat = re.compile(r""";\s*""", re.MULTILINE)
|
||||||
|
buf = pat.sub('\n', buf)
|
||||||
|
buf = buf.lstrip()
|
||||||
|
|
||||||
|
#associate *, &, and [] with type instead of variable
|
||||||
|
#pat = re.compile(r'\s+([*|&]+)\s*(\w+)')
|
||||||
|
pat = re.compile(r' \s* ([*|&]+) \s* (\w+)', re.VERBOSE)
|
||||||
|
buf = pat.sub(r'\1 \2', buf)
|
||||||
|
pat = re.compile(r'\s+ (\w+) \[ \s* \]', re.VERBOSE)
|
||||||
|
buf = pat.sub(r'[] \1', buf)
|
||||||
|
|
||||||
|
# make return types that are const work.
|
||||||
|
buf = string.replace(buf, 'G_CONST_RETURN ', 'const-')
|
||||||
|
buf = string.replace(buf, 'const ', 'const-')
|
||||||
|
|
||||||
|
return buf
|
||||||
|
|
||||||
|
proto_pat=re.compile(r"""
|
||||||
|
(?P<ret>(-|\w|\&|\*)+\s*) # return type
|
||||||
|
\s+ # skip whitespace
|
||||||
|
(?P<func>\w+)\s*[(] # match the function name until the opening (
|
||||||
|
\s*(?P<args>.*?)\s*[)] # group the function arguments
|
||||||
|
""", re.IGNORECASE|re.VERBOSE)
|
||||||
|
#"""
|
||||||
|
arg_split_pat = re.compile("\s*,\s*")
|
||||||
|
|
||||||
|
get_type_pat = re.compile(r'(const-)?([A-Za-z0-9]+)\*?\s+')
|
||||||
|
pointer_pat = re.compile('.*\*$')
|
||||||
|
func_new_pat = re.compile('(\w+)_new$')
|
||||||
|
|
||||||
|
class DefsWriter:
|
||||||
|
def __init__(self, fp=None, prefix=None, verbose=False,
|
||||||
|
defsfilter=None):
|
||||||
|
if not fp:
|
||||||
|
fp = sys.stdout
|
||||||
|
|
||||||
|
self.fp = fp
|
||||||
|
self.prefix = prefix
|
||||||
|
self.verbose = verbose
|
||||||
|
|
||||||
|
self._enums = {}
|
||||||
|
self._objects = {}
|
||||||
|
self._functions = {}
|
||||||
|
if defsfilter:
|
||||||
|
filter = defsparser.DefsParser(defsfilter)
|
||||||
|
filter.startParsing()
|
||||||
|
for func in filter.functions + filter.methods.values():
|
||||||
|
self._functions[func.c_name] = func
|
||||||
|
for obj in filter.objects + filter.boxes + filter.interfaces:
|
||||||
|
self._objects[obj.c_name] = func
|
||||||
|
for obj in filter.enums:
|
||||||
|
self._enums[obj.c_name] = func
|
||||||
|
|
||||||
|
def write_def(self, deffile):
|
||||||
|
buf = open(deffile).read()
|
||||||
|
|
||||||
|
self.fp.write('\n;; From %s\n\n' % os.path.basename(deffile))
|
||||||
|
self._define_func(buf)
|
||||||
|
self.fp.write('\n')
|
||||||
|
|
||||||
|
def write_enum_defs(self, enums, fp=None):
|
||||||
|
if not fp:
|
||||||
|
fp = self.fp
|
||||||
|
|
||||||
|
fp.write(';; Enumerations and flags ...\n\n')
|
||||||
|
trans = string.maketrans(string.uppercase + '_',
|
||||||
|
string.lowercase + '-')
|
||||||
|
filter = self._enums
|
||||||
|
for cname, isflags, entries in enums:
|
||||||
|
if filter:
|
||||||
|
if cname in filter:
|
||||||
|
continue
|
||||||
|
name = cname
|
||||||
|
module = None
|
||||||
|
m = split_prefix_pat.match(cname)
|
||||||
|
if m:
|
||||||
|
module = m.group(1)
|
||||||
|
name = m.group(2)
|
||||||
|
if isflags:
|
||||||
|
fp.write('(define-flags ' + name + '\n')
|
||||||
|
else:
|
||||||
|
fp.write('(define-enum ' + name + '\n')
|
||||||
|
if module:
|
||||||
|
fp.write(' (in-module "' + module + '")\n')
|
||||||
|
fp.write(' (c-name "' + cname + '")\n')
|
||||||
|
fp.write(' (gtype-id "' + typecode(cname) + '")\n')
|
||||||
|
prefix = entries[0]
|
||||||
|
for ent in entries:
|
||||||
|
# shorten prefix til we get a match ...
|
||||||
|
# and handle GDK_FONT_FONT, GDK_FONT_FONTSET case
|
||||||
|
while ent[:len(prefix)] != prefix or len(prefix) >= len(ent):
|
||||||
|
prefix = prefix[:-1]
|
||||||
|
prefix_len = len(prefix)
|
||||||
|
fp.write(' (values\n')
|
||||||
|
for ent in entries:
|
||||||
|
fp.write(' \'("%s" "%s")\n' %
|
||||||
|
(string.translate(ent[prefix_len:], trans), ent))
|
||||||
|
fp.write(' )\n')
|
||||||
|
fp.write(')\n\n')
|
||||||
|
|
||||||
|
def write_obj_defs(self, objdefs, fp=None):
|
||||||
|
if not fp:
|
||||||
|
fp = self.fp
|
||||||
|
|
||||||
|
fp.write(';; -*- scheme -*-\n')
|
||||||
|
fp.write('; object definitions ...\n')
|
||||||
|
|
||||||
|
filter = self._objects
|
||||||
|
for klass, parent in objdefs:
|
||||||
|
if filter:
|
||||||
|
if klass in filter:
|
||||||
|
continue
|
||||||
|
m = split_prefix_pat.match(klass)
|
||||||
|
cmodule = None
|
||||||
|
cname = klass
|
||||||
|
if m:
|
||||||
|
cmodule = m.group(1)
|
||||||
|
cname = m.group(2)
|
||||||
|
fp.write('(define-object ' + cname + '\n')
|
||||||
|
if cmodule:
|
||||||
|
fp.write(' (in-module "' + cmodule + '")\n')
|
||||||
|
if parent:
|
||||||
|
fp.write(' (parent "' + parent + '")\n')
|
||||||
|
fp.write(' (c-name "' + klass + '")\n')
|
||||||
|
fp.write(' (gtype-id "' + typecode(klass) + '")\n')
|
||||||
|
# should do something about accessible fields
|
||||||
|
fp.write(')\n\n')
|
||||||
|
|
||||||
|
def _define_func(self, buf):
|
||||||
|
buf = clean_func(buf)
|
||||||
|
buf = string.split(buf,'\n')
|
||||||
|
filter = self._functions
|
||||||
|
for p in buf:
|
||||||
|
if not p:
|
||||||
|
continue
|
||||||
|
m = proto_pat.match(p)
|
||||||
|
if m == None:
|
||||||
|
if self.verbose:
|
||||||
|
sys.stderr.write('No match:|%s|\n' % p)
|
||||||
|
continue
|
||||||
|
func = m.group('func')
|
||||||
|
if func[0] == '_':
|
||||||
|
continue
|
||||||
|
if filter:
|
||||||
|
if func in filter:
|
||||||
|
continue
|
||||||
|
ret = m.group('ret')
|
||||||
|
args = m.group('args')
|
||||||
|
args = arg_split_pat.split(args)
|
||||||
|
for i in range(len(args)):
|
||||||
|
spaces = string.count(args[i], ' ')
|
||||||
|
if spaces > 1:
|
||||||
|
args[i] = string.replace(args[i], ' ', '-', spaces - 1)
|
||||||
|
|
||||||
|
self._write_func(func, ret, args)
|
||||||
|
|
||||||
|
def _write_func(self, name, ret, args):
|
||||||
|
if len(args) >= 1:
|
||||||
|
# methods must have at least one argument
|
||||||
|
munged_name = name.replace('_', '')
|
||||||
|
m = get_type_pat.match(args[0])
|
||||||
|
if m:
|
||||||
|
obj = m.group(2)
|
||||||
|
if munged_name[:len(obj)] == obj.lower():
|
||||||
|
self._write_method(obj, name, ret, args)
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.prefix:
|
||||||
|
l = len(self.prefix)
|
||||||
|
if name[:l] == self.prefix and name[l] == '_':
|
||||||
|
fname = name[l+1:]
|
||||||
|
else:
|
||||||
|
fname = name
|
||||||
|
else:
|
||||||
|
fname = name
|
||||||
|
|
||||||
|
# it is either a constructor or normal function
|
||||||
|
self.fp.write('(define-function ' + fname + '\n')
|
||||||
|
self.fp.write(' (c-name "' + name + '")\n')
|
||||||
|
|
||||||
|
# Hmmm... Let's asume that a constructor function name
|
||||||
|
# ends with '_new' and it returns a pointer.
|
||||||
|
m = func_new_pat.match(name)
|
||||||
|
if pointer_pat.match(ret) and m:
|
||||||
|
cname = ''
|
||||||
|
for s in m.group(1).split ('_'):
|
||||||
|
cname += s.title()
|
||||||
|
if cname != '':
|
||||||
|
self.fp.write(' (is-constructor-of "' + cname + '")\n')
|
||||||
|
|
||||||
|
self._write_return(ret)
|
||||||
|
self._write_arguments(args)
|
||||||
|
|
||||||
|
def _write_method(self, obj, name, ret, args):
|
||||||
|
regex = string.join(map(lambda x: x+'_?', string.lower(obj)),'')
|
||||||
|
mname = re.sub(regex, '', name, 1)
|
||||||
|
if self.prefix:
|
||||||
|
l = len(self.prefix) + 1
|
||||||
|
if mname[:l] == self.prefix and mname[l+1] == '_':
|
||||||
|
mname = mname[l+1:]
|
||||||
|
self.fp.write('(define-method ' + mname + '\n')
|
||||||
|
self.fp.write(' (of-object "' + obj + '")\n')
|
||||||
|
self.fp.write(' (c-name "' + name + '")\n')
|
||||||
|
self._write_return(ret)
|
||||||
|
self._write_arguments(args[1:])
|
||||||
|
|
||||||
|
def _write_return(self, ret):
|
||||||
|
if ret != 'void':
|
||||||
|
self.fp.write(' (return-type "' + ret + '")\n')
|
||||||
|
else:
|
||||||
|
self.fp.write(' (return-type "none")\n')
|
||||||
|
|
||||||
|
def _write_arguments(self, args):
|
||||||
|
is_varargs = 0
|
||||||
|
has_args = len(args) > 0
|
||||||
|
for arg in args:
|
||||||
|
if arg == '...':
|
||||||
|
is_varargs = 1
|
||||||
|
elif arg in ('void', 'void '):
|
||||||
|
has_args = 0
|
||||||
|
if has_args:
|
||||||
|
self.fp.write(' (parameters\n')
|
||||||
|
for arg in args:
|
||||||
|
if arg != '...':
|
||||||
|
tupleArg = tuple(string.split(arg))
|
||||||
|
if len(tupleArg) == 2:
|
||||||
|
self.fp.write(' \'("%s" "%s")\n' % tupleArg)
|
||||||
|
self.fp.write(' )\n')
|
||||||
|
if is_varargs:
|
||||||
|
self.fp.write(' (varargs #t)\n')
|
||||||
|
self.fp.write(')\n\n')
|
||||||
|
|
||||||
|
# ------------------ Main function -----------------
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
verbose = False
|
||||||
|
onlyenums = False
|
||||||
|
onlyobjdefs = False
|
||||||
|
separate = False
|
||||||
|
modulename = None
|
||||||
|
defsfilter = None
|
||||||
|
opts, args = getopt.getopt(args[1:], 'vs:m:f:',
|
||||||
|
['onlyenums', 'onlyobjdefs',
|
||||||
|
'modulename=', 'separate=',
|
||||||
|
'defsfilter='])
|
||||||
|
for o, v in opts:
|
||||||
|
if o == '-v':
|
||||||
|
verbose = True
|
||||||
|
if o == '--onlyenums':
|
||||||
|
onlyenums = True
|
||||||
|
if o == '--onlyobjdefs':
|
||||||
|
onlyobjdefs = True
|
||||||
|
if o in ('-s', '--separate'):
|
||||||
|
separate = v
|
||||||
|
if o in ('-m', '--modulename'):
|
||||||
|
modulename = v
|
||||||
|
if o in ('-f', '--defsfilter'):
|
||||||
|
defsfilter = v
|
||||||
|
|
||||||
|
if not args[0:1]:
|
||||||
|
print 'Must specify at least one input file name'
|
||||||
|
return -1
|
||||||
|
|
||||||
|
# read all the object definitions in
|
||||||
|
objdefs = []
|
||||||
|
enums = []
|
||||||
|
for filename in args:
|
||||||
|
buf = open(filename).read()
|
||||||
|
find_obj_defs(buf, objdefs)
|
||||||
|
find_enum_defs(buf, enums)
|
||||||
|
objdefs = sort_obj_defs(objdefs)
|
||||||
|
|
||||||
|
if separate:
|
||||||
|
methods = file(separate + '.defs', 'w')
|
||||||
|
types = file(separate + '-types.defs', 'w')
|
||||||
|
|
||||||
|
dw = DefsWriter(methods, prefix=modulename, verbose=verbose,
|
||||||
|
defsfilter=defsfilter)
|
||||||
|
dw.write_obj_defs(objdefs, types)
|
||||||
|
dw.write_enum_defs(enums, types)
|
||||||
|
print "Wrote %s-types.defs" % separate
|
||||||
|
|
||||||
|
for filename in args:
|
||||||
|
dw.write_def(filename)
|
||||||
|
print "Wrote %s.defs" % separate
|
||||||
|
else:
|
||||||
|
dw = DefsWriter(prefix=modulename, verbose=verbose,
|
||||||
|
defsfilter=defsfilter)
|
||||||
|
|
||||||
|
if onlyenums:
|
||||||
|
dw.write_enum_defs(enums)
|
||||||
|
elif onlyobjdefs:
|
||||||
|
dw.write_obj_defs(objdefs)
|
||||||
|
else:
|
||||||
|
dw.write_obj_defs(objdefs)
|
||||||
|
dw.write_enum_defs(enums)
|
||||||
|
|
||||||
|
for filename in args:
|
||||||
|
dw.write_def(filename)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv))
|
26
bindings/python/codegen/mergedefs.py
Executable file
26
bindings/python/codegen/mergedefs.py
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||||
|
|
||||||
|
import optparse
|
||||||
|
|
||||||
|
import defsparser
|
||||||
|
|
||||||
|
parser = optparse.OptionParser(
|
||||||
|
usage="usage: %prog [options] generated-defs old-defs")
|
||||||
|
parser.add_option("-p", "--merge-parameters",
|
||||||
|
help="Merge changes in function/methods parameter lists",
|
||||||
|
action="store_true", dest="parmerge", default=False)
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
if len(args) != 2:
|
||||||
|
parser.error("wrong number of arguments")
|
||||||
|
|
||||||
|
newp = defsparser.DefsParser(args[0])
|
||||||
|
oldp = defsparser.DefsParser(args[1])
|
||||||
|
|
||||||
|
newp.startParsing()
|
||||||
|
oldp.startParsing()
|
||||||
|
|
||||||
|
newp.merge(oldp, options.parmerge)
|
||||||
|
|
||||||
|
newp.write_defs()
|
89
bindings/python/codegen/mkskel.py
Executable file
89
bindings/python/codegen/mkskel.py
Executable 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)
|
288
bindings/python/codegen/override.py
Normal file
288
bindings/python/codegen/override.py
Normal file
|
@ -0,0 +1,288 @@
|
||||||
|
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||||
|
|
||||||
|
# this file contains code for loading up an override file. The override file
|
||||||
|
# provides implementations of functions where the code generator could not
|
||||||
|
# do its job correctly.
|
||||||
|
|
||||||
|
import fnmatch
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import string
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def class2cname(klass, method):
|
||||||
|
c_name = ''
|
||||||
|
for c in klass:
|
||||||
|
if c.isupper():
|
||||||
|
c_name += '_' + c.lower()
|
||||||
|
else:
|
||||||
|
c_name += c
|
||||||
|
return c_name[1:] + '_' + method
|
||||||
|
|
||||||
|
import_pat = re.compile(r'\s*import\s+(\S+)\.([^\s.]+)\s+as\s+(\S+)')
|
||||||
|
|
||||||
|
class Overrides:
|
||||||
|
def __init__(self, filename=None, path=[]):
|
||||||
|
self.modulename = None
|
||||||
|
self.ignores = {}
|
||||||
|
self.glob_ignores = []
|
||||||
|
self.type_ignores = {}
|
||||||
|
self.overrides = {}
|
||||||
|
self.overridden = {}
|
||||||
|
self.kwargs = {}
|
||||||
|
self.noargs = {}
|
||||||
|
self.onearg = {}
|
||||||
|
self.staticmethod = {}
|
||||||
|
self.classmethod = {}
|
||||||
|
self.startlines = {}
|
||||||
|
self.override_attrs = {}
|
||||||
|
self.override_slots = {}
|
||||||
|
self.headers = ''
|
||||||
|
self.body = ''
|
||||||
|
self.init = ''
|
||||||
|
self.imports = []
|
||||||
|
self.defines = {}
|
||||||
|
self.functions = {}
|
||||||
|
self.newstyle_constructors = {}
|
||||||
|
self.path = [os.path.abspath(x) for x in path]
|
||||||
|
if filename:
|
||||||
|
self.handle_file(filename)
|
||||||
|
|
||||||
|
def handle_file(self, filename):
|
||||||
|
oldpath = os.getcwd()
|
||||||
|
|
||||||
|
fp = None
|
||||||
|
for path in self.path:
|
||||||
|
os.chdir(oldpath)
|
||||||
|
os.chdir(path)
|
||||||
|
try:
|
||||||
|
fp = open(filename, 'r')
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
os.chdir(oldpath)
|
||||||
|
if not fp:
|
||||||
|
raise Exception, "Couldn't find file %s" % filename
|
||||||
|
|
||||||
|
dirname = path
|
||||||
|
|
||||||
|
if dirname != oldpath:
|
||||||
|
os.chdir(dirname)
|
||||||
|
|
||||||
|
# read all the components of the file ...
|
||||||
|
bufs = []
|
||||||
|
startline = 1
|
||||||
|
lines = []
|
||||||
|
line = fp.readline()
|
||||||
|
linenum = 1
|
||||||
|
while line:
|
||||||
|
if line == '%%\n' or line == '%%':
|
||||||
|
if lines:
|
||||||
|
bufs.append((string.join(lines, ''), startline))
|
||||||
|
startline = linenum + 1
|
||||||
|
lines = []
|
||||||
|
else:
|
||||||
|
lines.append(line)
|
||||||
|
line = fp.readline()
|
||||||
|
linenum = linenum + 1
|
||||||
|
if lines:
|
||||||
|
bufs.append((string.join(lines, ''), startline))
|
||||||
|
if not bufs: return
|
||||||
|
|
||||||
|
for buf, startline in bufs:
|
||||||
|
self.__parse_override(buf, startline, filename)
|
||||||
|
|
||||||
|
os.chdir(oldpath)
|
||||||
|
|
||||||
|
def __parse_override(self, buffer, startline, filename):
|
||||||
|
pos = string.find(buffer, '\n')
|
||||||
|
if pos >= 0:
|
||||||
|
line = buffer[:pos]
|
||||||
|
rest = buffer[pos+1:]
|
||||||
|
else:
|
||||||
|
line = buffer ; rest = ''
|
||||||
|
words = string.split(line)
|
||||||
|
command = words[0]
|
||||||
|
if (command == 'ignore' or
|
||||||
|
command == 'ignore-' + sys.platform):
|
||||||
|
"ignore/ignore-platform [functions..]"
|
||||||
|
for func in words[1:]:
|
||||||
|
self.ignores[func] = 1
|
||||||
|
for func in string.split(rest):
|
||||||
|
self.ignores[func] = 1
|
||||||
|
elif (command == 'ignore-glob' or
|
||||||
|
command == 'ignore-glob-' + sys.platform):
|
||||||
|
"ignore-glob/ignore-glob-platform [globs..]"
|
||||||
|
for func in words[1:]:
|
||||||
|
self.glob_ignores.append(func)
|
||||||
|
for func in string.split(rest):
|
||||||
|
self.glob_ignores.append(func)
|
||||||
|
elif (command == 'ignore-type' or
|
||||||
|
command == 'ignore-type-' + sys.platform):
|
||||||
|
"ignore-type/ignore-type-platform [typenames..]"
|
||||||
|
for typename in words[1:]:
|
||||||
|
self.type_ignores[typename] = 1
|
||||||
|
for typename in string.split(rest):
|
||||||
|
self.type_ignores[typename] = 1
|
||||||
|
elif command == 'override':
|
||||||
|
"override function/method [kwargs|noargs|onearg] [staticmethod|classmethod]"
|
||||||
|
func = words[1]
|
||||||
|
if 'kwargs' in words[1:]:
|
||||||
|
self.kwargs[func] = 1
|
||||||
|
elif 'noargs' in words[1:]:
|
||||||
|
self.noargs[func] = 1
|
||||||
|
elif 'onearg' in words[1:]:
|
||||||
|
self.onearg[func] = True
|
||||||
|
|
||||||
|
if 'staticmethod' in words[1:]:
|
||||||
|
self.staticmethod[func] = True
|
||||||
|
elif 'classmethod' in words[1:]:
|
||||||
|
self.classmethod[func] = True
|
||||||
|
if func in self.overrides:
|
||||||
|
raise RuntimeError("Function %s is being overridden more than once" % (func,))
|
||||||
|
self.overrides[func] = rest
|
||||||
|
self.startlines[func] = (startline + 1, filename)
|
||||||
|
elif command == 'override-attr':
|
||||||
|
"override-slot Class.attr"
|
||||||
|
attr = words[1]
|
||||||
|
self.override_attrs[attr] = rest
|
||||||
|
self.startlines[attr] = (startline + 1, filename)
|
||||||
|
elif command == 'override-slot':
|
||||||
|
"override-slot Class.slot"
|
||||||
|
slot = words[1]
|
||||||
|
self.override_slots[slot] = rest
|
||||||
|
self.startlines[slot] = (startline + 1, filename)
|
||||||
|
elif command == 'headers':
|
||||||
|
"headers"
|
||||||
|
self.headers = '%s\n#line %d "%s"\n%s' % \
|
||||||
|
(self.headers, startline + 1, filename, rest)
|
||||||
|
elif command == 'body':
|
||||||
|
"body"
|
||||||
|
self.body = '%s\n#line %d "%s"\n%s' % \
|
||||||
|
(self.body, startline + 1, filename, rest)
|
||||||
|
elif command == 'init':
|
||||||
|
"init"
|
||||||
|
self.init = '%s\n#line %d "%s"\n%s' % \
|
||||||
|
(self.init, startline + 1, filename, rest)
|
||||||
|
elif command == 'modulename':
|
||||||
|
"modulename name"
|
||||||
|
self.modulename = words[1]
|
||||||
|
elif command == 'include':
|
||||||
|
"include filename"
|
||||||
|
for filename in words[1:]:
|
||||||
|
self.handle_file(filename)
|
||||||
|
for filename in string.split(rest):
|
||||||
|
self.handle_file(filename)
|
||||||
|
elif command == 'import':
|
||||||
|
"import module1 [\n module2, \n module3 ...]"
|
||||||
|
for line in string.split(buffer, '\n'):
|
||||||
|
match = import_pat.match(line)
|
||||||
|
if match:
|
||||||
|
self.imports.append(match.groups())
|
||||||
|
elif command == 'define':
|
||||||
|
"define funcname [kwargs|noargs|onearg] [classmethod|staticmethod]"
|
||||||
|
"define Class.method [kwargs|noargs|onearg] [classmethod|staticmethod]"
|
||||||
|
func = words[1]
|
||||||
|
klass = None
|
||||||
|
if func.find('.') != -1:
|
||||||
|
klass, func = func.split('.', 1)
|
||||||
|
|
||||||
|
if not self.defines.has_key(klass):
|
||||||
|
self.defines[klass] = {}
|
||||||
|
self.defines[klass][func] = rest
|
||||||
|
else:
|
||||||
|
self.functions[func] = rest
|
||||||
|
|
||||||
|
if 'kwargs' in words[1:]:
|
||||||
|
self.kwargs[func] = 1
|
||||||
|
elif 'noargs' in words[1:]:
|
||||||
|
self.noargs[func] = 1
|
||||||
|
elif 'onearg' in words[1:]:
|
||||||
|
self.onearg[func] = 1
|
||||||
|
|
||||||
|
if 'staticmethod' in words[1:]:
|
||||||
|
self.staticmethod[func] = True
|
||||||
|
elif 'classmethod' in words[1:]:
|
||||||
|
self.classmethod[func] = True
|
||||||
|
|
||||||
|
self.startlines[func] = (startline + 1, filename)
|
||||||
|
|
||||||
|
elif command == 'new-constructor':
|
||||||
|
"new-constructor GType"
|
||||||
|
gtype, = words[1:]
|
||||||
|
self.newstyle_constructors[gtype] = True
|
||||||
|
|
||||||
|
def is_ignored(self, name):
|
||||||
|
if self.ignores.has_key(name):
|
||||||
|
return 1
|
||||||
|
for glob in self.glob_ignores:
|
||||||
|
if fnmatch.fnmatchcase(name, glob):
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def is_type_ignored(self, name):
|
||||||
|
return name in self.type_ignores
|
||||||
|
|
||||||
|
def is_overriden(self, name):
|
||||||
|
return self.overrides.has_key(name)
|
||||||
|
|
||||||
|
def is_already_included(self, name):
|
||||||
|
return self.overridden.has_key(name)
|
||||||
|
|
||||||
|
def override(self, name):
|
||||||
|
self.overridden[name] = 1
|
||||||
|
return self.overrides[name]
|
||||||
|
|
||||||
|
def define(self, klass, name):
|
||||||
|
self.overridden[class2cname(klass, name)] = 1
|
||||||
|
return self.defines[klass][name]
|
||||||
|
|
||||||
|
def function(self, name):
|
||||||
|
return self.functions[name]
|
||||||
|
|
||||||
|
def getstartline(self, name):
|
||||||
|
return self.startlines[name]
|
||||||
|
|
||||||
|
def wants_kwargs(self, name):
|
||||||
|
return self.kwargs.has_key(name)
|
||||||
|
|
||||||
|
def wants_noargs(self, name):
|
||||||
|
return self.noargs.has_key(name)
|
||||||
|
|
||||||
|
def wants_onearg(self, name):
|
||||||
|
return self.onearg.has_key(name)
|
||||||
|
|
||||||
|
def is_staticmethod(self, name):
|
||||||
|
return self.staticmethod.has_key(name)
|
||||||
|
|
||||||
|
def is_classmethod(self, name):
|
||||||
|
return self.classmethod.has_key(name)
|
||||||
|
|
||||||
|
def attr_is_overriden(self, attr):
|
||||||
|
return self.override_attrs.has_key(attr)
|
||||||
|
|
||||||
|
def attr_override(self, attr):
|
||||||
|
return self.override_attrs[attr]
|
||||||
|
|
||||||
|
def slot_is_overriden(self, slot):
|
||||||
|
return self.override_slots.has_key(slot)
|
||||||
|
|
||||||
|
def slot_override(self, slot):
|
||||||
|
return self.override_slots[slot]
|
||||||
|
|
||||||
|
def get_headers(self):
|
||||||
|
return self.headers
|
||||||
|
|
||||||
|
def get_body(self):
|
||||||
|
return self.body
|
||||||
|
|
||||||
|
def get_init(self):
|
||||||
|
return self.init
|
||||||
|
|
||||||
|
def get_imports(self):
|
||||||
|
return self.imports
|
||||||
|
|
||||||
|
def get_defines_for(self, klass):
|
||||||
|
return self.defines.get(klass, {})
|
||||||
|
|
||||||
|
def get_functions(self):
|
||||||
|
return self.functions
|
771
bindings/python/codegen/reversewrapper.py
Normal file
771
bindings/python/codegen/reversewrapper.py
Normal file
|
@ -0,0 +1,771 @@
|
||||||
|
### -*- python -*-
|
||||||
|
### Code to generate "Reverse Wrappers", i.e. C->Python wrappers
|
||||||
|
### (C) 2004 Gustavo Carneiro <gjc@gnome.org>
|
||||||
|
import argtypes
|
||||||
|
import os
|
||||||
|
|
||||||
|
DEBUG_MODE = ('PYGTK_CODEGEN_DEBUG' in os.environ)
|
||||||
|
|
||||||
|
def join_ctype_name(ctype, name):
|
||||||
|
'''Joins a C type and a variable name into a single string'''
|
||||||
|
if ctype[-1] != '*':
|
||||||
|
return " ".join((ctype, name))
|
||||||
|
else:
|
||||||
|
return "".join((ctype, name))
|
||||||
|
|
||||||
|
|
||||||
|
class CodeSink(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.indent_level = 0 # current indent level
|
||||||
|
self.indent_stack = [] # previous indent levels
|
||||||
|
|
||||||
|
def _format_code(self, code):
|
||||||
|
assert isinstance(code, str)
|
||||||
|
l = []
|
||||||
|
for line in code.split('\n'):
|
||||||
|
l.append(' '*self.indent_level + line)
|
||||||
|
if l[-1]:
|
||||||
|
l.append('')
|
||||||
|
return '\n'.join(l)
|
||||||
|
|
||||||
|
def writeln(self, line=''):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def indent(self, level=4):
|
||||||
|
'''Add a certain ammount of indentation to all lines written
|
||||||
|
from now on and until unindent() is called'''
|
||||||
|
self.indent_stack.append(self.indent_level)
|
||||||
|
self.indent_level += level
|
||||||
|
|
||||||
|
def unindent(self):
|
||||||
|
'''Revert indentation level to the value before last indent() call'''
|
||||||
|
self.indent_level = self.indent_stack.pop()
|
||||||
|
|
||||||
|
|
||||||
|
class FileCodeSink(CodeSink):
|
||||||
|
def __init__(self, fp):
|
||||||
|
CodeSink.__init__(self)
|
||||||
|
assert isinstance(fp, file)
|
||||||
|
self.fp = fp
|
||||||
|
|
||||||
|
def writeln(self, line=''):
|
||||||
|
self.fp.write(self._format_code(line))
|
||||||
|
|
||||||
|
class MemoryCodeSink(CodeSink):
|
||||||
|
def __init__(self):
|
||||||
|
CodeSink.__init__(self)
|
||||||
|
self.lines = []
|
||||||
|
|
||||||
|
def writeln(self, line=''):
|
||||||
|
self.lines.append(self._format_code(line))
|
||||||
|
|
||||||
|
def flush_to(self, sink):
|
||||||
|
assert isinstance(sink, CodeSink)
|
||||||
|
for line in self.lines:
|
||||||
|
sink.writeln(line.rstrip())
|
||||||
|
self.lines = []
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
l = []
|
||||||
|
for line in self.lines:
|
||||||
|
l.append(self._format_code(line))
|
||||||
|
self.lines = []
|
||||||
|
return "".join(l)
|
||||||
|
|
||||||
|
class ReverseWrapper(object):
|
||||||
|
'''Object that generates a C->Python wrapper'''
|
||||||
|
def __init__(self, cname, is_static=True):
|
||||||
|
assert isinstance(cname, str)
|
||||||
|
|
||||||
|
self.cname = cname
|
||||||
|
## function object we will call, or object whose method we will call
|
||||||
|
self.called_pyobj = None
|
||||||
|
## name of method of self.called_pyobj we will call
|
||||||
|
self.method_name = None
|
||||||
|
self.is_static = is_static
|
||||||
|
|
||||||
|
self.parameters = []
|
||||||
|
self.declarations = MemoryCodeSink()
|
||||||
|
self.post_return_code = MemoryCodeSink()
|
||||||
|
self.body = MemoryCodeSink()
|
||||||
|
self.cleanup_actions = []
|
||||||
|
self.pyargv_items = []
|
||||||
|
self.pyargv_optional_items = []
|
||||||
|
self.pyret_parse_items = [] # list of (format_spec, parameter)
|
||||||
|
|
||||||
|
def set_call_target(self, called_pyobj, method_name=None):
|
||||||
|
assert called_pyobj is not None
|
||||||
|
assert self.called_pyobj is None
|
||||||
|
self.called_pyobj = called_pyobj
|
||||||
|
self.method_name = method_name
|
||||||
|
|
||||||
|
def set_return_type(self, return_type):
|
||||||
|
assert isinstance(return_type, ReturnType)
|
||||||
|
self.return_type = return_type
|
||||||
|
|
||||||
|
def add_parameter(self, param):
|
||||||
|
assert isinstance(param, Parameter)
|
||||||
|
self.parameters.append(param)
|
||||||
|
|
||||||
|
def add_declaration(self, decl_code):
|
||||||
|
self.declarations.writeln(decl_code)
|
||||||
|
|
||||||
|
def add_pyargv_item(self, variable, optional=False):
|
||||||
|
if optional:
|
||||||
|
self.pyargv_optional_items.append(variable)
|
||||||
|
else:
|
||||||
|
self.pyargv_items.append(variable)
|
||||||
|
|
||||||
|
def add_pyret_parse_item(self, format_specifier, parameter, prepend=False):
|
||||||
|
if prepend:
|
||||||
|
self.pyret_parse_items.insert(0, (format_specifier, parameter))
|
||||||
|
else:
|
||||||
|
self.pyret_parse_items.append((format_specifier, parameter))
|
||||||
|
|
||||||
|
def write_code(self, code,
|
||||||
|
cleanup=None,
|
||||||
|
failure_expression=None,
|
||||||
|
failure_cleanup=None,
|
||||||
|
failure_exception=None,
|
||||||
|
code_sink=None):
|
||||||
|
'''Add a chunk of code with cleanup and error handling
|
||||||
|
|
||||||
|
This method is to be used by TypeHandlers when generating code
|
||||||
|
|
||||||
|
Keywork arguments:
|
||||||
|
code -- code to add
|
||||||
|
cleanup -- code to cleanup any dynamic resources created by @code
|
||||||
|
(except in case of failure) (default None)
|
||||||
|
failure_expression -- C boolean expression to indicate
|
||||||
|
if anything failed (default None)
|
||||||
|
failure_cleanup -- code to cleanup any dynamic resources
|
||||||
|
created by @code in case of failure (default None)
|
||||||
|
failure_exception -- code to raise an exception in case of
|
||||||
|
failure (which will be immediately
|
||||||
|
printed and cleared), (default None)
|
||||||
|
code_sink -- "code sink" to use; by default,
|
||||||
|
ReverseWrapper.body is used, which writes the
|
||||||
|
main body of the wrapper, before calling the
|
||||||
|
python method. Alternatively,
|
||||||
|
ReverseWrapper.after_pyret_parse can be used, to
|
||||||
|
write code after the PyArg_ParseTuple that
|
||||||
|
parses the python method return value.
|
||||||
|
'''
|
||||||
|
if code_sink is None:
|
||||||
|
code_sink = self.body
|
||||||
|
if code is not None:
|
||||||
|
code_sink.writeln(code)
|
||||||
|
if failure_expression is not None:
|
||||||
|
code_sink.writeln("if (%s) {" % (failure_expression,))
|
||||||
|
code_sink.indent()
|
||||||
|
if failure_exception is None:
|
||||||
|
code_sink.writeln("if (PyErr_Occurred())")
|
||||||
|
code_sink.indent()
|
||||||
|
code_sink.writeln("PyErr_Print();")
|
||||||
|
code_sink.unindent()
|
||||||
|
else:
|
||||||
|
code_sink.writeln(failure_exception)
|
||||||
|
code_sink.writeln("PyErr_Print();")
|
||||||
|
if failure_cleanup is not None:
|
||||||
|
code_sink.writeln(failure_cleanup)
|
||||||
|
for cleanup_action in self.cleanup_actions:
|
||||||
|
code_sink.writeln(cleanup_action)
|
||||||
|
self.return_type.write_error_return()
|
||||||
|
code_sink.unindent()
|
||||||
|
code_sink.writeln("}")
|
||||||
|
if cleanup is not None:
|
||||||
|
self.cleanup_actions.insert(0, cleanup)
|
||||||
|
|
||||||
|
def generate(self, sink):
|
||||||
|
'''Generate the code into a CodeSink object'''
|
||||||
|
assert isinstance(sink, CodeSink)
|
||||||
|
|
||||||
|
if DEBUG_MODE:
|
||||||
|
self.declarations.writeln("/* begin declarations */")
|
||||||
|
self.body.writeln("/* begin main body */")
|
||||||
|
self.post_return_code.writeln("/* begin post-return code */")
|
||||||
|
|
||||||
|
self.add_declaration("PyGILState_STATE __py_state;")
|
||||||
|
self.write_code(code="__py_state = pyg_gil_state_ensure();",
|
||||||
|
cleanup="pyg_gil_state_release(__py_state);")
|
||||||
|
|
||||||
|
for param in self.parameters:
|
||||||
|
param.convert_c2py()
|
||||||
|
|
||||||
|
assert self.called_pyobj is not None,\
|
||||||
|
"Parameters failed to provide a target function or method."
|
||||||
|
|
||||||
|
if self.is_static:
|
||||||
|
sink.writeln('static %s' % self.return_type.get_c_type())
|
||||||
|
else:
|
||||||
|
sink.writeln(self.return_type.get_c_type())
|
||||||
|
c_proto_params = map(Parameter.format_for_c_proto, self.parameters)
|
||||||
|
sink.writeln("%s(%s)\n{" % (self.cname, ", ".join(c_proto_params)))
|
||||||
|
|
||||||
|
self.return_type.write_decl()
|
||||||
|
self.add_declaration("PyObject *py_retval;")
|
||||||
|
|
||||||
|
## Handle number of arguments
|
||||||
|
if self.pyargv_items:
|
||||||
|
self.add_declaration("PyObject *py_args;")
|
||||||
|
py_args = "py_args"
|
||||||
|
if self.pyargv_optional_items:
|
||||||
|
self.add_declaration("int argc = %i;" % len(self.pyargv_items))
|
||||||
|
argc = "argc"
|
||||||
|
for arg in self.pyargv_optional_items:
|
||||||
|
self.body.writeln("if (%s)" % arg)
|
||||||
|
self.body.indent()
|
||||||
|
self.body.writeln("++argc;")
|
||||||
|
self.body.unindent()
|
||||||
|
else:
|
||||||
|
argc = str(len(self.pyargv_items))
|
||||||
|
else:
|
||||||
|
if self.pyargv_optional_items:
|
||||||
|
self.add_declaration("PyObject *py_args;")
|
||||||
|
py_args = "py_args"
|
||||||
|
self.add_declaration("int argc = 0;")
|
||||||
|
argc = "argc"
|
||||||
|
for arg in self.pyargv_optional_items:
|
||||||
|
self.body.writeln("if (%s)" % arg)
|
||||||
|
self.body.indent()
|
||||||
|
self.body.writeln("++argc;")
|
||||||
|
self.body.unindent()
|
||||||
|
else:
|
||||||
|
py_args = "NULL"
|
||||||
|
argc = None
|
||||||
|
|
||||||
|
self.body.writeln()
|
||||||
|
|
||||||
|
if py_args != "NULL":
|
||||||
|
self.write_code("py_args = PyTuple_New(%s);" % argc,
|
||||||
|
cleanup="Py_DECREF(py_args);")
|
||||||
|
pos = 0
|
||||||
|
for arg in self.pyargv_items:
|
||||||
|
try: # try to remove the Py_DECREF cleanup action, if we can
|
||||||
|
self.cleanup_actions.remove("Py_DECREF(%s);" % arg)
|
||||||
|
except ValueError: # otherwise we have to Py_INCREF..
|
||||||
|
self.body.writeln("Py_INCREF(%s);" % arg)
|
||||||
|
self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
|
||||||
|
pos += 1
|
||||||
|
for arg in self.pyargv_optional_items:
|
||||||
|
self.body.writeln("if (%s) {" % arg)
|
||||||
|
self.body.indent()
|
||||||
|
try: # try to remove the Py_DECREF cleanup action, if we can
|
||||||
|
self.cleanup_actions.remove("Py_XDECREF(%s);" % arg)
|
||||||
|
except ValueError: # otherwise we have to Py_INCREF..
|
||||||
|
self.body.writeln("Py_INCREF(%s);" % arg)
|
||||||
|
self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
|
||||||
|
self.body.unindent()
|
||||||
|
self.body.writeln("}")
|
||||||
|
pos += 1
|
||||||
|
|
||||||
|
self.body.writeln()
|
||||||
|
|
||||||
|
## Call the python method
|
||||||
|
if self.method_name is None:
|
||||||
|
self.write_code("py_retval = PyObject_Call(%s, %s);"
|
||||||
|
% (self.called_pyobj, py_args),
|
||||||
|
cleanup="Py_DECREF(py_retval);",
|
||||||
|
failure_expression="!py_retval")
|
||||||
|
else:
|
||||||
|
self.add_declaration("PyObject *py_method;")
|
||||||
|
self.write_code("py_method = PyObject_GetAttrString(%s, \"%s\");"
|
||||||
|
% (self.called_pyobj, self.method_name),
|
||||||
|
cleanup="Py_DECREF(py_method);",
|
||||||
|
failure_expression="!py_method")
|
||||||
|
self.write_code("py_retval = PyObject_CallObject(py_method, %s);"
|
||||||
|
% (py_args,),
|
||||||
|
cleanup="Py_DECREF(py_retval);",
|
||||||
|
failure_expression="!py_retval")
|
||||||
|
|
||||||
|
## -- Handle the return value --
|
||||||
|
|
||||||
|
## we need to check if the return_type object is prepared to cooperate with multiple return values
|
||||||
|
len_before = len(self.pyret_parse_items)
|
||||||
|
self.return_type.write_conversion()
|
||||||
|
len_after = len(self.pyret_parse_items)
|
||||||
|
assert (self.return_type.get_c_type() == 'void'
|
||||||
|
or not (len_before == len_after and len_after > 0)),\
|
||||||
|
("Bug in reverse wrappers: return type handler %s"
|
||||||
|
" is not prepared to cooperate multiple return values") % (type(self.return_type),)
|
||||||
|
|
||||||
|
sink.indent()
|
||||||
|
|
||||||
|
if len(self.pyret_parse_items) == 1:
|
||||||
|
## if retval is one item only, pack it in a tuple so we
|
||||||
|
## can use PyArg_ParseTuple as usual..
|
||||||
|
self.write_code('py_retval = Py_BuildValue("(N)", py_retval);')
|
||||||
|
if len(self.pyret_parse_items) > 0:
|
||||||
|
## Parse return values using PyArg_ParseTuple
|
||||||
|
self.write_code(code=None, failure_expression=(
|
||||||
|
'!PyArg_ParseTuple(py_retval, "%s", %s)' % (
|
||||||
|
"".join([format for format, param in self.pyret_parse_items]),
|
||||||
|
", ".join([param for format, param in self.pyret_parse_items]))))
|
||||||
|
|
||||||
|
if DEBUG_MODE:
|
||||||
|
self.declarations.writeln("/* end declarations */")
|
||||||
|
self.declarations.flush_to(sink)
|
||||||
|
sink.writeln()
|
||||||
|
if DEBUG_MODE:
|
||||||
|
self.body.writeln("/* end main body */")
|
||||||
|
self.body.flush_to(sink)
|
||||||
|
sink.writeln()
|
||||||
|
if DEBUG_MODE:
|
||||||
|
self.post_return_code.writeln("/* end post-return code */")
|
||||||
|
self.post_return_code.flush_to(sink)
|
||||||
|
sink.writeln()
|
||||||
|
|
||||||
|
for cleanup_action in self.cleanup_actions:
|
||||||
|
sink.writeln(cleanup_action)
|
||||||
|
if self.return_type.get_c_type() != 'void':
|
||||||
|
sink.writeln()
|
||||||
|
sink.writeln("return retval;")
|
||||||
|
sink.unindent()
|
||||||
|
sink.writeln("}")
|
||||||
|
|
||||||
|
class TypeHandler(object):
|
||||||
|
def __init__(self, wrapper, **props):
|
||||||
|
assert isinstance(wrapper, ReverseWrapper)
|
||||||
|
self.wrapper = wrapper
|
||||||
|
self.props = props
|
||||||
|
|
||||||
|
class ReturnType(TypeHandler):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def write_decl(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def write_error_return(self):
|
||||||
|
'''Write "return <value>" code in case of error'''
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def write_conversion(self):
|
||||||
|
'''Writes code to convert Python return value in 'py_retval'
|
||||||
|
into C 'retval'. Returns a string with C boolean expression
|
||||||
|
that determines if anything went wrong. '''
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
class Parameter(TypeHandler):
|
||||||
|
|
||||||
|
def __init__(self, wrapper, name, **props):
|
||||||
|
TypeHandler.__init__(self, wrapper, **props)
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def convert_c2py(self):
|
||||||
|
'''Write some code before calling the Python method.'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def format_for_c_proto(self):
|
||||||
|
return join_ctype_name(self.get_c_type(), self.name)
|
||||||
|
|
||||||
|
|
||||||
|
###---
|
||||||
|
class StringParam(Parameter):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'char *').replace('const-', 'const ')
|
||||||
|
|
||||||
|
def convert_c2py(self):
|
||||||
|
if self.props.get('optional', False):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("if (%s)\n"
|
||||||
|
" py_%s = PyString_FromString(%s);\n"
|
||||||
|
% (self.name, self.name, self.name)),
|
||||||
|
cleanup=("Py_XDECREF(py_%s);" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name, optional=True)
|
||||||
|
else:
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" %
|
||||||
|
(self.name, self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name),
|
||||||
|
failure_expression=("!py_%s" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
for ctype in ('char*', 'gchar*', 'const-char*', 'char-const*', 'const-gchar*',
|
||||||
|
'gchar-const*', 'string', 'static_string'):
|
||||||
|
argtypes.matcher.register_reverse(ctype, StringParam)
|
||||||
|
del ctype
|
||||||
|
|
||||||
|
class StringReturn(ReturnType):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return "char *"
|
||||||
|
|
||||||
|
def write_decl(self):
|
||||||
|
self.wrapper.add_declaration("char *retval;")
|
||||||
|
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return NULL;")
|
||||||
|
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.add_pyret_parse_item("s", "&retval", prepend=True)
|
||||||
|
self.wrapper.write_code("retval = g_strdup(retval);", code_sink=self.wrapper.post_return_code)
|
||||||
|
|
||||||
|
for ctype in ('char*', 'gchar*'):
|
||||||
|
argtypes.matcher.register_reverse_ret(ctype, StringReturn)
|
||||||
|
del ctype
|
||||||
|
|
||||||
|
|
||||||
|
class VoidReturn(ReturnType):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return "void"
|
||||||
|
|
||||||
|
def write_decl(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return;")
|
||||||
|
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.write_code(
|
||||||
|
code=None,
|
||||||
|
failure_expression="py_retval != Py_None",
|
||||||
|
failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be None");')
|
||||||
|
|
||||||
|
argtypes.matcher.register_reverse_ret('void', VoidReturn)
|
||||||
|
argtypes.matcher.register_reverse_ret('none', VoidReturn)
|
||||||
|
|
||||||
|
class GObjectParam(Parameter):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'GObject *')
|
||||||
|
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("if (%s)\n"
|
||||||
|
" py_%s = pygobject_new((GObject *) %s);\n"
|
||||||
|
"else {\n"
|
||||||
|
" Py_INCREF(Py_None);\n"
|
||||||
|
" py_%s = Py_None;\n"
|
||||||
|
"}"
|
||||||
|
% (self.name, self.name, self.name, self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
argtypes.matcher.register_reverse('GObject*', GObjectParam)
|
||||||
|
|
||||||
|
class GObjectReturn(ReturnType):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'GObject *')
|
||||||
|
|
||||||
|
def write_decl(self):
|
||||||
|
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
|
||||||
|
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return NULL;")
|
||||||
|
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.write_code(
|
||||||
|
code=None,
|
||||||
|
failure_expression="!PyObject_TypeCheck(py_retval, &PyGObject_Type)",
|
||||||
|
failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be a GObject");')
|
||||||
|
self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);"
|
||||||
|
% self.get_c_type())
|
||||||
|
self.wrapper.write_code("g_object_ref((GObject *) retval);")
|
||||||
|
|
||||||
|
argtypes.matcher.register_reverse_ret('GObject*', GObjectReturn)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class IntParam(Parameter):
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'int')
|
||||||
|
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("py_%s = PyInt_FromLong(%s);" %
|
||||||
|
(self.name, self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
class IntReturn(ReturnType):
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'int')
|
||||||
|
def write_decl(self):
|
||||||
|
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return -G_MAXINT;")
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.add_pyret_parse_item("i", "&retval", prepend=True)
|
||||||
|
|
||||||
|
for argtype in ('int', 'gint', 'guint', 'short', 'gshort', 'gushort', 'long',
|
||||||
|
'glong', 'gsize', 'gssize', 'guint8', 'gint8', 'guint16',
|
||||||
|
'gint16', 'gint32', 'GTime'):
|
||||||
|
argtypes.matcher.register_reverse(argtype, IntParam)
|
||||||
|
argtypes.matcher.register_reverse_ret(argtype, IntReturn)
|
||||||
|
del argtype
|
||||||
|
|
||||||
|
class IntPtrParam(Parameter):
|
||||||
|
def __init__(self, wrapper, name, **props):
|
||||||
|
if "direction" not in props:
|
||||||
|
raise ValueError("cannot use int* parameter without direction")
|
||||||
|
if props["direction"] not in ("out", "inout"):
|
||||||
|
raise ValueError("cannot use int* parameter with direction '%s'" % (props["direction"],))
|
||||||
|
Parameter.__init__(self, wrapper, name, **props)
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'int*')
|
||||||
|
def convert_c2py(self):
|
||||||
|
if self.props["direction"] == "inout":
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("py_%s = PyInt_FromLong(*%s);" %
|
||||||
|
(self.name, self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
self.wrapper.add_pyret_parse_item("i", self.name)
|
||||||
|
for argtype in ('int*', 'gint*'):
|
||||||
|
argtypes.matcher.register_reverse(argtype, IntPtrParam)
|
||||||
|
del argtype
|
||||||
|
|
||||||
|
|
||||||
|
class GEnumReturn(IntReturn):
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.write_code(
|
||||||
|
code=None,
|
||||||
|
failure_expression=("pyg_enum_get_value(%s, py_retval, (gint *)&retval)" %
|
||||||
|
self.props['typecode']))
|
||||||
|
|
||||||
|
argtypes.matcher.register_reverse_ret("GEnum", GEnumReturn)
|
||||||
|
|
||||||
|
class GEnumParam(IntParam):
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("py_%s = pyg_enum_from_gtype(%s, %s);" %
|
||||||
|
(self.name, self.props['typecode'], self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name),
|
||||||
|
failure_expression=("!py_%s" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
argtypes.matcher.register_reverse("GEnum", GEnumParam)
|
||||||
|
|
||||||
|
class GFlagsReturn(IntReturn):
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.write_code(
|
||||||
|
code=None,
|
||||||
|
failure_expression=("pyg_flags_get_value(%s, py_retval, (gint *)&retval)" %
|
||||||
|
self.props['typecode']))
|
||||||
|
|
||||||
|
argtypes.matcher.register_reverse_ret("GFlags", GFlagsReturn)
|
||||||
|
|
||||||
|
class GFlagsParam(IntParam):
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("py_%s = pyg_flags_from_gtype(%s, %s);" %
|
||||||
|
(self.name, self.props['typecode'], self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name),
|
||||||
|
failure_expression=("!py_%s" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
argtypes.matcher.register_reverse("GFlags", GFlagsParam)
|
||||||
|
|
||||||
|
|
||||||
|
class GtkTreePathParam(IntParam):
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("py_%s = pygtk_tree_path_to_pyobject(%s);" %
|
||||||
|
(self.name, self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name),
|
||||||
|
failure_expression=("!py_%s" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
argtypes.matcher.register_reverse("GtkTreePath*", GtkTreePathParam)
|
||||||
|
|
||||||
|
|
||||||
|
class BooleanReturn(ReturnType):
|
||||||
|
def get_c_type(self):
|
||||||
|
return "gboolean"
|
||||||
|
def write_decl(self):
|
||||||
|
self.wrapper.add_declaration("gboolean retval;")
|
||||||
|
self.wrapper.add_declaration("PyObject *py_main_retval;")
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return FALSE;")
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.add_pyret_parse_item("O", "&py_main_retval", prepend=True)
|
||||||
|
self.wrapper.write_code("retval = PyObject_IsTrue(py_main_retval)? TRUE : FALSE;",
|
||||||
|
code_sink=self.wrapper.post_return_code)
|
||||||
|
argtypes.matcher.register_reverse_ret("gboolean", BooleanReturn)
|
||||||
|
|
||||||
|
class BooleanParam(Parameter):
|
||||||
|
def get_c_type(self):
|
||||||
|
return "gboolean"
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code("py_%s = %s? Py_True : Py_False;"
|
||||||
|
% (self.name, self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
argtypes.matcher.register_reverse("gboolean", BooleanParam)
|
||||||
|
|
||||||
|
|
||||||
|
class DoubleParam(Parameter):
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'gdouble')
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("py_%s = PyFloat_FromDouble(%s);" %
|
||||||
|
(self.name, self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
class DoublePtrParam(Parameter):
|
||||||
|
def __init__(self, wrapper, name, **props):
|
||||||
|
if "direction" not in props:
|
||||||
|
raise ValueError("cannot use double* parameter without direction")
|
||||||
|
if props["direction"] not in ("out", ): # inout not yet implemented
|
||||||
|
raise ValueError("cannot use double* parameter with direction '%s'" % (props["direction"],))
|
||||||
|
Parameter.__init__(self, wrapper, name, **props)
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'double*')
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_pyret_parse_item("d", self.name)
|
||||||
|
for argtype in ('double*', 'gdouble*'):
|
||||||
|
argtypes.matcher.register_reverse(argtype, DoublePtrParam)
|
||||||
|
del argtype
|
||||||
|
|
||||||
|
class DoubleReturn(ReturnType):
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'gdouble')
|
||||||
|
def write_decl(self):
|
||||||
|
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return -G_MAXFLOAT;")
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.write_code(
|
||||||
|
code=None,
|
||||||
|
failure_expression="!PyFloat_AsDouble(py_retval)",
|
||||||
|
failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a float");')
|
||||||
|
self.wrapper.write_code("retval = PyFloat_AsDouble(py_retval);")
|
||||||
|
|
||||||
|
for argtype in ('float', 'double', 'gfloat', 'gdouble'):
|
||||||
|
argtypes.matcher.register_reverse(argtype, DoubleParam)
|
||||||
|
argtypes.matcher.register_reverse_ret(argtype, DoubleReturn)
|
||||||
|
|
||||||
|
|
||||||
|
class GBoxedParam(Parameter):
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type').replace('const-', 'const ')
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
ctype = self.get_c_type()
|
||||||
|
if ctype.startswith('const '):
|
||||||
|
ctype_no_const = ctype[len('const '):]
|
||||||
|
self.wrapper.write_code(
|
||||||
|
code=('py_%s = pyg_boxed_new(%s, (%s) %s, TRUE, TRUE);' %
|
||||||
|
(self.name, self.props['typecode'],
|
||||||
|
ctype_no_const, self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name))
|
||||||
|
else:
|
||||||
|
self.wrapper.write_code(
|
||||||
|
code=('py_%s = pyg_boxed_new(%s, %s, FALSE, FALSE);' %
|
||||||
|
(self.name, self.props['typecode'], self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
argtypes.matcher.register_reverse("GBoxed", GBoxedParam)
|
||||||
|
|
||||||
|
class GBoxedReturn(ReturnType):
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type')
|
||||||
|
def write_decl(self):
|
||||||
|
self.wrapper.add_declaration("%s retval;" % self.get_c_type())
|
||||||
|
def write_error_return(self):
|
||||||
|
self.wrapper.write_code("return retval;")
|
||||||
|
def write_conversion(self):
|
||||||
|
self.wrapper.write_code(
|
||||||
|
failure_expression=("!pyg_boxed_check(py_retval, %s)" %
|
||||||
|
(self.props['typecode'],)),
|
||||||
|
failure_cleanup=('PyErr_SetString(PyExc_TypeError, "retval should be a %s");'
|
||||||
|
% (self.props['typename'],)))
|
||||||
|
self.wrapper.write_code('retval = pyg_boxed_get(py_retval, %s);' %
|
||||||
|
self.props['typename'])
|
||||||
|
|
||||||
|
argtypes.matcher.register_reverse_ret("GBoxed", GBoxedReturn)
|
||||||
|
|
||||||
|
|
||||||
|
class GdkRectanglePtrParam(Parameter):
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type').replace('const-', 'const ')
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code(
|
||||||
|
code=('py_%s = pyg_boxed_new(GDK_TYPE_RECTANGLE, %s, TRUE, TRUE);' %
|
||||||
|
(self.name, self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name))
|
||||||
|
self.wrapper.add_pyargv_item("py_%s" % self.name)
|
||||||
|
|
||||||
|
argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam)
|
||||||
|
argtypes.matcher.register_reverse('GtkAllocation*', GdkRectanglePtrParam)
|
||||||
|
|
||||||
|
|
||||||
|
class PyGObjectMethodParam(Parameter):
|
||||||
|
def __init__(self, wrapper, name, method_name, **props):
|
||||||
|
Parameter.__init__(self, wrapper, name, **props)
|
||||||
|
self.method_name = method_name
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return self.props.get('c_type', 'GObject *')
|
||||||
|
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
|
||||||
|
self.wrapper.write_code(code=("py_%s = pygobject_new((GObject *) %s);" %
|
||||||
|
(self.name, self.name)),
|
||||||
|
cleanup=("Py_DECREF(py_%s);" % self.name),
|
||||||
|
failure_expression=("!py_%s" % self.name))
|
||||||
|
self.wrapper.set_call_target("py_%s" % self.name, self.method_name)
|
||||||
|
|
||||||
|
class CallbackInUserDataParam(Parameter):
|
||||||
|
def __init__(self, wrapper, name, free_it, **props):
|
||||||
|
Parameter.__init__(self, wrapper, name, **props)
|
||||||
|
self.free_it = free_it
|
||||||
|
|
||||||
|
def get_c_type(self):
|
||||||
|
return "gpointer"
|
||||||
|
|
||||||
|
def convert_c2py(self):
|
||||||
|
self.wrapper.add_declaration("PyObject **_user_data;")
|
||||||
|
cleanup = self.free_it and ("g_free(%s);" % self.name) or None
|
||||||
|
self.wrapper.write_code(code=("_real_user_data = (PyObject **) %s;"
|
||||||
|
% self.name),
|
||||||
|
cleanup=cleanup)
|
||||||
|
|
||||||
|
self.wrapper.add_declaration("PyObject *py_func;")
|
||||||
|
cleanup = self.free_it and "Py_DECREF(py_func);" or None
|
||||||
|
self.wrapper.write_code(code="py_func = _user_data[0];",
|
||||||
|
cleanup=cleanup)
|
||||||
|
self.wrapper.set_call_target("py_func")
|
||||||
|
|
||||||
|
self.wrapper.add_declaration("PyObject *py_user_data;")
|
||||||
|
cleanup = self.free_it and "Py_XDECREF(py_user_data);" or None
|
||||||
|
self.wrapper.write_code(code="py_user_data = _user_data[1];",
|
||||||
|
cleanup=cleanup)
|
||||||
|
self.wrapper.add_pyargv_item("py_user_data", optional=True)
|
||||||
|
|
||||||
|
def _test():
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if 1:
|
||||||
|
wrapper = ReverseWrapper("this_is_the_c_function_name", is_static=True)
|
||||||
|
wrapper.set_return_type(StringReturn(wrapper))
|
||||||
|
wrapper.add_parameter(PyGObjectMethodParam(wrapper, "self", method_name="do_xxx"))
|
||||||
|
wrapper.add_parameter(StringParam(wrapper, "param2", optional=True))
|
||||||
|
wrapper.add_parameter(GObjectParam(wrapper, "param3"))
|
||||||
|
#wrapper.add_parameter(InoutIntParam(wrapper, "param4"))
|
||||||
|
wrapper.generate(FileCodeSink(sys.stderr))
|
||||||
|
|
||||||
|
if 0:
|
||||||
|
wrapper = ReverseWrapper("this_a_callback_wrapper")
|
||||||
|
wrapper.set_return_type(VoidReturn(wrapper))
|
||||||
|
wrapper.add_parameter(StringParam(wrapper, "param1", optional=False))
|
||||||
|
wrapper.add_parameter(GObjectParam(wrapper, "param2"))
|
||||||
|
wrapper.add_parameter(CallbackInUserDataParam(wrapper, "data", free_it=True))
|
||||||
|
wrapper.generate(FileCodeSink(sys.stderr))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
_test()
|
144
bindings/python/codegen/scmexpr.py
Normal file
144
bindings/python/codegen/scmexpr.py
Normal 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`
|
6
bindings/python/rtspserver-types.defs
Normal file
6
bindings/python/rtspserver-types.defs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
(define-object Server
|
||||||
|
(in-module "Gst.RTSPServer")
|
||||||
|
(parent "GObject")
|
||||||
|
(c-name "GstRTSPServer")
|
||||||
|
(gtype-id "GST_TYPE_RTSP_SERVER")
|
||||||
|
)
|
16
bindings/python/rtspserver.defs
Normal file
16
bindings/python/rtspserver.defs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
(include "rtspserver-types.defs")
|
||||||
|
|
||||||
|
(define-function rtsp_server_new
|
||||||
|
(c-name "gst_rtsp_server_new")
|
||||||
|
(is-constructor-of "GstRTSPServer")
|
||||||
|
(return-type "GstRTSPServer*")
|
||||||
|
)
|
||||||
|
|
||||||
|
(define-method attach
|
||||||
|
(of-object "GstRTSPServer")
|
||||||
|
(c-name "gst_rtsp_server_attach")
|
||||||
|
(return-type "guint")
|
||||||
|
(parameters
|
||||||
|
'("GMainContext*" "context")
|
||||||
|
)
|
||||||
|
)
|
52
bindings/python/rtspserver.override
Normal file
52
bindings/python/rtspserver.override
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/* -*- Mode: C; c-basic-offset: 4 -*- */
|
||||||
|
%%
|
||||||
|
headers
|
||||||
|
/* include any required headers here */
|
||||||
|
#define NO_IMPORT_PYGOBJECT
|
||||||
|
#include <pygobject.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Boonky define that allows for backwards compatibility with Python 2.4 */
|
||||||
|
#if PY_VERSION_HEX < 0x02050000
|
||||||
|
#define Py_ssize_t int
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "rtsp-server.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
GMainContext *context;
|
||||||
|
} PyGMainContext;
|
||||||
|
|
||||||
|
%%
|
||||||
|
import gobject.GObject as PyGObject_Type
|
||||||
|
import gobject.MainContext as PyGMainContext_Type
|
||||||
|
|
||||||
|
%%
|
||||||
|
override gst_rtsp_server_attach kwargs
|
||||||
|
static PyObject *
|
||||||
|
_wrap_gst_rtsp_server_attach (PyGObject *self,
|
||||||
|
PyObject *args, PyObject *keywords)
|
||||||
|
{
|
||||||
|
static char *kwlist[] = {"context", NULL};
|
||||||
|
PyGMainContext *py_context = NULL;
|
||||||
|
GMainContext *context = NULL;
|
||||||
|
guint res;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTupleAndKeywords (args, keywords,
|
||||||
|
"|O!:GstRTSPServer.__init__", kwlist,
|
||||||
|
&PyGMainContext_Type, &py_context))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (py_context)
|
||||||
|
context = py_context->context;
|
||||||
|
|
||||||
|
pyg_begin_allow_threads;
|
||||||
|
res = gst_rtsp_server_attach (GST_RTSP_SERVER (self->obj), context);
|
||||||
|
pyg_end_allow_threads;
|
||||||
|
|
||||||
|
return PyLong_FromLong (res);
|
||||||
|
}
|
31
bindings/python/rtspservermodule.c
Normal file
31
bindings/python/rtspservermodule.c
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/* -*- Mode: C; c-basic-offset: 4 -*- */
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
#include <Python.h>
|
||||||
|
#include <pygobject.h>
|
||||||
|
|
||||||
|
/* include any extra headers needed here */
|
||||||
|
|
||||||
|
void pygst_rtsp_server_register_classes(PyObject *d);
|
||||||
|
extern PyMethodDef pygst_rtsp_server_functions[];
|
||||||
|
|
||||||
|
DL_EXPORT(void)
|
||||||
|
initrtspserver(void)
|
||||||
|
{
|
||||||
|
PyObject *m, *d;
|
||||||
|
|
||||||
|
/* perform any initialisation required by the library here */
|
||||||
|
|
||||||
|
m = Py_InitModule("rtspserver", pygst_rtsp_server_functions);
|
||||||
|
d = PyModule_GetDict(m);
|
||||||
|
|
||||||
|
init_pygobject();
|
||||||
|
|
||||||
|
pygst_rtsp_server_register_classes(d);
|
||||||
|
|
||||||
|
/* add anything else to the module dictionary (such as constants) */
|
||||||
|
|
||||||
|
if (PyErr_Occurred())
|
||||||
|
Py_FatalError("could not initialise module rtspserver");
|
||||||
|
}
|
10
configure.ac
10
configure.ac
|
@ -68,6 +68,11 @@ dnl *** checks for programs ***
|
||||||
|
|
||||||
dnl find a compiler
|
dnl find a compiler
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
|
AM_PROG_CC_C_O
|
||||||
|
|
||||||
|
dnl check for python
|
||||||
|
AM_PATH_PYTHON(2.3)
|
||||||
|
AM_CHECK_PYTHON_HEADERS([HAVE_PYTHON_HEADERS="yes"], [HAVE_PYTHON_HEADERS="no"])
|
||||||
|
|
||||||
AC_PATH_PROG(VALGRIND_PATH, valgrind, no)
|
AC_PATH_PROG(VALGRIND_PATH, valgrind, no)
|
||||||
AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno")
|
AM_CONDITIONAL(HAVE_VALGRIND, test ! "x$VALGRIND_PATH" = "xno")
|
||||||
|
@ -109,6 +114,7 @@ if test "x$HAVE_PYTHON_HEADERS" = "xyes" -a \
|
||||||
else
|
else
|
||||||
HAVE_PYTHON_BINDINGS="no"
|
HAVE_PYTHON_BINDINGS="no"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AM_CONDITIONAL(WITH_PYTHON, [test "x$HAVE_PYTHON_BINDINGS" = "xyes"])
|
AM_CONDITIONAL(WITH_PYTHON, [test "x$HAVE_PYTHON_BINDINGS" = "xyes"])
|
||||||
|
|
||||||
dnl Check for vala
|
dnl Check for vala
|
||||||
|
@ -128,7 +134,6 @@ if test "x$HAVE_VALA" = "xyes"; then
|
||||||
fi
|
fi
|
||||||
AC_SUBST(VAPIDIR)
|
AC_SUBST(VAPIDIR)
|
||||||
|
|
||||||
|
|
||||||
dnl *** checks for libraries ***
|
dnl *** checks for libraries ***
|
||||||
|
|
||||||
dnl *** checks for header files ***
|
dnl *** checks for header files ***
|
||||||
|
@ -267,6 +272,8 @@ gst/Makefile
|
||||||
gst/rtsp-server/Makefile
|
gst/rtsp-server/Makefile
|
||||||
examples/Makefile
|
examples/Makefile
|
||||||
bindings/Makefile
|
bindings/Makefile
|
||||||
|
bindings/python/Makefile
|
||||||
|
bindings/python/codegen/Makefile
|
||||||
bindings/vala/Makefile
|
bindings/vala/Makefile
|
||||||
pkgconfig/Makefile
|
pkgconfig/Makefile
|
||||||
pkgconfig/gst-rtsp-server.pc
|
pkgconfig/gst-rtsp-server.pc
|
||||||
|
@ -281,6 +288,7 @@ Configuration
|
||||||
Prefix : ${prefix}
|
Prefix : ${prefix}
|
||||||
Compiler : ${CC}
|
Compiler : ${CC}
|
||||||
Vala bindings : ${HAVE_VALA}
|
Vala bindings : ${HAVE_VALA}
|
||||||
|
Python bindings: : ${HAVE_PYTHON_BINDINGS}
|
||||||
|
|
||||||
Gst-rtsp-server configured. Type 'make' to build.
|
Gst-rtsp-server configured. Type 'make' to build.
|
||||||
"
|
"
|
||||||
|
|
Loading…
Reference in a new issue