summaryrefslogtreecommitdiff
path: root/codegen
diff options
context:
space:
mode:
authorJinkun Jang <jinkun.jang@samsung.com>2013-03-13 02:21:24 +0900
committerJinkun Jang <jinkun.jang@samsung.com>2013-03-13 02:21:24 +0900
commitc6b9e84f2f7f8c85939a8e5ff5d8a5aa067cecf3 (patch)
tree1436172370a45714687122f914354ad167a2f528 /codegen
parentf7d643cbb2184346b6f8d26091eb7eb38c6bbfe1 (diff)
downloadpygobject2-accepted/tizen/20130520.101830.tar.gz
pygobject2-accepted/tizen/20130520.101830.tar.bz2
pygobject2-accepted/tizen/20130520.101830.zip
Diffstat (limited to 'codegen')
-rw-r--r--codegen/Makefile.am31
-rw-r--r--codegen/Makefile.in555
-rw-r--r--codegen/README.defs351
-rw-r--r--codegen/__init__.py16
-rw-r--r--codegen/argtypes.py1043
-rwxr-xr-xcodegen/code-coverage.py44
-rwxr-xr-xcodegen/codegen.py1722
-rwxr-xr-xcodegen/createdefs.py17
-rw-r--r--codegen/definitions.py575
-rwxr-xr-xcodegen/defsconvert.py132
-rwxr-xr-xcodegen/defsgen.py737
-rw-r--r--codegen/defsparser.py153
-rw-r--r--codegen/docextract.py448
-rwxr-xr-xcodegen/docextract_to_xml.py139
-rwxr-xr-xcodegen/docgen.py766
-rwxr-xr-xcodegen/h2def.py631
-rwxr-xr-xcodegen/mergedefs.py26
-rwxr-xr-xcodegen/missingdefs.py17
-rwxr-xr-xcodegen/mkskel.py89
-rw-r--r--codegen/override.py285
-rw-r--r--codegen/pygobject-codegen-2.0.in11
-rw-r--r--codegen/reversewrapper.py912
-rwxr-xr-xcodegen/scanvirtuals.py54
-rwxr-xr-xcodegen/scmexpr.py143
24 files changed, 8897 insertions, 0 deletions
diff --git a/codegen/Makefile.am b/codegen/Makefile.am
new file mode 100644
index 0000000..cdb1e99
--- /dev/null
+++ b/codegen/Makefile.am
@@ -0,0 +1,31 @@
+PLATFORM_VERSION = 2.0
+
+bin_SCRIPTS = pygobject-codegen-$(PLATFORM_VERSION)
+
+codegendir = $(pkgdatadir)/$(PLATFORM_VERSION)/codegen
+
+codegen_SCRIPTS = \
+ code-coverage.py \
+ codegen.py \
+ createdefs.py \
+ defsconvert.py \
+ defsgen.py \
+ docextract_to_xml.py \
+ docgen.py \
+ h2def.py \
+ mergedefs.py \
+ missingdefs.py \
+ mkskel.py \
+ scanvirtuals.py \
+ scmexpr.py
+
+codegen_PYTHON = \
+ __init__.py \
+ argtypes.py \
+ definitions.py \
+ defsparser.py \
+ docextract.py \
+ override.py \
+ reversewrapper.py
+
+EXTRA_DIST = $(codegen_SCRIPTS) README.defs pygobject-codegen-$(PLATFORM_VERSION).in
diff --git a/codegen/Makefile.in b/codegen/Makefile.in
new file mode 100644
index 0000000..c9193fc
--- /dev/null
+++ b/codegen/Makefile.in
@@ -0,0 +1,555 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = codegen
+DIST_COMMON = $(codegen_PYTHON) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/pygobject-codegen-2.0.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \
+ $(top_srcdir)/m4/jhflags.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/python.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = pygobject-codegen-2.0
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(codegendir)" \
+ "$(DESTDIR)$(codegendir)"
+SCRIPTS = $(bin_SCRIPTS) $(codegen_SCRIPTS)
+SOURCES =
+DIST_SOURCES =
+py_compile = $(top_srcdir)/py-compile
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIR = @DATADIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FFI_CFLAGS = @FFI_CFLAGS@
+FFI_LIBS = @FFI_LIBS@
+FGREP = @FGREP@
+GIOUNIX_CFLAGS = @GIOUNIX_CFLAGS@
+GIOUNIX_LIBS = @GIOUNIX_LIBS@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBFFI_PC = @LIBFFI_PC@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLATFORM = @PLATFORM@
+PYGOBJECT_MAJOR_VERSION = @PYGOBJECT_MAJOR_VERSION@
+PYGOBJECT_MICRO_VERSION = @PYGOBJECT_MICRO_VERSION@
+PYGOBJECT_MINOR_VERSION = @PYGOBJECT_MINOR_VERSION@
+PYTHON = @PYTHON@
+PYTHON_BASENAME = @PYTHON_BASENAME@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+THREADING_CFLAGS = @THREADING_CFLAGS@
+VERSION = @VERSION@
+XSLTPROC = @XSLTPROC@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pygobject_CODEGEN_DEFINES = @pygobject_CODEGEN_DEFINES@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+PLATFORM_VERSION = 2.0
+bin_SCRIPTS = pygobject-codegen-$(PLATFORM_VERSION)
+codegendir = $(pkgdatadir)/$(PLATFORM_VERSION)/codegen
+codegen_SCRIPTS = \
+ code-coverage.py \
+ codegen.py \
+ createdefs.py \
+ defsconvert.py \
+ defsgen.py \
+ docextract_to_xml.py \
+ docgen.py \
+ h2def.py \
+ mergedefs.py \
+ missingdefs.py \
+ mkskel.py \
+ scanvirtuals.py \
+ scmexpr.py
+
+codegen_PYTHON = \
+ __init__.py \
+ argtypes.py \
+ definitions.py \
+ defsparser.py \
+ docextract.py \
+ override.py \
+ reversewrapper.py
+
+EXTRA_DIST = $(codegen_SCRIPTS) README.defs pygobject-codegen-$(PLATFORM_VERSION).in
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu codegen/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu codegen/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+pygobject-codegen-2.0: $(top_builddir)/config.status $(srcdir)/pygobject-codegen-2.0.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-binSCRIPTS: $(bin_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+install-codegenSCRIPTS: $(codegen_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ test -z "$(codegendir)" || $(MKDIR_P) "$(DESTDIR)$(codegendir)"
+ @list='$(codegen_SCRIPTS)'; test -n "$(codegendir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(codegendir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(codegendir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-codegenSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(codegen_SCRIPTS)'; test -n "$(codegendir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(codegendir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(codegendir)" && rm -f $$files
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-codegenPYTHON: $(codegen_PYTHON)
+ @$(NORMAL_INSTALL)
+ test -z "$(codegendir)" || $(MKDIR_P) "$(DESTDIR)$(codegendir)"
+ @list='$(codegen_PYTHON)'; dlist=; list2=; test -n "$(codegendir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \
+ if test -f $$b$$p; then \
+ $(am__strip_dir) \
+ dlist="$$dlist $$f"; \
+ list2="$$list2 $$b$$p"; \
+ else :; fi; \
+ done; \
+ for file in $$list2; do echo $$file; done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(codegendir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(codegendir)" || exit $$?; \
+ done || exit $$?; \
+ if test -n "$$dlist"; then \
+ if test -z "$(DESTDIR)"; then \
+ PYTHON=$(PYTHON) $(py_compile) --basedir "$(codegendir)" $$dlist; \
+ else \
+ PYTHON=$(PYTHON) $(py_compile) --destdir "$(DESTDIR)" --basedir "$(codegendir)" $$dlist; \
+ fi; \
+ else :; fi
+
+uninstall-codegenPYTHON:
+ @$(NORMAL_UNINSTALL)
+ @list='$(codegen_PYTHON)'; test -n "$(codegendir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ filesc=`echo "$$files" | sed 's|$$|c|'`; \
+ fileso=`echo "$$files" | sed 's|$$|o|'`; \
+ echo " ( cd '$(DESTDIR)$(codegendir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(codegendir)" && rm -f $$files || exit $$?; \
+ echo " ( cd '$(DESTDIR)$(codegendir)' && rm -f" $$filesc ")"; \
+ cd "$(DESTDIR)$(codegendir)" && rm -f $$filesc || exit $$?; \
+ echo " ( cd '$(DESTDIR)$(codegendir)' && rm -f" $$fileso ")"; \
+ cd "$(DESTDIR)$(codegendir)" && rm -f $$fileso
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(codegendir)" "$(DESTDIR)$(codegendir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-codegenPYTHON install-codegenSCRIPTS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binSCRIPTS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binSCRIPTS uninstall-codegenPYTHON \
+ uninstall-codegenSCRIPTS
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binSCRIPTS install-codegenPYTHON \
+ install-codegenSCRIPTS install-data install-data-am \
+ install-dvi install-dvi-am install-exec install-exec-am \
+ install-html install-html-am install-info install-info-am \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am uninstall uninstall-am uninstall-binSCRIPTS \
+ uninstall-codegenPYTHON uninstall-codegenSCRIPTS
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/codegen/README.defs b/codegen/README.defs
new file mode 100644
index 0000000..5f7957e
--- /dev/null
+++ b/codegen/README.defs
@@ -0,0 +1,351 @@
+ ChangeLog for this draft:
+ - caller-owns-return attribute on functions/methods
+ - include gtk-type-id in the type alias system
+ - c-name for types converted to in-c-name out-c-name inout-c-name
+ - merge unref-func and destroy-func for boxed types into release-func
+
+ - split structs out of boxed types
+ - c-declaration field
+ - special "native" type alias; bail and use C declaration when
+ necessary
+ - defined objects and boxeds automatically create a module
+ - make constructors functions and not methods, in appropriate
+ object/boxed module
+
+ Draft =========================
+
+ The overall syntax is:
+
+ (type-of-thing-being-defined name-used-to-refer-to-this-thing
+ (attribute-name attribute-value-depending-on-the-attribute)
+ (attribute-name attribute-value-depending-on-the-attribute)
+ (attribute-name attribute-value-depending-on-the-attribute))
+
+ Some definitions can have a c-declaration field that gives the C code
+ we parsed to arrive at the definition. The c-declaration is a quoted
+ string because it can contain parentheses and such.
+
+ Defined types and their attributes:
+
+ ===
+ (module module-name
+ (submodule-of module-name)) ;; submodule is optional
+
+ Ex: (module Gtk)
+ Ex: (module Rgb
+ (submodule-of Gdk))
+
+ modules are later referred to with a list of module names, like
+ (Gdk Rgb) or (Gtk)
+
+ Object and boxed type definitions automatically create a submodule.
+ For example, GtkCList creates the module (module CList (submodule-of
+ (Gtk))) which is referred to as module (Gtk CList).
+
+ ===
+
+ (type
+ (alias some-unique-identifier)
+ (in-module module-name) ;; optional, gchar* is not in a module
+ (gtk-type-id gtk-type-system-id) ;; optional, absent if this is not
+ ;; in the type system
+ (in-c-name name-of-symbol-in-C)
+ (out-c-name name-of-symbol-in-C)
+ (inout-c-name name-of-symbol-in-C))
+
+ Ex: (type
+ (alias string)
+ (gtk-type-id GTK_TYPE_STRING)
+ (in-c-name const-gchar*)
+ (out-c-name gchar**) ;; actually I'm not sure how strings work
+ out/inout
+ (inout-c-name gchar*))
+
+ ;; This one would be implied by the (object) def for GtkWidget I
+ ;; think - (type) is only required for types that are not implied
+ ;; by other definitions, such as int/boolean/etc.
+
+ (type
+ (alias GtkWidget)
+ (in-module (Gtk))
+ (gtk-type-id GTK_TYPE_WIDGET)
+ (in-c-name GtkWidget*)
+ (inout-c-name GtkWidget*)
+ (out-c-name GtkWidget**))
+
+ "Type" bindings are automatically assumed for objects, boxed types,
+ etc. as defined below.
+
+ The alias field is used to refer to the type later on.
+
+ If the C type has spaces they are converted to hyphens after
+ compressing all syntactically significant whitespace to a single
+ space:
+ (type
+ (alias const-gchar*
+ (c-name const-gchar*)))
+
+ So hyphens have to go back to spaces for binding generators that
+ output C code.
+
+ Whenever a type alias can be used, it is also possible to use the
+ keyword "native", which implies that the type in question is too
+ C-specific to represent. Then a c-declaration will typically be
+ available for use.
+
+ C types containing [] or () are function pointers or arrays. For
+ arrays that don't specify a size, we just treat them as pointers. For
+ function pointers, we need special (type) syntax/attributes of some
+ kind, but since there basically aren't any of these right now in the
+ libs we care about we can just ignore them. For arrays that specify a
+ size ditto, you would handle them by adding an (array-size) attribute
+ or something or using the "native" keyword and skipping the (type)
+ stuff.
+
+ ===
+ (object object-name
+ (in-module module-name-list)
+ (parent object-name optional-module-name-if-different)
+ (abstract boolean-is-abstract-class) ;; omit for default of #f
+ (c-name name-of-the-object-in-C)
+ (field (type-and-name type-alias-of-struct-field
+ name-of-struct-field)
+ (access read-or-write-or-readwrite)))
+
+
+ Ex: (object Widget
+ (in-module (Gtk))
+ (parent Object) ;; could say (parent Object (Gtk))
+ (abstract #t)
+ (c-name GtkWidget)
+ (field (type-and-name GdkWindow* window) (access read)))
+
+ An "object" declaration automatically implies the type definition:
+
+ (type
+ (alias concat-module-elements-and-object-name)
+ (in-c-name pointer-to-c-name)
+ (out-c-name pointer-to-pointer-to-c-name)
+ (inout-c-name pointer-to-c-name))
+
+ Ex:
+ (type (alias GtkWidget)
+ (in-c-name GtkWidget*)
+ (out-c-name GtkWidget**)
+ (inout-c-name GtkWidget*))
+
+ It also implies a module that is the name broken into parts:
+ (module CTree
+ (submodule-of Gtk))
+
+ ===
+
+ (function function-name
+ (in-module module-name-list) ;; "static methods" go in their
+ ;; object's module
+ (is-constructor-of object-type-alias) ;; optional, marks a
+ constructor
+ (c-name function-name)
+ (return-type return-value-type) ;; defaults to void
+ (caller-owns-return boolean-value) ;; defaults to #f
+ (parameter in-or-out-or-inout
+ (type-and-name parameter-type-alias parameter-name)
+ (c-declaration "c-type-and-name")) ;; c-declaration only
+ required
+ ;; if the type alias is
+ "native"
+ (varargs #t) ;; has varargs at the end
+ )
+
+ Ex:
+ (function init
+ (in-module (Gdk Rgb)
+ (c-name gdk_rgb_init)))
+
+ Ex:
+ (function new
+ (in-module (Gdk Rgb Cmap))
+ (is-constructor-of GdkRgbCmap)
+ (c-name gdk_rgb_cmap_new)
+ (return-type GdkRgbCmap)
+ (caller-owns-return #t) ;; perhaps this could be implied by
+ is-constructor-of
+ (parameter in (type-and-name array-of-guint32 colors))
+ (parameter in (type-and-name gint n_colors)))
+
+ Ex:
+ (function config_set_set_handler
+ (in-module (Gnome))
+ (c-name gnome_config_set_set_handler)
+ (parameter in (type-and-name native func)
+ (c-declaration "void (*func)(void*)"))
+ (parameter in (type-and-name gpointer data)))
+
+ ===
+ (method method-name
+ (of-object object-name module-name)
+ ;; retval/arg attributes as for (function), but with first parameter
+
+ ;; omitted for non-constructors
+ )
+
+ Ex:
+ (method set_text
+ (of-object Label (Gtk))
+ (parameter (type-and-name const-gchar* str)))
+
+ ===
+ (object-argument arg-name
+ (of-object object-we-are-an-argument-of optional-objects-module)
+ (type argument-type) ;; not sure what to put for type
+ ;; flags all default to #f
+ (readable bool-value)
+ (writeable bool-value)
+ (run-action bool-value)
+ (construct-only bool-value))
+
+ Ex:
+ (object-argument label
+ (of-object Label (Gtk))
+ (type gchar*) ;; ????
+ (readable #t)
+ (writeable #t))
+
+ ===
+ (signal signal-name
+ (of-object object-we-are-a-signal-of optional-objects-module)
+ ;; return value and parameters as for a function, omitting the
+ object
+ ;; and user data parameters
+
+ ;; what other properties matter for a signal?
+ )
+
+ Ex:
+ (signal select_row
+ (of-object CList (Gtk))
+ ;; return type defaults to void
+ (parameter in (type-and-name gint row))
+ (parameter in (type-and-name gint column))
+ (parameter in (type-and-name GdkEvent* event)))
+
+ ===
+ (enum enum-name
+ (in-module modname)
+ (c-name name-in-c)
+ (value (name value-name-noprefixes-hyphen-lowercase) (c-name
+ value-c-name)))
+
+ Ex:
+
+ (enum DirectionType
+ (in-module Gtk)
+ (c-name GtkDirectionType)
+ (value (name tab-forward) (c-name GTK_DIR_TAB_FORWARD))
+ (value (name tab-backward) (c-name GTK_DIR_TAB_BACKWARD))
+ (value (name up) (c-name GTK_DIR_UP))
+ (value (name down) (c-name GTK_DIR_DOWN))
+ (value (name left) (c-name GTK_DIR_LEFT))
+ (value (name right) (c-name GTK_DIR_RIGHT)))
+
+ (enum Pos
+ (in-module (Gtk CTree))
+ (c-name GtkCTreePos)
+ (value (name before) (c-name GTK_CTREE_POS_BEFORE))
+ (value (name as-child) (c-name GTK_CTREE_POS_AS_CHILD))
+ (value (name after) (c-name GTK_CTREE_POS_AFTER)))
+
+ ===
+ (flags) is just like enum, but some bindings may wrap enums and flags
+ differently.
+
+ ===
+
+ (boxed boxed-name
+ (in-module modname)
+ (c-name c-name)
+ (ref-func func-to-increase-refcount)
+ (copy-func func-to-copy)
+ (release-func func-to-destroy-or-decrement-refcount)
+ (field (type-and-name type-alias-of-struct-field
+ name-of-struct-field) (access access-rule)))
+
+ It is never OK to use memcpy() to copy a boxed type, or use
+ malloc()/free() to alloc/free one.
+
+ Ex:
+
+ (boxed Pixmap
+ (in-module (Gdk))
+ (c-name GdkPixmap)
+ (ref-func pixmap_ref)
+ (unref-func pixmap_unref))
+
+ An "object" declaration automatically implies the type definition:
+
+ (type
+ (alias concat-module-elements-and-boxed-name)
+ (in-c-name pointer-to-c-name)
+ (out-c-name pointer-to-pointer-to-c-name)
+ (inout-c-name pointer-to-c-name))
+
+ Ex:
+ (type (alias GdkPixmap)
+ (in-c-name GdkPixmap*)
+ (out-c-name GdkPixmap**)
+ (inout-c-name GdkPixmap*))
+
+ ===
+
+ (struct struct-name
+ (in-module modname)
+ (c-name c-name)
+ (field (type-and-name type-alias-of-struct-field
+ name-of-struct-field) (access access-rule)))
+
+ Ex:
+ (struct Rectangle
+ (in-module (Gdk))
+ (c-name GdkRectangle)
+ (field (type-and-name gint16 x) (access readwrite))
+ (field (type-and-name gint16 y) (access readwrite))
+ (field (type-and-name guint16 width) (access readwrite))
+ (field (type-and-name guint16 height) (access readwrite)))
+
+ Implies GdkRectangle type alias:
+
+ (type (alias GdkRectangle)
+ (in-c-name GdkRectangle*)
+ (out-c-name GdkRectangle*) ;; note - not the same as boxed
+ types
+ (inout-c-name GdkRectangle*))
+
+ ===
+
+ (user-function name
+ (in-module module)
+ (c-name c-typedef-name)
+ ;; return-type and parameters as for (function)
+ )
+
+ Ex:
+
+ (user-function PrintFunc
+ (in-module (Gtk))
+ (parameter in (type-and-name gpointer func_data))
+ (parameter in (type-and-name gchar* str)))
+
+ ===
+
+ (typedef new-name
+ (in-module module)
+ (c-name c-full-name)
+ (orig-type alias-of-orig-type))
+
+ Ex:
+
+ (typedef Type
+ (in-module (Gtk))
+ (c-name GtkType)
+ (orig-type guint))
+
diff --git a/codegen/__init__.py b/codegen/__init__.py
new file mode 100644
index 0000000..86188f9
--- /dev/null
+++ b/codegen/__init__.py
@@ -0,0 +1,16 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+
+__all__ = [
+ 'argtypes',
+ 'codegen',
+ 'definitions',
+ 'defsparser',
+ 'docextract',
+ 'docgen',
+ 'h2def',
+ 'defsgen'
+ 'mergedefs',
+ 'mkskel',
+ 'override',
+ 'scmexpr'
+]
diff --git a/codegen/argtypes.py b/codegen/argtypes.py
new file mode 100644
index 0000000..b35f6ef
--- /dev/null
+++ b/codegen/argtypes.py
@@ -0,0 +1,1043 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+import string
+import keyword
+import struct
+
+py_ssize_t_clean = False
+
+class ArgTypeError(Exception):
+ pass
+
+class ArgTypeNotFoundError(ArgTypeError):
+ pass
+
+class ArgTypeConfigurationError(ArgTypeError):
+ pass
+
+
+class VarList:
+ """Nicely format a C variable list"""
+ def __init__(self):
+ self.vars = {}
+ def add(self, ctype, name):
+ if self.vars.has_key(ctype):
+ self.vars[ctype] = self.vars[ctype] + (name,)
+ else:
+ self.vars[ctype] = (name,)
+ def __str__(self):
+ ret = []
+ for type in self.vars.keys():
+ ret.append(' ')
+ ret.append(type)
+ ret.append(' ')
+ ret.append(string.join(self.vars[type], ', '))
+ ret.append(';\n')
+ if ret:
+ ret.append('\n')
+ return string.join(ret, '')
+ return ''
+
+class WrapperInfo:
+ """A class that holds information about variable defs, code
+ snippets, etcd for use in writing out the function/method
+ wrapper."""
+ def __init__(self):
+ self.varlist = VarList()
+ self.parsestr = ''
+ self.parselist = ['', 'kwlist']
+ self.codebefore = []
+ self.codeafter = []
+ self.arglist = []
+ self.kwlist = []
+ def get_parselist(self):
+ return string.join(self.parselist, ', ')
+ def get_codebefore(self):
+ return string.join(self.codebefore, '')
+ def get_codeafter(self):
+ return string.join(self.codeafter, '')
+ def get_arglist(self):
+ return string.join(self.arglist, ', ')
+ def get_varlist(self):
+ return str(self.varlist)
+ def get_kwlist(self):
+ ret = ' static char *kwlist[] = { %s };\n' % \
+ string.join(self.kwlist + [ 'NULL' ], ', ')
+ if not self.get_varlist():
+ ret = ret + '\n'
+ return ret
+
+ def add_parselist(self, codes, parseargs, keywords):
+ self.parsestr = self.parsestr + codes
+ for arg in parseargs:
+ self.parselist.append(arg)
+ for kw in keywords:
+ if keyword.iskeyword(kw):
+ kw = kw + '_'
+ self.kwlist.append('"%s"' % kw)
+
+class ArgType:
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ """Add code to the WrapperInfo instance to handle
+ parameter."""
+ raise RuntimeError, "write_param not implemented for %s" % \
+ self.__class__.__name__
+ def write_return(self, ptype, ownsreturn, info):
+ """Adds a variable named ret of the return type to
+ info.varlist, and add any required code to info.codeafter to
+ convert the return value to a python object."""
+ raise RuntimeError, "write_return not implemented for %s" % \
+ self.__class__.__name__
+
+class NoneArg(ArgType):
+ def write_return(self, ptype, ownsreturn, info):
+ info.codeafter.append(' Py_INCREF(Py_None);\n' +
+ ' return Py_None;')
+
+class StringArg(ArgType):
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt != None:
+ if pdflt != 'NULL': pdflt = '"' + pdflt + '"'
+ info.varlist.add('char', '*' + pname + ' = ' + pdflt)
+ else:
+ info.varlist.add('char', '*' + pname)
+ info.arglist.append(pname)
+ if pnull:
+ info.add_parselist('z', ['&' + pname], [pname])
+ else:
+ info.add_parselist('s', ['&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ if ownsreturn:
+ # have to free result ...
+ info.varlist.add('gchar', '*ret')
+ info.codeafter.append(' if (ret) {\n' +
+ ' PyObject *py_ret = PyString_FromString(ret);\n' +
+ ' g_free(ret);\n' +
+ ' return py_ret;\n' +
+ ' }\n' +
+ ' Py_INCREF(Py_None);\n' +
+ ' return Py_None;')
+ else:
+ info.varlist.add('const gchar', '*ret')
+ info.codeafter.append(' if (ret)\n' +
+ ' return PyString_FromString(ret);\n'+
+ ' Py_INCREF(Py_None);\n' +
+ ' return Py_None;')
+
+class UCharArg(ArgType):
+ # allows strings with embedded NULLs.
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add('guchar', '*' + pname + ' = "' + pdflt + '"')
+ else:
+ info.varlist.add('guchar', '*' + pname)
+ if py_ssize_t_clean:
+ info.varlist.add('Py_ssize_t', pname + '_len')
+ else:
+ info.varlist.add('int', pname + '_len')
+ info.arglist.append(pname)
+ if pnull:
+ info.add_parselist('z#', ['&' + pname, '&' + pname + '_len'],
+ [pname])
+ else:
+ info.add_parselist('s#', ['&' + pname, '&' + pname + '_len'],
+ [pname])
+
+class CharArg(ArgType):
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add('char', pname + " = '" + pdflt + "'")
+ else:
+ info.varlist.add('char', pname)
+ info.arglist.append(pname)
+ info.add_parselist('c', ['&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('gchar', 'ret')
+ info.codeafter.append(' return PyString_FromStringAndSize(&ret, 1);')
+class GUniCharArg(ArgType):
+ ret_tmpl = ('#if !defined(Py_UNICODE_SIZE) || Py_UNICODE_SIZE == 2\n'
+ ' if (ret > 0xffff) {\n'
+ ' PyErr_SetString(PyExc_RuntimeError, "returned character can not be represented in 16-bit unicode");\n'
+ ' return NULL;\n'
+ ' }\n'
+ '#endif\n'
+ ' py_ret = (Py_UNICODE)ret;\n'
+ ' return PyUnicode_FromUnicode(&py_ret, 1);\n')
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add('gunichar', pname + " = '" + pdflt + "'")
+ else:
+ info.varlist.add('gunichar', pname)
+ info.arglist.append(pname)
+ info.add_parselist('O&', ['pyg_pyobj_to_unichar_conv', '&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('gunichar', 'ret')
+ info.varlist.add('Py_UNICODE', 'py_ret')
+ info.codeafter.append(self.ret_tmpl)
+
+
+class IntArg(ArgType):
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add('int', pname + ' = ' + pdflt)
+ else:
+ info.varlist.add('int', pname)
+ info.arglist.append(pname)
+ info.add_parselist('i', ['&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('int', 'ret')
+ info.codeafter.append(' return PyInt_FromLong(ret);')
+
+class UIntArg(ArgType):
+ dflt = (' if (py_%(name)s) {\n'
+ ' if (PyLong_Check(py_%(name)s))\n'
+ ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n'
+ ' else if (PyInt_Check(py_%(name)s))\n'
+ ' %(name)s = PyInt_AsLong(py_%(name)s);\n'
+ ' else\n'
+ ' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n'
+ ' if (PyErr_Occurred())\n'
+ ' return NULL;\n'
+ ' }\n')
+ before = (' if (PyLong_Check(py_%(name)s))\n'
+ ' %(name)s = PyLong_AsUnsignedLong(py_%(name)s);\n'
+ ' else if (PyInt_Check(py_%(name)s))\n'
+ ' %(name)s = PyInt_AsLong(py_%(name)s);\n'
+ ' else\n'
+ ' PyErr_SetString(PyExc_TypeError, "Parameter \'%(name)s\' must be an int or a long");\n'
+ ' if (PyErr_Occurred())\n'
+ ' return NULL;\n')
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if not pdflt:
+ pdflt = '0';
+
+ info.varlist.add(ptype, pname + ' = ' + pdflt)
+ info.codebefore.append(self.dflt % {'name':pname})
+ info.varlist.add('PyObject', "*py_" + pname + ' = NULL')
+ info.arglist.append(pname)
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add(ptype, 'ret')
+ info.codeafter.append(' return PyLong_FromUnsignedLong(ret);')
+
+class SizeArg(ArgType):
+
+ if struct.calcsize('P') <= struct.calcsize('l'):
+ llp64 = True
+ else:
+ llp64 = False
+
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add(ptype, pname + ' = ' + pdflt)
+ else:
+ info.varlist.add(ptype, pname)
+ info.arglist.append(pname)
+ if self.llp64:
+ info.add_parselist('k', ['&' + pname], [pname])
+ else:
+ info.add_parselist('K', ['&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add(ptype, 'ret')
+ if self.llp64:
+ info.codeafter.append(' return PyLong_FromUnsignedLongLong(ret);\n')
+ else:
+ info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n')
+
+class SSizeArg(ArgType):
+
+ if struct.calcsize('P') <= struct.calcsize('l'):
+ llp64 = True
+ else:
+ llp64 = False
+
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add(ptype, pname + ' = ' + pdflt)
+ else:
+ info.varlist.add(ptype, pname)
+ info.arglist.append(pname)
+ if self.llp64:
+ info.add_parselist('l', ['&' + pname], [pname])
+ else:
+ info.add_parselist('L', ['&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add(ptype, 'ret')
+ if self.llp64:
+ info.codeafter.append(' return PyLong_FromLongLong(ret);\n')
+ else:
+ info.codeafter.append(' return PyLong_FromLong(ret);\n')
+
+class LongArg(ArgType):
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add(ptype, pname + ' = ' + pdflt)
+ else:
+ info.varlist.add(ptype, pname)
+ info.arglist.append(pname)
+ info.add_parselist('l', ['&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add(ptype, 'ret')
+ info.codeafter.append(' return PyInt_FromLong(ret);\n')
+
+class BoolArg(IntArg):
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('int', 'ret')
+ info.codeafter.append(' return PyBool_FromLong(ret);\n')
+
+class TimeTArg(ArgType):
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add('time_t', pname + ' = ' + pdflt)
+ else:
+ info.varlist.add('time_t', pname)
+ info.arglist.append(pname)
+ info.add_parselist('i', ['&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('time_t', 'ret')
+ info.codeafter.append(' return PyInt_FromLong(ret);')
+
+class ULongArg(ArgType):
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add('unsigned long', pname + ' = ' + pdflt)
+ else:
+ info.varlist.add('unsigned long', pname)
+ info.arglist.append(pname)
+ info.add_parselist('k', ['&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add(ptype, 'ret')
+ info.codeafter.append(' return PyLong_FromUnsignedLong(ret);\n')
+
+class UInt32Arg(ULongArg):
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ ULongArg.write_param(self, ptype, pname, pdflt, pnull, info)
+ ## if sizeof(unsigned long) > sizeof(unsigned int), we need to
+ ## check the value is within guint32 range
+ if struct.calcsize('L') > struct.calcsize('I'):
+ info.codebefore.append((
+ ' if (%(pname)s > G_MAXUINT32) {\n'
+ ' PyErr_SetString(PyExc_ValueError,\n'
+ ' "Value out of range in conversion of"\n'
+ ' " %(pname)s parameter to unsigned 32 bit integer");\n'
+ ' return NULL;\n'
+ ' }\n') % vars())
+
+class Int64Arg(ArgType):
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add('gint64', pname + ' = ' + pdflt)
+ else:
+ info.varlist.add('gint64', pname)
+ info.arglist.append(pname)
+ info.add_parselist('L', ['&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('gint64', 'ret')
+ info.codeafter.append(' return PyLong_FromLongLong(ret);')
+
+class UInt64Arg(ArgType):
+ dflt = ' if (py_%(name)s)\n' \
+ ' %(name)s = PyLong_AsUnsignedLongLong(py_%(name)s);\n'
+ before = ' %(name)s = PyLong_AsUnsignedLongLong(py_%(name)s);\n'
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add('guint64', pname + ' = ' + pdflt)
+ info.codebefore.append(self.dflt % {'name':pname})
+ else:
+ info.varlist.add('guint64', pname)
+ info.codebefore.append(self.before % {'name':pname})
+ info.varlist.add('PyObject', "*py_" + pname + ' = NULL')
+ info.arglist.append(pname)
+ info.add_parselist('O!', ['&PyLong_Type', '&py_' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('guint64', 'ret')
+ info.codeafter.append(' return PyLong_FromUnsignedLongLong(ret);')
+
+
+class DoubleArg(ArgType):
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add('double', pname + ' = ' + pdflt)
+ else:
+ info.varlist.add('double', pname)
+ info.arglist.append(pname)
+ info.add_parselist('d', ['&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('double', 'ret')
+ info.codeafter.append(' return PyFloat_FromDouble(ret);')
+
+class FileArg(ArgType):
+ nulldflt = (' if (py_%(name)s == Py_None)\n'
+ ' %(name)s = NULL;\n'
+ ' else if (py_%(name)s && PyFile_Check(py_%(name)s)\n'
+ ' %s = PyFile_AsFile(py_%(name)s);\n'
+ ' else if (py_%(name)s) {\n'
+ ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a file object or None");\n'
+ ' return NULL;\n'
+ ' }')
+ null = (' if (py_%(name)s && PyFile_Check(py_%(name)s)\n'
+ ' %(name)s = PyFile_AsFile(py_%(name)s);\n'
+ ' else if (py_%(name)s != Py_None) {\n'
+ ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a file object or None");\n'
+ ' return NULL;\n'
+ ' }\n')
+ dflt = (' if (py_%(name)s)\n'
+ ' %(name)s = PyFile_AsFile(py_%(name)s);\n')
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pnull:
+ if pdflt:
+ info.varlist.add('FILE', '*' + pname + ' = ' + pdflt)
+ info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+ info.codebefore.append(self.nulldflt % {'name':pname})
+ else:
+ info.varlist.add('FILE', '*' + pname + ' = NULL')
+ info.varlist.add('PyObject', '*py_' + pname)
+ info.codebefore.append(self.null & {'name':pname})
+ info.arglist.appned(pname)
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ else:
+ if pdflt:
+ info.varlist.add('FILE', '*' + pname + ' = ' + pdflt)
+ info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+ info.codebefore.append(self.dflt % {'name':pname})
+ info.arglist.append(pname)
+ else:
+ info.varlist.add('PyObject', '*' + pname)
+ info.arglist.append('PyFile_AsFile(' + pname + ')')
+ info.add_parselist('O!', ['&PyFile_Type', '&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('FILE', '*ret')
+ info.codeafter.append(' if (ret)\n' +
+ ' return PyFile_FromFile(ret, "", "", fclose);\n' +
+ ' Py_INCREF(Py_None);\n' +
+ ' return Py_None;')
+
+class EnumArg(ArgType):
+ enum = (' if (pyg_enum_get_value(%(typecode)s, py_%(name)s, (gpointer)&%(name)s))\n'
+ ' return NULL;\n')
+ def __init__(self, enumname, typecode):
+ self.enumname = enumname
+ self.typecode = typecode
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add(self.enumname, pname + ' = ' + pdflt)
+ else:
+ info.varlist.add(self.enumname, pname)
+ info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+ info.codebefore.append(self.enum % { 'typecode': self.typecode,
+ 'name': pname})
+ info.arglist.append(pname)
+ info.add_parselist('O', ['&py_' + pname], [pname]);
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('gint', 'ret')
+ info.codeafter.append(' return pyg_enum_from_gtype(%s, ret);' % self.typecode)
+
+class FlagsArg(ArgType):
+ flag = (' if (%(default)spyg_flags_get_value(%(typecode)s, py_%(name)s, (gpointer)&%(name)s))\n'
+ ' return NULL;\n')
+ def __init__(self, flagname, typecode):
+ self.flagname = flagname
+ self.typecode = typecode
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add(self.flagname, pname + ' = ' + pdflt)
+ default = "py_%s && " % (pname,)
+ else:
+ info.varlist.add(self.flagname, pname)
+ default = ""
+ info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+ info.codebefore.append(self.flag % {'default':default,
+ 'typecode':self.typecode,
+ 'name':pname})
+ info.arglist.append(pname)
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('guint', 'ret')
+ info.codeafter.append(' return pyg_flags_from_gtype(%s, ret);' % self.typecode)
+
+class ObjectArg(ArgType):
+ # should change these checks to more typesafe versions that check
+ # a little further down in the class heirachy.
+ nulldflt = (' if ((PyObject *)py_%(name)s == Py_None)\n'
+ ' %(name)s = NULL;\n'
+ ' else if (py_%(name)s && pygobject_check(py_%(name)s, &Py%(type)s_Type))\n'
+ ' %(name)s = %(cast)s(py_%(name)s->obj);\n'
+ ' else if (py_%(name)s) {\n'
+ ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
+ ' return NULL;\n'
+ ' }\n')
+ null = (' if (py_%(name)s && pygobject_check(py_%(name)s, &Py%(type)s_Type))\n'
+ ' %(name)s = %(cast)s(py_%(name)s->obj);\n'
+ ' else if ((PyObject *)py_%(name)s != Py_None) {\n'
+ ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
+ ' return NULL;\n'
+ ' }\n')
+ dflt = ' if (py_%(name)s)\n' \
+ ' %(name)s = %(cast)s(py_%(name)s->obj);\n'
+ def __init__(self, objname, parent, typecode):
+ self.objname = objname
+ self.cast = string.replace(typecode, '_TYPE_', '_', 1)
+ self.parent = parent
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pnull:
+ if pdflt:
+ info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
+ info.varlist.add('PyGObject', '*py_' + pname + ' = NULL')
+ info.codebefore.append(self.nulldflt % {'name':pname,
+ 'cast':self.cast,
+ 'type':self.objname})
+ else:
+ info.varlist.add(self.objname, '*' + pname + ' = NULL')
+ info.varlist.add('PyGObject', '*py_' + pname)
+ info.codebefore.append(self.null % {'name':pname,
+ 'cast':self.cast,
+ 'type':self.objname})
+ if ptype.endswith('*'):
+ typename = ptype[:-1]
+ try:
+ const, typename = typename.split('const-')
+ except ValueError:
+ const = ''
+ if typename != ptype:
+ info.arglist.append('(%s *) %s' % (ptype[:-1], pname))
+ else:
+ info.arglist.append(pname)
+
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ else:
+ if pdflt:
+ info.varlist.add(self.objname, '*' + pname + ' = ' + pdflt)
+ info.varlist.add('PyGObject', '*py_' + pname + ' = NULL')
+ info.codebefore.append(self.dflt % {'name':pname,
+ 'cast':self.cast})
+ info.arglist.append(pname)
+ info.add_parselist('O!', ['&Py%s_Type' % self.objname,
+ '&py_' + pname], [pname])
+ else:
+ info.varlist.add('PyGObject', '*' + pname)
+ info.arglist.append('%s(%s->obj)' % (self.cast, pname))
+ info.add_parselist('O!', ['&Py%s_Type' % self.objname,
+ '&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ if ptype.endswith('*'):
+ typename = ptype[:-1]
+ try:
+ const, typename = typename.split('const-')
+ except ValueError:
+ const = ''
+ info.varlist.add(typename, '*ret')
+ if ownsreturn:
+ info.varlist.add('PyObject', '*py_ret')
+ info.codeafter.append(' py_ret = pygobject_new((GObject *)ret);\n'
+ ' if (ret != NULL)\n'
+ ' g_object_unref(ret);\n'
+ ' return py_ret;')
+ else:
+ info.codeafter.append(' /* pygobject_new handles NULL checking */\n' +
+ ' return pygobject_new((GObject *)ret);')
+
+class BoxedArg(ArgType):
+ # haven't done support for default args. Is it needed?
+ check = (' if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n'
+ ' %(name)s = pyg_boxed_get(py_%(name)s, %(typename)s);\n'
+ ' else {\n'
+ ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s");\n'
+ ' return NULL;\n'
+ ' }\n')
+ null = (' if (pyg_boxed_check(py_%(name)s, %(typecode)s))\n'
+ ' %(name)s = pyg_boxed_get(py_%(name)s, %(typename)s);\n'
+ ' else if (py_%(name)s != Py_None) {\n'
+ ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s or None");\n'
+ ' return NULL;\n'
+ ' }\n')
+ def __init__(self, ptype, typecode):
+ self.typename = ptype
+ self.typecode = typecode
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pnull:
+ info.varlist.add(self.typename, '*' + pname + ' = NULL')
+ info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
+ info.codebefore.append(self.null % {'name': pname,
+ 'typename': self.typename,
+ 'typecode': self.typecode})
+ else:
+ info.varlist.add(self.typename, '*' + pname + ' = NULL')
+ info.varlist.add('PyObject', '*py_' + pname)
+ info.codebefore.append(self.check % {'name': pname,
+ 'typename': self.typename,
+ 'typecode': self.typecode})
+ if ptype[-1] == '*':
+ typename = ptype[:-1]
+ if typename[:6] == 'const-': typename = typename[6:]
+ if typename != self.typename:
+ info.arglist.append('(%s *)%s' % (ptype[:-1], pname))
+ else:
+ info.arglist.append(pname)
+ else:
+ info.arglist.append(pname)
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ ret_tmpl = ' /* pyg_boxed_new handles NULL checking */\n' \
+ ' return pyg_boxed_new(%(typecode)s, %(ret)s, %(copy)s, TRUE);'
+ def write_return(self, ptype, ownsreturn, info):
+ if ptype[-1] == '*':
+ decl_type = self.typename
+ ret = 'ret'
+ if ptype[:6] == 'const-':
+ decl_type = 'const ' + self.typename
+ ret = '(%s*) ret' % (self.typename,)
+ info.varlist.add(decl_type, '*ret')
+ else:
+ info.varlist.add(self.typename, 'ret')
+ ret = '&ret'
+ ownsreturn = 0 # of course it can't own a ref to a local var ...
+ info.codeafter.append(self.ret_tmpl %
+ { 'typecode': self.typecode,
+ 'ret': ret,
+ 'copy': ownsreturn and 'FALSE' or 'TRUE'})
+
+class CustomBoxedArg(ArgType):
+ # haven't done support for default args. Is it needed?
+ null = (' if (%(check)s(py_%(name)s))\n'
+ ' %(name)s = %(get)s(py_%(name)s);\n'
+ ' else if (py_%(name)s != Py_None) {\n'
+ ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(type)s or None");\n'
+ ' return NULL;\n'
+ ' }\n')
+ def __init__(self, ptype, pytype, getter, new):
+ self.pytype = pytype
+ self.getter = getter
+ self.checker = 'Py' + ptype + '_Check'
+ self.new = new
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pnull:
+ info.varlist.add(ptype[:-1], '*' + pname + ' = NULL')
+ info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
+ info.codebefore.append(self.null % {'name': pname,
+ 'get': self.getter,
+ 'check': self.checker,
+ 'type': ptype[:-1]})
+ info.arglist.append(pname)
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ else:
+ info.varlist.add('PyObject', '*' + pname)
+ info.arglist.append(self.getter + '(' + pname + ')')
+ info.add_parselist('O!', ['&' + self.pytype, '&' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add(ptype[:-1], '*ret')
+ info.codeafter.append(' if (ret)\n' +
+ ' return ' + self.new + '(ret);\n' +
+ ' Py_INCREF(Py_None);\n' +
+ ' return Py_None;')
+
+class PointerArg(ArgType):
+ # haven't done support for default args. Is it needed?
+ check = (' if (pyg_pointer_check(py_%(name)s, %(typecode)s))\n'
+ ' %(name)s = pyg_pointer_get(py_%(name)s, %(typename)s);\n'
+ ' else {\n'
+ ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s");\n'
+ ' return NULL;\n'
+ ' }\n')
+ null = (' if (pyg_pointer_check(py_%(name)s, %(typecode)s))\n'
+ ' %(name)s = pyg_pointer_get(py_%(name)s, %(typename)s);\n'
+ ' else if (py_%(name)s != Py_None) {\n'
+ ' PyErr_SetString(PyExc_TypeError, "%(name)s should be a %(typename)s or None");\n'
+ ' return NULL;\n'
+ ' }\n')
+ def __init__(self, ptype, typecode):
+ self.typename = ptype
+ self.typecode = typecode
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pnull:
+ info.varlist.add(self.typename, '*' + pname + ' = NULL')
+ info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
+ info.codebefore.append(self.null % {'name': pname,
+ 'typename': self.typename,
+ 'typecode': self.typecode})
+ else:
+ info.varlist.add(self.typename, '*' + pname + ' = NULL')
+ info.varlist.add('PyObject', '*py_' + pname)
+ info.codebefore.append(self.check % {'name': pname,
+ 'typename': self.typename,
+ 'typecode': self.typecode})
+ info.arglist.append(pname)
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ if ptype[-1] == '*':
+ info.varlist.add(self.typename, '*ret')
+ info.codeafter.append(' /* pyg_pointer_new handles NULL checking */\n' +
+ ' return pyg_pointer_new(' + self.typecode + ', ret);')
+ else:
+ info.varlist.add(self.typename, 'ret')
+ info.codeafter.append(' /* pyg_pointer_new handles NULL checking */\n' +
+ ' return pyg_pointer_new(' + self.typecode + ', &ret);')
+
+class AtomArg(IntArg):
+ dflt = ' if (py_%(name)s) {\n' \
+ ' %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n' \
+ ' if (PyErr_Occurred())\n' \
+ ' return NULL;\n' \
+ ' }\n'
+ atom = (' %(name)s = pygdk_atom_from_pyobject(py_%(name)s);\n'
+ ' if (PyErr_Occurred())\n'
+ ' return NULL;\n')
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pdflt:
+ info.varlist.add('GdkAtom', pname + ' = ' + pdflt)
+ info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+ info.codebefore.append(self.dflt % {'name': pname})
+ else:
+ info.varlist.add('GdkAtom', pname)
+ info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+ info.codebefore.append(self.atom % {'name': pname})
+ info.arglist.append(pname)
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('GdkAtom', 'ret')
+ info.varlist.add('PyObject *', 'py_ret')
+ info.varlist.add('gchar *', 'name')
+ info.codeafter.append(' name = gdk_atom_name(ret);\n'
+ ' py_ret = PyString_FromString(name);\n'
+ ' g_free(name);\n'
+ ' return py_ret;')
+
+class GTypeArg(ArgType):
+ gtype = (' if ((%(name)s = pyg_type_from_object(py_%(name)s)) == 0)\n'
+ ' return NULL;\n')
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ info.varlist.add('GType', pname)
+ info.varlist.add('PyObject', '*py_' + pname + ' = NULL')
+ info.codebefore.append(self.gtype % {'name': pname})
+ info.arglist.append(pname)
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('GType', 'ret')
+ info.codeafter.append(' return pyg_type_wrapper_new(ret);')
+
+# simple GError handler.
+class GErrorArg(ArgType):
+ handleerror = (' if (pyg_error_check(&%(name)s))\n'
+ ' return NULL;\n')
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ info.varlist.add('GError', '*' + pname + ' = NULL')
+ info.arglist.append('&' + pname)
+ info.codeafter.append(self.handleerror % { 'name': pname })
+
+class GtkTreePathArg(ArgType):
+ # haven't done support for default args. Is it needed?
+ normal = (' %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n'
+ ' if (!%(name)s) {\n'
+ ' PyErr_SetString(PyExc_TypeError, "could not convert %(name)s to a GtkTreePath");\n'
+ ' return NULL;\n'
+ ' }\n')
+ null = (' if (py_%(name)s != Py_None) {\n'
+ ' %(name)s = pygtk_tree_path_from_pyobject(py_%(name)s);\n'
+ ' if (!%(name)s) {\n'
+ ' PyErr_SetString(PyExc_TypeError, "could not convert %(name)s to a GtkTreePath");\n'
+ ' return NULL;\n'
+ ' }\n'
+ ' }\n')
+ freepath = (' if (%(name)s)\n'
+ ' gtk_tree_path_free(%(name)s);\n')
+ def __init__(self):
+ pass
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pnull:
+ info.varlist.add('GtkTreePath', '*' + pname + ' = NULL')
+ info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
+ info.codebefore.append(self.null % {'name': pname})
+ info.arglist.append(pname)
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ else:
+ info.varlist.add('GtkTreePath', '*' + pname)
+ info.varlist.add('PyObject', '*py_' + pname)
+ info.codebefore.append(self.normal % {'name': pname})
+ info.arglist.append(pname)
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ info.codeafter.append(self.freepath % {'name': pname})
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('GtkTreePath', '*ret')
+ if ownsreturn:
+ info.codeafter.append(' if (ret) {\n'
+ ' PyObject *py_ret = pygtk_tree_path_to_pyobject(ret);\n'
+ ' gtk_tree_path_free(ret);\n'
+ ' return py_ret;\n'
+ ' }\n'
+ ' Py_INCREF(Py_None);\n'
+ ' return Py_None;')
+ else:
+ info.codeafter.append(' if (ret) {\n'
+ ' PyObject *py_ret = pygtk_tree_path_to_pyobject(ret);\n'
+ ' return py_ret;\n'
+ ' }\n'
+ ' Py_INCREF(Py_None);\n'
+ ' return Py_None;')
+
+class GdkRectanglePtrArg(ArgType):
+ normal = (' if (!pygdk_rectangle_from_pyobject(py_%(name)s, &%(name)s))\n'
+ ' return NULL;\n')
+ null = (' if (py_%(name)s == Py_None)\n'
+ ' %(name)s = NULL;\n'
+ ' else if (pygdk_rectangle_from_pyobject(py_%(name)s, &%(name)s_rect))\n'
+ ' %(name)s = &%(name)s_rect;\n'
+ ' else\n'
+ ' return NULL;\n')
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ if pnull:
+ info.varlist.add('GdkRectangle', pname + '_rect = { 0, 0, 0, 0 }')
+ info.varlist.add('GdkRectangle', '*' + pname)
+ info.varlist.add('PyObject', '*py_' + pname + ' = Py_None')
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ info.arglist.append(pname)
+ info.codebefore.append(self.null % {'name': pname})
+ else:
+ info.varlist.add('GdkRectangle', pname + ' = { 0, 0, 0, 0 }')
+ info.varlist.add('PyObject', '*py_' + pname)
+ info.add_parselist('O', ['&py_' + pname], [pname])
+ info.arglist.append('&' + pname)
+ info.codebefore.append(self.normal % {'name': pname})
+
+class GdkRectangleArg(ArgType):
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add('GdkRectangle', 'ret')
+ info.codeafter.append(' return pyg_boxed_new(GDK_TYPE_RECTANGLE, &ret, TRUE, TRUE);')
+
+class PyObjectArg(ArgType):
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ info.varlist.add('PyObject', '*' + pname)
+ info.add_parselist('O', ['&' + pname], [pname])
+ info.arglist.append(pname)
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add("PyObject", "*ret")
+ if ownsreturn:
+ info.codeafter.append(' if (ret) {\n'
+ ' return ret;\n'
+ ' }\n'
+ ' Py_INCREF(Py_None);\n'
+ ' return Py_None;')
+ else:
+ info.codeafter.append(' if (!ret) ret = Py_None;\n'
+ ' Py_INCREF(ret);\n'
+ ' return ret;')
+
+class CairoArg(ArgType):
+ def write_param(self, ptype, pname, pdflt, pnull, info):
+ info.varlist.add('PycairoContext', '*' + pname)
+ info.add_parselist('O!', ['&PycairoContext_Type', '&' + pname], [pname])
+ info.arglist.append('%s->ctx' % pname)
+ def write_return(self, ptype, ownsreturn, info):
+ info.varlist.add("cairo_t", "*ret")
+ if ownsreturn:
+ info.codeafter.append(' return PycairoContext_FromContext(ret, NULL, NULL);')
+ else:
+ info.codeafter.append(' cairo_reference(ret);\n'
+ ' return PycairoContext_FromContext(ret, NULL, NULL);')
+
+
+class ArgMatcher:
+ def __init__(self):
+ self.argtypes = {}
+ self.reverse_argtypes = {}
+ self.reverse_rettypes = {}
+
+ def register(self, ptype, handler, overwrite=False):
+ if not overwrite and ptype in self.argtypes:
+ return
+ self.argtypes[ptype] = handler
+ def register_reverse(self, ptype, handler):
+ self.reverse_argtypes[ptype] = handler
+ def register_reverse_ret(self, ptype, handler):
+ self.reverse_rettypes[ptype] = handler
+
+ def register_enum(self, ptype, typecode):
+ if typecode is None:
+ self.register(ptype, IntArg())
+ else:
+ self.register(ptype, EnumArg(ptype, typecode))
+ def register_flag(self, ptype, typecode):
+ if typecode is None:
+ self.register(ptype, IntArg())
+ else:
+ self.register(ptype, FlagsArg(ptype, typecode))
+ def register_object(self, ptype, parent, typecode):
+ oa = ObjectArg(ptype, parent, typecode)
+ self.register(ptype, oa) # in case I forget the * in the .defs
+ self.register(ptype+'*', oa)
+ self.register('const-'+ptype+'*', oa)
+ if ptype == 'GdkPixmap':
+ # hack to handle GdkBitmap synonym.
+ self.register('GdkBitmap', oa)
+ self.register('GdkBitmap*', oa)
+ def register_boxed(self, ptype, typecode):
+ if self.argtypes.has_key(ptype): return
+ arg = BoxedArg(ptype, typecode)
+ self.register(ptype, arg)
+ self.register(ptype+'*', arg)
+ self.register('const-'+ptype+'*', arg)
+ def register_custom_boxed(self, ptype, pytype, getter, new):
+ arg = CustomBoxedArg(ptype, pytype, getter, new)
+ self.register(ptype+'*', arg)
+ self.register('const-'+ptype+'*', arg)
+ def register_pointer(self, ptype, typecode):
+ arg = PointerArg(ptype, typecode)
+ self.register(ptype, arg)
+ self.register(ptype+'*', arg)
+ self.register('const-'+ptype+'*', arg)
+
+ def get(self, ptype):
+ try:
+ return self.argtypes[ptype]
+ except KeyError:
+ if ptype[:8] == 'GdkEvent' and ptype[-1] == '*':
+ return self.argtypes['GdkEvent*']
+ raise ArgTypeNotFoundError("No ArgType for %s" % (ptype,))
+ def _get_reverse_common(self, ptype, registry):
+ props = dict(c_type=ptype)
+ try:
+ return registry[ptype], props
+ except KeyError:
+ try:
+ handler = self.argtypes[ptype]
+ except KeyError:
+ if ptype.startswith('GdkEvent') and ptype.endswith('*'):
+ handler = self.argtypes['GdkEvent*']
+ else:
+ raise ArgTypeNotFoundError("No ArgType for %s" % (ptype,))
+ if isinstance(handler, ObjectArg):
+ return registry['GObject*'], props
+ elif isinstance(handler, EnumArg):
+ props['typecode'] = handler.typecode
+ props['enumname'] = handler.enumname
+ return registry['GEnum'], props
+ elif isinstance(handler, FlagsArg):
+ props['typecode'] = handler.typecode
+ props['flagname'] = handler.flagname
+ return registry['GFlags'], props
+ elif isinstance(handler, BoxedArg):
+ props['typecode'] = handler.typecode
+ props['typename'] = handler.typename
+ return registry['GBoxed'], props
+ else:
+ raise ArgTypeNotFoundError("No ArgType for %s" % (ptype,))
+
+ def get_reverse(self, ptype):
+ return self._get_reverse_common(ptype, self.reverse_argtypes)
+
+ def get_reverse_ret(self, ptype):
+ ret, props = self._get_reverse_common(ptype, self.reverse_rettypes)
+ if hasattr(ptype, 'optional') and ptype.optional:
+ if ret.supports_optional:
+ props['optional'] = True
+ else:
+ raise ArgTypeNotFoundError("Unsupported 'optional' for %s"
+ % (ptype,))
+ return ret, props
+
+ def object_is_a(self, otype, parent):
+ if otype == None: return 0
+ if otype == parent: return 1
+ if not self.argtypes.has_key(otype): return 0
+ return self.object_is_a(self.get(otype).parent, parent)
+
+matcher = ArgMatcher()
+
+arg = NoneArg()
+matcher.register(None, arg)
+matcher.register('none', arg)
+
+arg = StringArg()
+matcher.register('char*', arg)
+matcher.register('gchar*', arg)
+matcher.register('const-char*', arg)
+matcher.register('char-const*', arg)
+matcher.register('const-gchar*', arg)
+matcher.register('gchar-const*', arg)
+matcher.register('string', arg)
+matcher.register('static_string', arg)
+
+arg = UCharArg()
+matcher.register('unsigned-char*', arg)
+matcher.register('const-guchar*', arg)
+matcher.register('const-guint8*', arg)
+matcher.register('guchar*', arg)
+
+arg = CharArg()
+matcher.register('char', arg)
+matcher.register('gchar', arg)
+matcher.register('guchar', arg)
+
+arg = GUniCharArg()
+matcher.register('gunichar', arg)
+
+arg = IntArg()
+matcher.register('int', arg)
+matcher.register('gint', arg)
+matcher.register('short', arg)
+matcher.register('gshort', arg)
+matcher.register('gushort', arg)
+matcher.register('gsize', SizeArg())
+matcher.register('gssize', SSizeArg())
+matcher.register('guint8', arg)
+matcher.register('gint8', arg)
+matcher.register('guint16', arg)
+matcher.register('gint16', arg)
+matcher.register('gint32', arg)
+matcher.register('GTime', arg)
+matcher.register('GSeekType', arg) # Hack, but we have no python wrapper
+
+arg = LongArg()
+matcher.register('long', arg)
+matcher.register('glong', arg)
+
+arg = UIntArg()
+matcher.register('guint', arg)
+
+arg = BoolArg()
+matcher.register('gboolean', arg)
+
+arg = TimeTArg()
+matcher.register('time_t', arg)
+
+matcher.register('guint32', UInt32Arg())
+
+arg = ULongArg()
+matcher.register('gulong', arg)
+
+arg = Int64Arg()
+matcher.register('gint64', arg)
+matcher.register('long-long', arg)
+matcher.register('goffset', arg)
+
+arg = UInt64Arg()
+matcher.register('guint64', arg)
+matcher.register('unsigned-long-long', arg)
+
+arg = DoubleArg()
+matcher.register('double', arg)
+matcher.register('gdouble', arg)
+matcher.register('float', arg)
+matcher.register('gfloat', arg)
+
+arg = FileArg()
+matcher.register('FILE*', arg)
+
+# enums, flags, objects
+
+matcher.register('GdkAtom', AtomArg())
+
+matcher.register('GType', GTypeArg())
+matcher.register('GtkType', GTypeArg())
+
+matcher.register('GError**', GErrorArg())
+matcher.register('GtkTreePath*', GtkTreePathArg())
+matcher.register('GdkRectangle*', GdkRectanglePtrArg())
+matcher.register('GtkAllocation*', GdkRectanglePtrArg())
+matcher.register('GdkRectangle', GdkRectangleArg())
+matcher.register('PyObject*', PyObjectArg())
+
+matcher.register('GdkNativeWindow', ULongArg())
+
+matcher.register_object('GObject', None, 'G_TYPE_OBJECT')
+
+del arg
+
+matcher.register('cairo_t*', CairoArg())
+matcher.register_boxed("GClosure", "G_TYPE_CLOSURE")
diff --git a/codegen/code-coverage.py b/codegen/code-coverage.py
new file mode 100755
index 0000000..1dc54c3
--- /dev/null
+++ b/codegen/code-coverage.py
@@ -0,0 +1,44 @@
+#! /usr/bin/env python
+
+from __future__ import generators
+import sys, os
+
+def read_symbols(file, type=None, dynamic=0):
+ if dynamic:
+ cmd = 'nm -D %s' % file
+ else:
+ cmd = 'nm %s' % file
+ for line in os.popen(cmd, 'r'):
+ if line[0] != ' ': # has an address as first bit of line
+ while line[0] != ' ':
+ line = line[1:]
+ while line[0] == ' ':
+ line = line[1:]
+ # we should be up to "type symbolname" now
+ sym_type = line[0]
+ symbol = line[1:].strip()
+
+ if not type or type == sym_type:
+ yield symbol
+
+def main():
+ if len(sys.argv) != 3:
+ sys.stderr.write('usage: coverage-check library.so wrapper.so\n')
+ sys.exit(1)
+ library = sys.argv[1]
+ wrapper = sys.argv[2]
+
+ # first create a dict with all referenced symbols in the wrapper
+ # should really be a set, but a dict will do ...
+ wrapper_symbols = {}
+ for symbol in read_symbols(wrapper, type='U', dynamic=1):
+ wrapper_symbols[symbol] = 1
+
+ # now go through the library looking for matches on the defined symbols:
+ for symbol in read_symbols(library, type='T', dynamic=1):
+ if symbol[0] == '_': continue
+ if symbol not in wrapper_symbols:
+ print symbol
+
+if __name__ == '__main__':
+ main()
diff --git a/codegen/codegen.py b/codegen/codegen.py
new file mode 100755
index 0000000..008f01c
--- /dev/null
+++ b/codegen/codegen.py
@@ -0,0 +1,1722 @@
+#! /usr/bin/env python
+
+import getopt
+import keyword
+import os
+import string
+import sys
+
+import argtypes
+import definitions
+import defsparser
+import override
+import reversewrapper
+import warnings
+
+class Coverage(object):
+ def __init__(self, name):
+ self.name = name
+ self.wrapped = 0
+ self.not_wrapped = 0
+
+ def declare_wrapped(self):
+ self.wrapped += 1
+
+ def declare_not_wrapped(self):
+ self.not_wrapped += 1
+
+ def printstats(self):
+ total = self.wrapped + self.not_wrapped
+ fd = sys.stderr
+ if total:
+ fd.write("***INFO*** The coverage of %s is %.2f%% (%i/%i)\n" %
+ (self.name,
+ float(self.wrapped*100)/total,
+ self.wrapped,
+ total))
+ else:
+ fd.write("***INFO*** There are no declared %s.\n" % self.name)
+
+functions_coverage = Coverage("global functions")
+methods_coverage = Coverage("methods")
+vproxies_coverage = Coverage("virtual proxies")
+vaccessors_coverage = Coverage("virtual accessors")
+iproxies_coverage = Coverage("interface proxies")
+
+def exc_info():
+ warnings.warn("deprecated", DeprecationWarning, stacklevel=2)
+ #traceback.print_exc()
+ etype, value, tb = sys.exc_info()
+ ret = ""
+ try:
+ sval = str(value)
+ if etype == argtypes.ArgTypeError:
+ ret = "No ArgType for %s" % (sval,)
+ else:
+ ret = sval
+ finally:
+ del etype, value, tb
+ return ret
+
+def fixname(name):
+ if keyword.iskeyword(name):
+ return name + '_'
+ return name
+
+class FileOutput:
+ '''Simple wrapper for file object, that makes writing #line
+ statements easier.''' # "
+ def __init__(self, fp, filename=None):
+ self.fp = fp
+ self.lineno = 1
+ if filename:
+ self.filename = filename
+ else:
+ self.filename = self.fp.name
+ # handle writing to the file, and keep track of the line number ...
+ def write(self, str):
+ self.fp.write(str)
+ self.lineno = self.lineno + string.count(str, '\n')
+ def writelines(self, sequence):
+ for line in sequence:
+ self.write(line)
+ def close(self):
+ self.fp.close()
+ def flush(self):
+ self.fp.flush()
+
+ def setline(self, linenum, filename):
+ '''writes out a #line statement, for use by the C
+ preprocessor.''' # "
+ self.write('#line %d "%s"\n' % (linenum, filename))
+ def resetline(self):
+ '''resets line numbering to the original file'''
+ self.setline(self.lineno + 1, self.filename)
+
+class Wrapper:
+ type_tmpl = (
+ 'PyTypeObject G_GNUC_INTERNAL Py%(typename)s_Type = {\n'
+ ' PyObject_HEAD_INIT(NULL)\n'
+ ' 0, /* ob_size */\n'
+ ' "%(classname)s", /* tp_name */\n'
+ ' sizeof(%(tp_basicsize)s), /* tp_basicsize */\n'
+ ' 0, /* tp_itemsize */\n'
+ ' /* methods */\n'
+ ' (destructor)%(tp_dealloc)s, /* tp_dealloc */\n'
+ ' (printfunc)0, /* tp_print */\n'
+ ' (getattrfunc)%(tp_getattr)s, /* tp_getattr */\n'
+ ' (setattrfunc)%(tp_setattr)s, /* tp_setattr */\n'
+ ' (cmpfunc)%(tp_compare)s, /* tp_compare */\n'
+ ' (reprfunc)%(tp_repr)s, /* tp_repr */\n'
+ ' (PyNumberMethods*)%(tp_as_number)s, /* tp_as_number */\n'
+ ' (PySequenceMethods*)%(tp_as_sequence)s, /* tp_as_sequence */\n'
+ ' (PyMappingMethods*)%(tp_as_mapping)s, /* tp_as_mapping */\n'
+ ' (hashfunc)%(tp_hash)s, /* tp_hash */\n'
+ ' (ternaryfunc)%(tp_call)s, /* tp_call */\n'
+ ' (reprfunc)%(tp_str)s, /* tp_str */\n'
+ ' (getattrofunc)%(tp_getattro)s, /* tp_getattro */\n'
+ ' (setattrofunc)%(tp_setattro)s, /* tp_setattro */\n'
+ ' (PyBufferProcs*)%(tp_as_buffer)s, /* tp_as_buffer */\n'
+ ' %(tp_flags)s, /* tp_flags */\n'
+ ' %(tp_doc)s, /* Documentation string */\n'
+ ' (traverseproc)%(tp_traverse)s, /* tp_traverse */\n'
+ ' (inquiry)%(tp_clear)s, /* tp_clear */\n'
+ ' (richcmpfunc)%(tp_richcompare)s, /* tp_richcompare */\n'
+ ' %(tp_weaklistoffset)s, /* tp_weaklistoffset */\n'
+ ' (getiterfunc)%(tp_iter)s, /* tp_iter */\n'
+ ' (iternextfunc)%(tp_iternext)s, /* tp_iternext */\n'
+ ' (struct PyMethodDef*)%(tp_methods)s, /* tp_methods */\n'
+ ' (struct PyMemberDef*)0, /* tp_members */\n'
+ ' (struct PyGetSetDef*)%(tp_getset)s, /* tp_getset */\n'
+ ' NULL, /* tp_base */\n'
+ ' NULL, /* tp_dict */\n'
+ ' (descrgetfunc)%(tp_descr_get)s, /* tp_descr_get */\n'
+ ' (descrsetfunc)%(tp_descr_set)s, /* tp_descr_set */\n'
+ ' %(tp_dictoffset)s, /* tp_dictoffset */\n'
+ ' (initproc)%(tp_init)s, /* tp_init */\n'
+ ' (allocfunc)%(tp_alloc)s, /* tp_alloc */\n'
+ ' (newfunc)%(tp_new)s, /* tp_new */\n'
+ ' (freefunc)%(tp_free)s, /* tp_free */\n'
+ ' (inquiry)%(tp_is_gc)s /* tp_is_gc */\n'
+ '};\n\n'
+ )
+
+ slots_list = [
+ 'tp_getattr', 'tp_setattr', 'tp_getattro', 'tp_setattro',
+ 'tp_compare', 'tp_repr',
+ 'tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'tp_hash',
+ 'tp_call', 'tp_str', 'tp_as_buffer', 'tp_richcompare', 'tp_iter',
+ 'tp_iternext', 'tp_descr_get', 'tp_descr_set', 'tp_init',
+ 'tp_alloc', 'tp_new', 'tp_free', 'tp_is_gc',
+ 'tp_traverse', 'tp_clear', 'tp_dealloc', 'tp_flags', 'tp_doc'
+ ]
+
+ getter_tmpl = (
+ 'static PyObject *\n'
+ '%(funcname)s(PyObject *self, void *closure)\n'
+ '{\n'
+ '%(varlist)s'
+ ' ret = %(field)s;\n'
+ '%(codeafter)s\n'
+ '}\n\n'
+ )
+
+ parse_tmpl = (
+ ' if (!PyArg_ParseTupleAndKeywords(args, kwargs,'
+ '"%(typecodes)s:%(name)s"%(parselist)s))\n'
+ ' return %(errorreturn)s;\n'
+ )
+
+ deprecated_tmpl = (
+ ' if (PyErr_Warn(PyExc_DeprecationWarning, '
+ '"%(deprecationmsg)s") < 0)\n'
+ ' return %(errorreturn)s;\n'
+ )
+
+ methdef_tmpl = (
+ ' { "%(name)s", (PyCFunction)%(cname)s, %(flags)s,\n'
+ ' %(docstring)s },\n'
+ )
+
+ noconstructor = (
+ 'static int\n'
+ 'pygobject_no_constructor(PyObject *self, PyObject *args, '
+ 'PyObject *kwargs)\n'
+ '{\n'
+ ' gchar buf[512];\n'
+ '\n'
+ ' g_snprintf(buf, sizeof(buf), "%s is an abstract widget", '
+ 'self->ob_type->tp_name);\n'
+ ' PyErr_SetString(PyExc_NotImplementedError, buf);\n'
+ ' return -1;\n'
+ '}\n\n'
+ )
+
+ function_tmpl = (
+ 'static PyObject *\n'
+ '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n'
+ '{\n'
+ '%(varlist)s'
+ '%(parseargs)s'
+ '%(codebefore)s'
+ ' %(begin_allow_threads)s\n'
+ ' %(setreturn)s%(cname)s(%(arglist)s);\n'
+ ' %(end_allow_threads)s\n'
+ '%(codeafter)s\n'
+ '}\n\n'
+ )
+
+ virtual_accessor_tmpl = (
+ 'static PyObject *\n'
+ '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n'
+ '{\n'
+ ' gpointer klass;\n'
+ '%(varlist)s'
+ '%(parseargs)s'
+ '%(codebefore)s'
+ ' klass = g_type_class_ref(pyg_type_from_object(cls));\n'
+ ' if (%(class_cast_macro)s(klass)->%(virtual)s)\n'
+ ' %(setreturn)s%(class_cast_macro)s(klass)->'
+ '%(virtual)s(%(arglist)s);\n'
+ ' else {\n'
+ ' PyErr_SetString(PyExc_NotImplementedError, '
+ '"virtual method %(name)s not implemented");\n'
+ ' g_type_class_unref(klass);\n'
+ ' return NULL;\n'
+ ' }\n'
+ ' g_type_class_unref(klass);\n'
+ '%(codeafter)s\n'
+ '}\n\n'
+ )
+
+ # template for method calls
+ constructor_tmpl = None
+ method_tmpl = None
+
+ def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)):
+ self.parser = parser
+ self.objinfo = objinfo
+ self.overrides = overrides
+ self.fp = fp
+
+ def get_lower_name(self):
+ return string.lower(string.replace(self.objinfo.typecode,
+ '_TYPE_', '_', 1))
+
+ def get_field_accessor(self, fieldname):
+ raise NotImplementedError
+
+ def get_initial_class_substdict(self): return {}
+
+ def get_initial_constructor_substdict(self, constructor):
+ return { 'name': '%s.__init__' % self.objinfo.py_name,
+ 'errorreturn': '-1' }
+
+ def get_initial_method_substdict(self, method):
+ substdict = { 'name': '%s.%s' % (self.objinfo.py_name, method.name) }
+ if method.unblock_threads:
+ substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;'
+ substdict['end_allow_threads'] = 'pyg_end_allow_threads;'
+ else:
+ substdict['begin_allow_threads'] = ''
+ substdict['end_allow_threads'] = ''
+ return substdict
+
+ def write_class(self):
+ if self.overrides.is_type_ignored(self.objinfo.c_name):
+ return
+ self.fp.write('\n/* ----------- %s ----------- */\n\n' %
+ self.objinfo.c_name)
+ substdict = self.get_initial_class_substdict()
+ if not substdict.has_key('tp_flags'):
+ substdict['tp_flags'] = 'Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE'
+ substdict['typename'] = self.objinfo.c_name
+ if self.overrides.modulename:
+ substdict['classname'] = '%s.%s' % (self.overrides.modulename,
+ self.objinfo.name)
+ else:
+ substdict['classname'] = self.objinfo.name
+ substdict['tp_doc'] = self.objinfo.docstring
+
+ # Maybe this could be done in a nicer way, but I'll leave it as it is
+ # for now: -- Johan
+ if not self.overrides.slot_is_overriden('%s.tp_init' %
+ self.objinfo.c_name):
+ substdict['tp_init'] = self.write_constructor()
+ substdict['tp_methods'] = self.write_methods()
+ substdict['tp_getset'] = self.write_getsets()
+
+ # handle slots ...
+ for slot in self.slots_list:
+
+ slotname = '%s.%s' % (self.objinfo.c_name, slot)
+ slotfunc = '_wrap_%s_%s' % (self.get_lower_name(), slot)
+ if slot[:6] == 'tp_as_':
+ slotfunc = '&' + slotfunc
+ if self.overrides.slot_is_overriden(slotname):
+ data = self.overrides.slot_override(slotname)
+ self.write_function(slotname, data)
+ substdict[slot] = slotfunc
+ else:
+ if not substdict.has_key(slot):
+ substdict[slot] = '0'
+
+ self.fp.write(self.type_tmpl % substdict)
+
+ self.write_virtuals()
+
+ def write_function_wrapper(self, function_obj, template,
+ handle_return=0, is_method=0, kwargs_needed=0,
+ substdict=None):
+ '''This function is the guts of all functions that generate
+ wrappers for functions, methods and constructors.'''
+ if not substdict: substdict = {}
+
+ info = argtypes.WrapperInfo()
+
+ substdict.setdefault('errorreturn', 'NULL')
+
+ # for methods, we want the leading comma
+ if is_method:
+ info.arglist.append('')
+
+ if function_obj.varargs:
+ raise argtypes.ArgTypeNotFoundError("varargs functions not supported")
+
+ for param in function_obj.params:
+ if param.pdflt != None and '|' not in info.parsestr:
+ info.add_parselist('|', [], [])
+ handler = argtypes.matcher.get(param.ptype)
+ handler.write_param(param.ptype, param.pname, param.pdflt,
+ param.pnull, info)
+
+ substdict['setreturn'] = ''
+ if handle_return:
+ if function_obj.ret not in ('none', None):
+ substdict['setreturn'] = 'ret = '
+ handler = argtypes.matcher.get(function_obj.ret)
+ handler.write_return(function_obj.ret,
+ function_obj.caller_owns_return, info)
+
+ if function_obj.deprecated != None:
+ deprecated = self.deprecated_tmpl % {
+ 'deprecationmsg': function_obj.deprecated,
+ 'errorreturn': substdict['errorreturn'] }
+ else:
+ deprecated = ''
+
+ # if name isn't set, set it to function_obj.name
+ substdict.setdefault('name', function_obj.name)
+
+ if function_obj.unblock_threads:
+ substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;'
+ substdict['end_allow_threads'] = 'pyg_end_allow_threads;'
+ else:
+ substdict['begin_allow_threads'] = ''
+ substdict['end_allow_threads'] = ''
+
+ if self.objinfo:
+ substdict['typename'] = self.objinfo.c_name
+ substdict.setdefault('cname', function_obj.c_name)
+ substdict['varlist'] = info.get_varlist()
+ substdict['typecodes'] = info.parsestr
+ substdict['parselist'] = info.get_parselist()
+ substdict['arglist'] = info.get_arglist()
+ substdict['codebefore'] = deprecated + (
+ string.replace(info.get_codebefore(),
+ 'return NULL', 'return ' + substdict['errorreturn'])
+ )
+ substdict['codeafter'] = (
+ string.replace(info.get_codeafter(),
+ 'return NULL',
+ 'return ' + substdict['errorreturn']))
+
+ if info.parsestr or kwargs_needed:
+ substdict['parseargs'] = self.parse_tmpl % substdict
+ substdict['extraparams'] = ', PyObject *args, PyObject *kwargs'
+ flags = 'METH_VARARGS|METH_KEYWORDS'
+
+ # prepend the keyword list to the variable list
+ substdict['varlist'] = info.get_kwlist() + substdict['varlist']
+ else:
+ substdict['parseargs'] = ''
+ substdict['extraparams'] = ''
+ flags = 'METH_NOARGS'
+
+ return template % substdict, flags
+
+ def write_constructor(self):
+ initfunc = '0'
+ constructor = self.parser.find_constructor(self.objinfo,self.overrides)
+ if not constructor:
+ return self.write_default_constructor()
+
+ funcname = constructor.c_name
+ try:
+ if self.overrides.is_overriden(funcname):
+ data = self.overrides.override(funcname)
+ self.write_function(funcname, data)
+ self.objinfo.has_new_constructor_api = (
+ self.objinfo.typecode in
+ self.overrides.newstyle_constructors)
+ else:
+ # ok, a hack to determine if we should use
+ # new-style constructores :P
+ property_based = getattr(self,
+ 'write_property_based_constructor',
+ None)
+ if property_based:
+ if (len(constructor.params) == 0 or
+ isinstance(constructor.params[0],
+ definitions.Property)):
+ # write_property_based_constructor is only
+ # implemented in GObjectWrapper
+ return self.write_property_based_constructor(
+ constructor)
+ else:
+ sys.stderr.write(
+ "Warning: generating old-style constructor for:" +
+ constructor.c_name + '\n')
+
+ # write constructor from template ...
+ code = self.write_function_wrapper(constructor,
+ self.constructor_tmpl,
+ handle_return=0, is_method=0, kwargs_needed=1,
+ substdict=self.get_initial_constructor_substdict(
+ constructor))[0]
+ self.fp.write(code)
+ initfunc = '_wrap_' + funcname
+ except argtypes.ArgTypeError, ex:
+ sys.stderr.write('Could not write constructor for %s: %s\n'
+ % (self.objinfo.c_name, str(ex)))
+
+ initfunc = self.write_noconstructor()
+ return initfunc
+
+ def write_noconstructor(self):
+ # this is a hack ...
+ if not hasattr(self.overrides, 'no_constructor_written'):
+ self.fp.write(self.noconstructor)
+ self.overrides.no_constructor_written = 1
+ initfunc = 'pygobject_no_constructor'
+ return initfunc
+
+ def write_default_constructor(self):
+ return self.write_noconstructor()
+
+ def get_methflags(self, funcname):
+ if self.overrides.wants_kwargs(funcname):
+ flags = 'METH_VARARGS|METH_KEYWORDS'
+ elif self.overrides.wants_noargs(funcname):
+ flags = 'METH_NOARGS'
+ elif self.overrides.wants_onearg(funcname):
+ flags = 'METH_O'
+ else:
+ flags = 'METH_VARARGS'
+ if self.overrides.is_staticmethod(funcname):
+ flags += '|METH_STATIC'
+ elif self.overrides.is_classmethod(funcname):
+ flags += '|METH_CLASS'
+ return flags
+
+ def write_function(self, funcname, data):
+ lineno, filename = self.overrides.getstartline(funcname)
+ self.fp.setline(lineno, filename)
+ self.fp.write(data)
+ self.fp.resetline()
+ self.fp.write('\n\n')
+
+ def _get_class_virtual_substdict(self, meth, cname, parent):
+ substdict = self.get_initial_method_substdict(meth)
+ substdict['virtual'] = meth.name
+ substdict['cname'] = cname
+ substdict['class_cast_macro'] = parent.typecode.replace(
+ '_TYPE_', '_', 1) + "_CLASS"
+ substdict['typecode'] = self.objinfo.typecode
+ substdict['cast'] = string.replace(parent.typecode, '_TYPE_', '_', 1)
+ return substdict
+
+ def write_methods(self):
+ methods = []
+ klass = self.objinfo.c_name
+ # First, get methods from the defs files
+ for meth in self.parser.find_methods(self.objinfo):
+ method_name = meth.c_name
+ if self.overrides.is_ignored(method_name):
+ continue
+ try:
+ if self.overrides.is_overriden(method_name):
+ if not self.overrides.is_already_included(method_name):
+ data = self.overrides.override(method_name)
+ self.write_function(method_name, data)
+
+ methflags = self.get_methflags(method_name)
+ else:
+ # write constructor from template ...
+ code, methflags = self.write_function_wrapper(meth,
+ self.method_tmpl, handle_return=1, is_method=1,
+ substdict=self.get_initial_method_substdict(meth))
+ self.fp.write(code)
+ methods.append(self.methdef_tmpl %
+ { 'name': fixname(meth.name),
+ 'cname': '_wrap_' + method_name,
+ 'flags': methflags,
+ 'docstring': meth.docstring })
+ methods_coverage.declare_wrapped()
+ except argtypes.ArgTypeError, ex:
+ methods_coverage.declare_not_wrapped()
+ sys.stderr.write('Could not write method %s.%s: %s\n'
+ % (klass, meth.name, str(ex)))
+
+ # Now try to see if there are any defined in the override
+ for method_name in self.overrides.get_defines_for(klass):
+ c_name = override.class2cname(klass, method_name)
+ if self.overrides.is_already_included(method_name):
+ continue
+
+ try:
+ data = self.overrides.define(klass, method_name)
+ self.write_function(method_name, data)
+ methflags = self.get_methflags(method_name)
+
+ methods.append(self.methdef_tmpl %
+ { 'name': method_name,
+ 'cname': '_wrap_' + c_name,
+ 'flags': methflags,
+ 'docstring': 'NULL' })
+ methods_coverage.declare_wrapped()
+ except argtypes.ArgTypeError, ex:
+ methods_coverage.declare_not_wrapped()
+ sys.stderr.write('Could not write method %s.%s: %s\n'
+ % (klass, method_name, str(ex)))
+
+ # Add GObject virtual method accessors, for chaining to parent
+ # virtuals from subclasses
+ methods += self.write_virtual_accessors()
+
+ if methods:
+ methoddefs = '_Py%s_methods' % self.objinfo.c_name
+ # write the PyMethodDef structure
+ methods.append(' { NULL, NULL, 0, NULL }\n')
+ self.fp.write('static const PyMethodDef %s[] = {\n' % methoddefs)
+ self.fp.write(string.join(methods, ''))
+ self.fp.write('};\n\n')
+ else:
+ methoddefs = 'NULL'
+ return methoddefs
+
+ def write_virtual_accessors(self):
+ klass = self.objinfo.c_name
+ methods = []
+ for meth in self.parser.find_virtuals(self.objinfo):
+ method_name = self.objinfo.c_name + "__do_" + meth.name
+ if self.overrides.is_ignored(method_name):
+ continue
+ try:
+ if self.overrides.is_overriden(method_name):
+ if not self.overrides.is_already_included(method_name):
+ data = self.overrides.override(method_name)
+ self.write_function(method_name, data)
+ methflags = self.get_methflags(method_name)
+ else:
+ # temporarily add a 'self' parameter as first argument
+ meth.params.insert(0, definitions.Parameter(
+ ptype=(self.objinfo.c_name + '*'),
+ pname='self', pdflt=None, pnull=None))
+ try:
+ # write method from template ...
+ code, methflags = self.write_function_wrapper(
+ meth, self.virtual_accessor_tmpl,
+ handle_return=True, is_method=False,
+ substdict=self._get_class_virtual_substdict(
+ meth, method_name, self.objinfo))
+ self.fp.write(code)
+ finally:
+ del meth.params[0]
+ methods.append(self.methdef_tmpl %
+ { 'name': "do_" + fixname(meth.name),
+ 'cname': '_wrap_' + method_name,
+ 'flags': methflags + '|METH_CLASS',
+ 'docstring': 'NULL'})
+ vaccessors_coverage.declare_wrapped()
+ except argtypes.ArgTypeError, ex:
+ vaccessors_coverage.declare_not_wrapped()
+ sys.stderr.write(
+ 'Could not write virtual accessor method %s.%s: %s\n'
+ % (klass, meth.name, str(ex)))
+ return methods
+
+ def write_virtuals(self):
+ '''
+ Write _wrap_FooBar__proxy_do_zbr() reverse wrapers for
+ GObject virtuals
+ '''
+ klass = self.objinfo.c_name
+ virtuals = []
+ for meth in self.parser.find_virtuals(self.objinfo):
+ method_name = self.objinfo.c_name + "__proxy_do_" + meth.name
+ if self.overrides.is_ignored(method_name):
+ continue
+ try:
+ if self.overrides.is_overriden(method_name):
+ if not self.overrides.is_already_included(method_name):
+ data = self.overrides.override(method_name)
+ self.write_function(method_name, data)
+ else:
+ # write virtual proxy ...
+ ret, props = argtypes.matcher.get_reverse_ret(meth.ret)
+ wrapper = reversewrapper.ReverseWrapper(
+ '_wrap_' + method_name, is_static=True)
+ wrapper.set_return_type(ret(wrapper, **props))
+ wrapper.add_parameter(reversewrapper.PyGObjectMethodParam(
+ wrapper, "self", method_name="do_" + meth.name,
+ c_type=(klass + ' *')))
+ for param in meth.params:
+ handler, props = argtypes.matcher.get_reverse(
+ param.ptype)
+ props["direction"] = param.pdir
+ props["nullok"] = param.pnull
+ wrapper.add_parameter(handler(wrapper,
+ param.pname, **props))
+ buf = reversewrapper.MemoryCodeSink()
+ wrapper.generate(buf)
+ self.fp.write(buf.flush())
+ virtuals.append((fixname(meth.name), '_wrap_' + method_name))
+ vproxies_coverage.declare_wrapped()
+ except argtypes.ArgTypeError, ex:
+ vproxies_coverage.declare_not_wrapped()
+ virtuals.append((fixname(meth.name), None))
+ sys.stderr.write('Could not write virtual proxy %s.%s: %s\n'
+ % (klass, meth.name, str(ex)))
+ if virtuals:
+ # Write a 'pygtk class init' function for this object,
+ # except when the object type is explicitly ignored (like
+ # GtkPlug and GtkSocket on win32).
+ if self.overrides.is_ignored(self.objinfo.typecode):
+ return
+ class_cast_macro = self.objinfo.typecode.replace(
+ '_TYPE_', '_', 1) + "_CLASS"
+ cast_macro = self.objinfo.typecode.replace('_TYPE_', '_', 1)
+ funcname = "__%s_class_init" % klass
+ self.objinfo.class_init_func = funcname
+ have_implemented_virtuals = not not [True
+ for name, cname in virtuals
+ if cname is not None]
+ self.fp.write(
+ ('\nstatic int\n'
+ '%(funcname)s(gpointer gclass, PyTypeObject *pyclass)\n'
+ '{\n') % vars())
+
+ if have_implemented_virtuals:
+ self.fp.write(' PyObject *o;\n')
+ self.fp.write(
+ ' %(klass)sClass *klass = '
+ '%(class_cast_macro)s(gclass);\n'
+ ' PyObject *gsignals = '
+ 'PyDict_GetItemString(pyclass->tp_dict, "__gsignals__");\n'
+ % vars())
+
+ for name, cname in virtuals:
+ do_name = 'do_' + name
+ if cname is None:
+ self.fp.write('\n /* overriding %(do_name)s '
+ 'is currently not supported */\n' % vars())
+ else:
+ self.fp.write('''
+ o = PyObject_GetAttrString((PyObject *) pyclass, "%(do_name)s");
+ if (o == NULL)
+ PyErr_Clear();
+ else {
+ if (!PyObject_TypeCheck(o, &PyCFunction_Type)
+ && !(gsignals && PyDict_GetItemString(gsignals, "%(name)s")))
+ klass->%(name)s = %(cname)s;
+ Py_DECREF(o);
+ }
+''' % vars())
+ self.fp.write(' return 0;\n}\n')
+
+ def write_getsets(self):
+ lower_name = self.get_lower_name()
+ getsets_name = lower_name + '_getsets'
+ getterprefix = '_wrap_' + lower_name + '__get_'
+ setterprefix = '_wrap_' + lower_name + '__set_'
+
+ # no overrides for the whole function. If no fields,
+ # don't write a func
+ if not self.objinfo.fields:
+ return '0'
+ getsets = []
+ for ftype, cfname in self.objinfo.fields:
+ fname = cfname.replace('.', '_')
+ gettername = '0'
+ settername = '0'
+ attrname = self.objinfo.c_name + '.' + fname
+ if self.overrides.attr_is_overriden(attrname):
+ code = self.overrides.attr_override(attrname)
+ self.write_function(attrname, code)
+ if string.find(code, getterprefix + fname) >= 0:
+ gettername = getterprefix + fname
+ if string.find(code, setterprefix + fname) >= 0:
+ settername = setterprefix + fname
+ if gettername == '0':
+ try:
+ funcname = getterprefix + fname
+ info = argtypes.WrapperInfo()
+ handler = argtypes.matcher.get(ftype)
+ # for attributes, we don't own the "return value"
+ handler.write_return(ftype, 0, info)
+ self.fp.write(self.getter_tmpl %
+ { 'funcname': funcname,
+ 'varlist': info.varlist,
+ 'field': self.get_field_accessor(cfname),
+ 'codeafter': info.get_codeafter() })
+ gettername = funcname
+ except argtypes.ArgTypeError, ex:
+ sys.stderr.write(
+ "Could not write getter for %s.%s: %s\n"
+ % (self.objinfo.c_name, fname, str(ex)))
+ if gettername != '0' or settername != '0':
+ getsets.append(' { "%s", (getter)%s, (setter)%s },\n' %
+ (fixname(fname), gettername, settername))
+
+ if not getsets:
+ return '0'
+ self.fp.write('static const PyGetSetDef %s[] = {\n' % getsets_name)
+ for getset in getsets:
+ self.fp.write(getset)
+ self.fp.write(' { NULL, (getter)0, (setter)0 },\n')
+ self.fp.write('};\n\n')
+
+ return getsets_name
+
+ def _write_get_symbol_names(self, writer, functions):
+ self.fp.write("""static PyObject *
+_wrap__get_symbol_names(PyObject *self)
+{
+ PyObject *pylist = PyList_New(0);
+
+""")
+ for obj, bases in writer.get_classes():
+ self.fp.write(' PyList_Append(pylist, '
+ 'PyString_FromString("%s"));\n' % (obj.name))
+
+ for name, cname, flags, docstring in functions:
+ self.fp.write(' PyList_Append(pylist, '
+ 'PyString_FromString("%s"));\n' % (name))
+
+ for enum in writer.get_enums():
+ self.fp.write(' PyList_Append(pylist, '
+ 'PyString_FromString("%s"));\n' % (enum.name))
+ for nick, value in enum.values:
+ name = value[len(self.overrides.modulename)+1:]
+ self.fp.write(' PyList_Append(pylist, '
+ 'PyString_FromString("%s"));\n' % (name))
+
+ self.fp.write(" return pylist;\n}\n\n");
+
+ def _write_get_symbol(self, writer, functions):
+ self.fp.write("""static PyObject *
+_wrap__get_symbol(PyObject *self, PyObject *args)
+{
+ PyObject *d;
+ char *name;
+ static PyObject *modulename = NULL;
+ static PyObject *module = NULL;
+ static char *strip_prefix = "%s";
+
+ if (!PyArg_ParseTuple(args, "Os", &d, &name))
+ return NULL;
+
+ if (!modulename)
+ modulename = PyString_FromString("%s");
+
+ if (!module)
+ module = PyDict_GetItemString(d, "__module__");
+
+""" % (self.overrides.modulename.upper() + '_',
+ self.overrides.modulename))
+
+ first = True
+ # Classes / GObjects
+ for obj, bases in writer.get_classes():
+ if first:
+ self.fp.write(' if (!strcmp(name, "%s")) {\n' % obj.name)
+ first = False
+ else:
+ self.fp.write(' } else if (!strcmp(name, "%s")) {\n' % obj.name)
+ self.fp.write(
+ ' return (PyObject*)pygobject_lookup_class(%s);\n' %
+ obj.typecode)
+ self.fp.write(' }\n')
+
+ # Functions
+ for name, cname, flags, docstring in functions:
+ self.fp.write(' else if (!strcmp(name, "%s")) {\n' % name)
+ self.fp.write(' static PyMethodDef ml = { '
+ '"%s", (PyCFunction)%s, %s, "%s"};\n' % (
+ name, cname, flags, docstring))
+ self.fp.write(' return PyCFunction_NewEx(&ml, NULL, modulename);\n')
+ self.fp.write(' }\n')
+
+ # Enums
+ def write_enum(enum, returnobj=False):
+ if returnobj:
+ ret = 'return '
+ else:
+ ret = ''
+ if enum.deftype == 'enum':
+ self.fp.write(
+ ' %spyg_enum_add(module, "%s", strip_prefix, %s);\n'
+ % (ret, enum.name, enum.typecode))
+ else:
+ self.fp.write(
+ ' %spyg_flags_add(module, "%s", strip_prefix, %s);\n'
+ % (ret, enum.name, enum.typecode))
+
+ strip_len = len(self.overrides.modulename)+1 # GTK_
+ for enum in writer.get_enums():
+ # XXX: Implement without typecodes
+ self.fp.write(' else if (!strcmp(name, "%s")) {\n' % enum.name)
+ write_enum(enum, returnobj=True)
+ self.fp.write(' }\n')
+
+ for nick, value in enum.values:
+ value = value[strip_len:]
+ self.fp.write(' else if (!strcmp(name, "%s")) {\n' % value)
+ write_enum(enum)
+ self.fp.write(' return PyObject_GetAttrString(module, "%s");\n' %
+ value)
+ self.fp.write(' }\n')
+
+ self.fp.write(' return Py_None;\n}\n\n');
+
+ def _write_function_bodies(self):
+ functions = []
+ # First, get methods from the defs files
+ for func in self.parser.find_functions():
+ funcname = func.c_name
+ if self.overrides.is_ignored(funcname):
+ continue
+ try:
+ if self.overrides.is_overriden(funcname):
+ data = self.overrides.override(funcname)
+ self.write_function(funcname, data)
+
+ methflags = self.get_methflags(funcname)
+ else:
+ # write constructor from template ...
+ code, methflags = self.write_function_wrapper(func,
+ self.function_tmpl, handle_return=1, is_method=0)
+ self.fp.write(code)
+ functions.append((func.name, '_wrap_' + funcname,
+ methflags, func.docstring))
+ functions_coverage.declare_wrapped()
+ except argtypes.ArgTypeError, ex:
+ functions_coverage.declare_not_wrapped()
+ sys.stderr.write('Could not write function %s: %s\n'
+ % (func.name, str(ex)))
+
+ # Now try to see if there are any defined in the override
+ for funcname in self.overrides.get_functions():
+ try:
+ data = self.overrides.function(funcname)
+ self.write_function(funcname, data)
+ methflags = self.get_methflags(funcname)
+ functions.append((funcname, '_wrap_' + funcname,
+ methflags, 'NULL'))
+ functions_coverage.declare_wrapped()
+ except argtypes.ArgTypeError, ex:
+ functions_coverage.declare_not_wrapped()
+ sys.stderr.write('Could not write function %s: %s\n'
+ % (funcname, str(ex)))
+ return functions
+
+ def write_functions(self, writer, prefix):
+ self.fp.write('\n/* ----------- functions ----------- */\n\n')
+ functions = []
+ func_infos = self._write_function_bodies()
+
+ # If we have a dynamic namespace, write symbol and attribute getter
+ if self.overrides.dynamicnamespace:
+ self._write_get_symbol_names(writer, func_infos)
+ self._write_get_symbol(writer, func_infos)
+ for obj, bases in writer.get_classes():
+ self.fp.write("""static PyTypeObject *
+%s_register_type(const gchar *name, PyObject *unused)
+{
+ PyObject *m = PyImport_ImportModule("gtk");
+ PyObject *d = PyModule_GetDict(m);
+""" % obj.c_name)
+ writer.write_class(obj, bases, indent=1)
+ self.fp.write(
+ ' return (%s)PyDict_GetItemString(d, "%s");\n' % (
+ 'PyTypeObject*', obj.name))
+ self.fp.write("}\n")
+
+ functions.append(' { "_get_symbol_names", '
+ '(PyCFunction)_wrap__get_symbol_names, '
+ 'METH_NOARGS, NULL },\n')
+ functions.append(' { "_get_symbol", '
+ '(PyCFunction)_wrap__get_symbol, '
+ 'METH_VARARGS, NULL },\n')
+ else:
+ for name, cname, flags, docstring in func_infos:
+ functions.append(self.methdef_tmpl % dict(name=name,
+ cname=cname,
+ flags=flags,
+ docstring=docstring))
+
+ # write the PyMethodDef structure
+ functions.append(' { NULL, NULL, 0, NULL }\n')
+
+ self.fp.write('const PyMethodDef ' + prefix + '_functions[] = {\n')
+ self.fp.write(string.join(functions, ''))
+ self.fp.write('};\n\n')
+
+class GObjectWrapper(Wrapper):
+ constructor_tmpl = (
+ 'static int\n'
+ '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n'
+ '{\n'
+ '%(varlist)s'
+ '%(parseargs)s'
+ '%(codebefore)s'
+ ' self->obj = (GObject *)%(cname)s(%(arglist)s);\n'
+ '%(codeafter)s\n'
+ ' if (!self->obj) {\n'
+ ' PyErr_SetString(PyExc_RuntimeError, '
+ '"could not create %(typename)s object");\n'
+ ' return -1;\n'
+ ' }\n'
+ '%(aftercreate)s'
+ ' pygobject_register_wrapper((PyObject *)self);\n'
+ ' return 0;\n'
+ '}\n\n'
+ )
+
+ method_tmpl = (
+ 'static PyObject *\n'
+ '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n'
+ '{\n'
+ '%(varlist)s'
+ '%(parseargs)s'
+ '%(codebefore)s'
+ ' %(begin_allow_threads)s\n'
+ ' %(setreturn)s%(cname)s(%(cast)s(self->obj)%(arglist)s);\n'
+ ' %(end_allow_threads)s\n'
+ '%(codeafter)s\n'
+ '}\n\n'
+ )
+ def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)):
+ Wrapper.__init__(self, parser, objinfo, overrides, fp)
+ if self.objinfo:
+ self.castmacro = string.replace(self.objinfo.typecode,
+ '_TYPE_', '_', 1)
+
+ def get_initial_class_substdict(self):
+ return { 'tp_basicsize' : 'PyGObject',
+ 'tp_weaklistoffset' : 'offsetof(PyGObject, weakreflist)',
+ 'tp_dictoffset' : 'offsetof(PyGObject, inst_dict)' }
+
+ def get_field_accessor(self, fieldname):
+ castmacro = string.replace(self.objinfo.typecode, '_TYPE_', '_', 1)
+ return '%s(pygobject_get(self))->%s' % (castmacro, fieldname)
+
+ def get_initial_constructor_substdict(self, constructor):
+ substdict = Wrapper.get_initial_constructor_substdict(self,
+ constructor)
+ if not constructor.caller_owns_return:
+ substdict['aftercreate'] = " g_object_ref(self->obj);\n"
+ else:
+ substdict['aftercreate'] = ''
+ return substdict
+
+ def get_initial_method_substdict(self, method):
+ substdict = Wrapper.get_initial_method_substdict(self, method)
+ substdict['cast'] = string.replace(self.objinfo.typecode,
+ '_TYPE_', '_', 1)
+ return substdict
+
+ def write_default_constructor(self):
+ try:
+ parent = self.parser.find_object(self.objinfo.parent)
+ except ValueError:
+ parent = None
+ if parent is not None:
+ ## just like the constructor is inheritted, we should
+ # inherit the new API compatibility flag
+ self.objinfo.has_new_constructor_api = (
+ parent.has_new_constructor_api)
+ elif self.objinfo.parent == 'GObject':
+ self.objinfo.has_new_constructor_api = True
+ return '0'
+
+ def write_property_based_constructor(self, constructor):
+ self.objinfo.has_new_constructor_api = True
+ out = self.fp
+ print >> out, "static int"
+ print >> out, '_wrap_%s(PyGObject *self, PyObject *args,' \
+ ' PyObject *kwargs)\n{' % constructor.c_name
+ if constructor.params:
+ s = " GType obj_type = pyg_type_from_object((PyObject *) self);"
+ print >> out, s
+
+ def py_str_list_to_c(arg):
+ if arg:
+ return "{" + ", ".join(
+ map(lambda s: '"' + s + '"', arg)) + ", NULL }"
+ else:
+ return "{ NULL }"
+
+ classname = '%s.%s' % (self.overrides.modulename,
+ self.objinfo.name)
+
+ if constructor.params:
+ mandatory_arguments = [param for param in constructor.params
+ if not param.optional]
+ optional_arguments = [param for param in constructor.params
+ if param.optional]
+ arg_names = py_str_list_to_c(
+ [param.argname
+ for param in mandatory_arguments + optional_arguments])
+
+ prop_names = py_str_list_to_c(
+ [param.pname
+ for param in mandatory_arguments + optional_arguments])
+
+ print >> out, " GParameter params[%i];" % \
+ len(constructor.params)
+ print >> out, " PyObject *parsed_args[%i] = {NULL, };" % \
+ len(constructor.params)
+ print >> out, " char *arg_names[] = %s;" % arg_names
+ print >> out, " char *prop_names[] = %s;" % prop_names
+ print >> out, " guint nparams, i;"
+ print >> out
+ if constructor.deprecated is not None:
+ out.write(
+ ' if (PyErr_Warn(PyExc_DeprecationWarning, '
+ '"%s") < 0)\n' %
+ constructor.deprecated)
+ print >> out, ' return -1;'
+ print >> out
+ out.write(" if (!PyArg_ParseTupleAndKeywords(args, kwargs, ")
+ template = '"'
+ if mandatory_arguments:
+ template += "O"*len(mandatory_arguments)
+ if optional_arguments:
+ template += "|" + "O"*len(optional_arguments)
+ template += ':%s.__init__"' % classname
+ print >> out, template, ", arg_names",
+ for i in range(len(constructor.params)):
+ print >> out, ", &parsed_args[%i]" % i,
+
+ out.write(
+ "))\n"
+ " return -1;\n"
+ "\n"
+ " memset(params, 0, sizeof(GParameter)*%i);\n"
+ " if (!pyg_parse_constructor_args(obj_type, arg_names,\n"
+ " prop_names, params, \n"
+ " &nparams, parsed_args))\n"
+ " return -1;\n"
+ " pygobject_constructv(self, nparams, params);\n"
+ " for (i = 0; i < nparams; ++i)\n"
+ " g_value_unset(&params[i].value);\n"
+ % len(constructor.params))
+ else:
+ out.write(
+ " static char* kwlist[] = { NULL };\n"
+ "\n")
+
+ if constructor.deprecated is not None:
+ out.write(
+ ' if (PyErr_Warn(PyExc_DeprecationWarning, "%s") < 0)\n'
+ ' return -1;\n'
+ '\n' % constructor.deprecated)
+
+ out.write(
+ ' if (!PyArg_ParseTupleAndKeywords(args, kwargs,\n'
+ ' ":%s.__init__",\n'
+ ' kwlist))\n'
+ ' return -1;\n'
+ '\n'
+ ' pygobject_constructv(self, 0, NULL);\n' % classname)
+ out.write(
+ ' if (!self->obj) {\n'
+ ' PyErr_SetString(\n'
+ ' PyExc_RuntimeError, \n'
+ ' "could not create %s object");\n'
+ ' return -1;\n'
+ ' }\n' % classname)
+
+ if not constructor.caller_owns_return:
+ print >> out, " g_object_ref(self->obj);\n"
+
+ out.write(
+ ' return 0;\n'
+ '}\n\n')
+
+ return "_wrap_%s" % constructor.c_name
+
+
+class GInterfaceWrapper(GObjectWrapper):
+ virtual_accessor_tmpl = (
+ 'static PyObject *\n'
+ '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n'
+ '{\n'
+ ' %(vtable)s *iface;\n'
+ '%(varlist)s'
+ '%(parseargs)s'
+ '%(codebefore)s'
+ ' iface = g_type_interface_peek('
+ 'g_type_class_peek(pyg_type_from_object(cls)), %(typecode)s);\n'
+ ' if (iface->%(virtual)s)\n'
+ ' %(setreturn)siface->%(virtual)s(%(arglist)s);\n'
+ ' else {\n'
+ ' PyErr_SetString(PyExc_NotImplementedError, '
+ '"interface method %(name)s not implemented");\n'
+ ' return NULL;\n'
+ ' }\n'
+ '%(codeafter)s\n'
+ '}\n\n'
+ )
+
+ def get_initial_class_substdict(self):
+ return { 'tp_basicsize' : 'PyObject',
+ 'tp_weaklistoffset' : '0',
+ 'tp_dictoffset' : '0'}
+
+ def write_constructor(self):
+ # interfaces have no constructors ...
+ return '0'
+ def write_getsets(self):
+ # interfaces have no fields ...
+ return '0'
+
+ def _get_class_virtual_substdict(self, meth, cname, parent):
+ substdict = self.get_initial_method_substdict(meth)
+ substdict['virtual'] = meth.name
+ substdict['cname'] = cname
+ substdict['typecode'] = self.objinfo.typecode
+ substdict['vtable'] = self.objinfo.vtable
+ return substdict
+
+ def write_virtuals(self):
+ ## Now write reverse method wrappers, which let python code
+ ## implement interface methods.
+ # First, get methods from the defs files
+ klass = self.objinfo.c_name
+ proxies = []
+ for meth in self.parser.find_virtuals(self.objinfo):
+ method_name = self.objinfo.c_name + "__proxy_do_" + meth.name
+ if self.overrides.is_ignored(method_name):
+ continue
+ try:
+ if self.overrides.is_overriden(method_name):
+ if not self.overrides.is_already_included(method_name):
+ data = self.overrides.override(method_name)
+ self.write_function(method_name, data)
+ else:
+ # write proxy ...
+ ret, props = argtypes.matcher.get_reverse_ret(meth.ret)
+ wrapper = reversewrapper.ReverseWrapper(
+ '_wrap_' + method_name, is_static=True)
+ wrapper.set_return_type(ret(wrapper, **props))
+ wrapper.add_parameter(reversewrapper.PyGObjectMethodParam(
+ wrapper, "self", method_name="do_" + meth.name,
+ c_type=(klass + ' *')))
+ for param in meth.params:
+ handler, props = argtypes.matcher.get_reverse(
+ param.ptype)
+ props["direction"] = param.pdir
+ props["nullok"] = param.pnull
+ wrapper.add_parameter(
+ handler(wrapper, param.pname, **props))
+ buf = reversewrapper.MemoryCodeSink()
+ wrapper.generate(buf)
+ self.fp.write(buf.flush())
+ proxies.append((fixname(meth.name), '_wrap_' + method_name))
+ iproxies_coverage.declare_wrapped()
+ except argtypes.ArgTypeError, ex:
+ iproxies_coverage.declare_not_wrapped()
+ proxies.append((fixname(meth.name), None))
+ sys.stderr.write('Could not write interface proxy %s.%s: %s\n'
+ % (klass, meth.name, str(ex)))
+
+ if not proxies or not [cname for name, cname in proxies if cname]:
+ return
+
+ ## Write an interface init function for this object
+ funcname = "__%s__interface_init" % klass
+ vtable = self.objinfo.vtable
+ self.fp.write(
+ '\nstatic void\n'
+ '%(funcname)s(%(vtable)s *iface, PyTypeObject *pytype)\n'
+ '{\n'
+ ' %(vtable)s *parent_iface = '
+ 'g_type_interface_peek_parent(iface);\n'
+ ' PyObject *py_method;\n'
+ '\n'
+ % vars())
+
+ for name, cname in proxies:
+ do_name = 'do_' + name
+ if cname is None:
+ continue
+
+ self.fp.write((
+ ' py_method = pytype? PyObject_GetAttrString('
+ '(PyObject *) pytype, "%(do_name)s") : NULL;\n'
+ ' if (py_method && !PyObject_TypeCheck(py_method, '
+ '&PyCFunction_Type)) {\n'
+ ' iface->%(name)s = %(cname)s;\n'
+ ' } else {\n'
+ ' PyErr_Clear();\n'
+ ' if (parent_iface) {\n'
+ ' iface->%(name)s = parent_iface->%(name)s;\n'
+ ' }\n'
+ ' Py_XDECREF(py_method);\n'
+ ' }\n'
+ ) % vars())
+ self.fp.write('}\n\n')
+ interface_info = "__%s__iinfo" % klass
+ self.fp.write('''
+static const GInterfaceInfo %s = {
+ (GInterfaceInitFunc) %s,
+ NULL,
+ NULL
+};
+''' % (interface_info, funcname))
+ self.objinfo.interface_info = interface_info
+
+class GBoxedWrapper(Wrapper):
+ constructor_tmpl = (
+ 'static int\n'
+ '_wrap_%(cname)s(PyGBoxed *self%(extraparams)s)\n'
+ '{\n'
+ '%(varlist)s'
+ '%(parseargs)s'
+ '%(codebefore)s'
+ ' self->gtype = %(typecode)s;\n'
+ ' self->free_on_dealloc = FALSE;\n'
+ ' self->boxed = %(cname)s(%(arglist)s);\n'
+ '%(codeafter)s\n'
+ ' if (!self->boxed) {\n'
+ ' PyErr_SetString(PyExc_RuntimeError, '
+ '"could not create %(typename)s object");\n'
+ ' return -1;\n'
+ ' }\n'
+ ' self->free_on_dealloc = TRUE;\n'
+ ' return 0;\n'
+ '}\n\n'
+ )
+
+ method_tmpl = (
+ 'static PyObject *\n'
+ '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n'
+ '{\n'
+ '%(varlist)s'
+ '%(parseargs)s'
+ '%(codebefore)s'
+ ' %(begin_allow_threads)s\n'
+ ' %(setreturn)s%(cname)s(pyg_boxed_get(self, '
+ '%(typename)s)%(arglist)s);\n'
+ ' %(end_allow_threads)s\n'
+ '%(codeafter)s\n'
+ '}\n\n'
+ )
+
+ def get_initial_class_substdict(self):
+ return { 'tp_basicsize' : 'PyGBoxed',
+ 'tp_weaklistoffset' : '0',
+ 'tp_dictoffset' : '0' }
+
+ def get_field_accessor(self, fieldname):
+ return 'pyg_boxed_get(self, %s)->%s' % (self.objinfo.c_name, fieldname)
+
+ def get_initial_constructor_substdict(self, constructor):
+ substdict = Wrapper.get_initial_constructor_substdict(
+ self, constructor)
+ substdict['typecode'] = self.objinfo.typecode
+ return substdict
+
+class GPointerWrapper(GBoxedWrapper):
+ constructor_tmpl = (
+ 'static int\n'
+ '_wrap_%(cname)s(PyGPointer *self%(extraparams)s)\n'
+ '{\n'
+ '%(varlist)s'
+ '%(parseargs)s'
+ '%(codebefore)s'
+ ' self->gtype = %(typecode)s;\n'
+ ' self->pointer = %(cname)s(%(arglist)s);\n'
+ '%(codeafter)s\n'
+ ' if (!self->pointer) {\n'
+ ' PyErr_SetString(PyExc_RuntimeError, '
+ '"could not create %(typename)s object");\n'
+ ' return -1;\n'
+ ' }\n'
+ ' return 0;\n'
+ '}\n\n'
+ )
+
+ method_tmpl = (
+ 'static PyObject *\n'
+ '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n'
+ '{\n'
+ '%(varlist)s'
+ '%(parseargs)s'
+ '%(codebefore)s'
+ ' %(setreturn)s%(cname)s(pyg_pointer_get(self, '
+ '%(typename)s)%(arglist)s);\n'
+ '%(codeafter)s\n'
+ '}\n\n'
+ )
+
+ def get_initial_class_substdict(self):
+ return { 'tp_basicsize' : 'PyGPointer',
+ 'tp_weaklistoffset' : '0',
+ 'tp_dictoffset' : '0' }
+
+ def get_field_accessor(self, fieldname):
+ return 'pyg_pointer_get(self, %s)->%s' % (self.objinfo.c_name,
+ fieldname)
+
+ def get_initial_constructor_substdict(self, constructor):
+ substdict = Wrapper.get_initial_constructor_substdict(
+ self, constructor)
+ substdict['typecode'] = self.objinfo.typecode
+ return substdict
+
+class SourceWriter:
+ def __init__(self, parser, overrides, prefix, fp=FileOutput(sys.stdout)):
+ self.parser = parser
+ self.overrides = overrides
+ self.prefix = prefix
+ self.fp = fp
+
+ def write(self, py_ssize_t_clean=False):
+ argtypes.py_ssize_t_clean = py_ssize_t_clean
+
+ self.write_headers(py_ssize_t_clean)
+ self.write_imports()
+ self.write_type_declarations()
+ self.write_body()
+ self.write_classes()
+
+ wrapper = Wrapper(self.parser, None, self.overrides, self.fp)
+ wrapper.write_functions(self, self.prefix)
+
+ if not self.overrides.dynamicnamespace:
+ self.write_enums()
+ self.write_extension_init()
+ self.write_registers()
+
+ argtypes.py_ssize_t_clean = False
+
+ def write_headers(self, py_ssize_t_clean):
+ self.fp.write('/* -- THIS FILE IS GENERATED - DO NOT EDIT */')
+ self.fp.write('/* -*- Mode: C; c-basic-offset: 4 -*- */\n\n')
+ if py_ssize_t_clean:
+ self.fp.write('#define PY_SSIZE_T_CLEAN\n')
+ self.fp.write('#include <Python.h>\n\n\n')
+ if py_ssize_t_clean:
+ self.fp.write('''
+
+#if PY_VERSION_HEX < 0x02050000
+typedef int Py_ssize_t;
+#define PY_SSIZE_T_MAX INT_MAX
+#define PY_SSIZE_T_MIN INT_MIN
+typedef inquiry lenfunc;
+typedef intargfunc ssizeargfunc;
+typedef intobjargproc ssizeobjargproc;
+#endif
+
+''')
+ self.fp.write(self.overrides.get_headers())
+ self.fp.resetline()
+ self.fp.write('\n\n')
+
+ def write_imports(self):
+ self.fp.write('/* ---------- types from other modules ---------- */\n')
+ for module, pyname, cname, importing_for in self.overrides.get_imports():
+ if importing_for is None or is_registered_object(importing_for):
+ self.fp.write('static PyTypeObject *_%s;\n' % cname)
+ self.fp.write('#define %s (*_%s)\n' % (cname, cname))
+ self.fp.write('\n\n')
+
+ def write_type_declarations(self):
+ #todo use 'static' if used only in one file
+ self.fp.write('/* ---------- forward type declarations ---------- */\n')
+ for obj in self.parser.boxes:
+ if not self.overrides.is_type_ignored(obj.c_name):
+ self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + obj.c_name + '_Type;\n')
+ for obj in self.parser.objects:
+ if not self.overrides.is_type_ignored(obj.c_name):
+ self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + obj.c_name + '_Type;\n')
+ for interface in self.parser.interfaces:
+ if not self.overrides.is_type_ignored(interface.c_name):
+ self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + interface.c_name + '_Type;\n')
+ self.fp.write('\n')
+
+ def write_body(self):
+ self.fp.write(self.overrides.get_body())
+ self.fp.resetline()
+ self.fp.write('\n\n')
+
+ def _sort_parent_children(self, objects):
+ objects = list(objects)
+ modified = True
+ while modified:
+ modified = False
+ parent_index = None
+ child_index = None
+ for i, obj in enumerate(objects):
+ if obj.parent == 'GObject':
+ continue
+ if obj.parent not in [info.c_name for info in objects[:i]]:
+ for j, info in enumerate(objects[i+1:]):
+ if info.c_name == obj.parent:
+ parent_index = i + 1 + j
+ child_index = i
+ break
+ else:
+ continue
+ break
+ if child_index is not None and parent_index is not None:
+ if child_index != parent_index:
+ objects.insert(child_index, objects.pop(parent_index))
+ modified = True
+ return objects
+
+ def write_classes(self):
+ ## Sort the objects, so that we generate code for the parent types
+ ## before their children.
+ objects = self._sort_parent_children(self.parser.objects)
+
+ for klass, items in ((GBoxedWrapper, self.parser.boxes),
+ (GPointerWrapper, self.parser.pointers),
+ (GObjectWrapper, objects),
+ (GInterfaceWrapper, self.parser.interfaces)):
+ for item in items:
+ instance = klass(self.parser, item, self.overrides, self.fp)
+ instance.write_class()
+ self.fp.write('\n')
+
+ def get_enums(self):
+ enums = []
+ for enum in self.parser.enums:
+ if self.overrides.is_type_ignored(enum.c_name):
+ continue
+ enums.append(enum)
+ return enums
+
+ def write_enums(self):
+ if not self.parser.enums:
+ return
+
+ self.fp.write('\n/* ----------- enums and flags ----------- */\n\n')
+ self.fp.write(
+ 'void\n' + self.prefix +
+ '_add_constants(PyObject *module, const gchar *strip_prefix)\n{\n')
+
+ self.fp.write(
+ '#ifdef VERSION\n'
+ ' PyModule_AddStringConstant(module, "__version__", VERSION);\n'
+ '#endif\n')
+
+ for enum in self.get_enums():
+ if enum.typecode is None:
+ for nick, value in enum.values:
+ self.fp.write(
+ ' PyModule_AddIntConstant(module, '
+ '(char *) pyg_constant_strip_prefix("%s", strip_prefix), %s);\n'
+ % (value, value))
+ else:
+ if enum.deftype == 'enum':
+ self.fp.write(' pyg_enum_add(module, "%s", strip_prefix, %s);\n'
+ % (enum.name, enum.typecode))
+ else:
+ self.fp.write(' pyg_flags_add(module, "%s", strip_prefix, %s);\n'
+ % (enum.name, enum.typecode))
+
+ self.fp.write('\n')
+ self.fp.write(' if (PyErr_Occurred())\n')
+ self.fp.write(' PyErr_Print();\n')
+ self.fp.write('}\n\n')
+
+ def write_object_imports(self, retval=''):
+ imports = self.overrides.get_imports()[:]
+ if not imports:
+ return
+
+ bymod = {}
+ for module, pyname, cname, importing_for in imports:
+ if importing_for is None or is_registered_object(importing_for):
+ bymod.setdefault(module, []).append((pyname, cname))
+ self.fp.write(' PyObject *module;\n\n')
+ for module in bymod:
+ self.fp.write(
+ ' if ((module = PyImport_ImportModule("%s")) != NULL) {\n'
+ % module)
+ #self.fp.write(
+ # ' PyObject *moddict = PyModule_GetDict(module);\n\n')
+ for pyname, cname in bymod[module]:
+ #self.fp.write(
+ # ' _%s = (PyTypeObject *)PyDict_GetItemString('
+ # 'moddict, "%s");\n' % (cname, pyname))
+ self.fp.write(
+ ' _%s = (PyTypeObject *)PyObject_GetAttrString('
+ 'module, "%s");\n' % (cname, pyname))
+ self.fp.write(' if (_%s == NULL) {\n' % cname)
+ self.fp.write(' PyErr_SetString(PyExc_ImportError,\n')
+ self.fp.write(' "cannot import name %s from %s");\n'
+ % (pyname, module))
+ self.fp.write(' return %s;\n' % retval)
+ self.fp.write(' }\n')
+ self.fp.write(' } else {\n')
+ self.fp.write(' PyErr_SetString(PyExc_ImportError,\n')
+ self.fp.write(' "could not import %s");\n' % module)
+ self.fp.write(' return %s;\n' % retval)
+ self.fp.write(' }\n')
+ self.fp.write('\n')
+
+ def write_extension_init(self):
+ self.fp.write('/* initialise stuff extension classes */\n')
+ self.fp.write('void\n' + self.prefix + '_register_classes(PyObject *d)\n{\n')
+ self.write_object_imports()
+ self.fp.write(self.overrides.get_init() + '\n')
+ self.fp.resetline()
+
+ def get_classes(self):
+ objects = self.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
+
+ retval = []
+ for obj in objects:
+ if self.overrides.is_type_ignored(obj.c_name):
+ continue
+ bases = []
+ if obj.parent != None:
+ bases.append(obj.parent)
+ bases = bases + obj.implements
+ retval.append((obj, bases))
+
+ return retval
+
+ def write_registers(self):
+ for boxed in self.parser.boxes:
+ if not self.overrides.is_type_ignored(boxed.c_name):
+ self.fp.write(' pyg_register_boxed(d, "' + boxed.name +
+ '", ' + boxed.typecode +
+ ', &Py' + boxed.c_name +
+ '_Type);\n')
+ for pointer in self.parser.pointers:
+ if not self.overrides.is_type_ignored(pointer.c_name):
+ self.fp.write(' pyg_register_pointer(d, "' + pointer.name +
+ '", ' + pointer.typecode +
+ ', &Py' + pointer.c_name + '_Type);\n')
+ for interface in self.parser.interfaces:
+ if not self.overrides.is_type_ignored(interface.c_name):
+ self.fp.write(' pyg_register_interface(d, "'
+ + interface.name + '", '+ interface.typecode
+ + ', &Py' + interface.c_name + '_Type);\n')
+ if interface.interface_info is not None:
+ self.fp.write(' pyg_register_interface_info(%s, &%s);\n' %
+ (interface.typecode, interface.interface_info))
+
+ if not self.overrides.dynamicnamespace:
+ for obj, bases in self.get_classes():
+ self.write_class(obj, bases)
+ else:
+ for obj, bases in self.get_classes():
+ self.fp.write(
+ ' pyg_type_register_custom_callback("%s", '
+ '(PyGTypeRegistrationFunction)%s_register_type, d);\n' %
+ (obj.c_name, obj.c_name))
+
+ self.fp.write('}\n')
+
+ def _can_direct_ref(self, base):
+ if not self.overrides.dynamicnamespace:
+ return True
+ if base == 'GObject':
+ return True
+ obj = get_object_by_name(base)
+ if obj.module.lower() != self.overrides.modulename:
+ return True
+ return False
+
+ def write_class(self, obj, bases, indent=1):
+ indent_str = ' ' * (indent * 4)
+ if bases:
+ bases_str = 'Py_BuildValue("(%s)"' % (len(bases) * 'O')
+
+ for base in bases:
+ if self._can_direct_ref(base):
+ bases_str += ', &Py%s_Type' % base
+ else:
+ baseobj = get_object_by_name(base)
+ bases_str += ', PyObject_GetAttrString(m, "%s")' % baseobj.name
+ bases_str += ')'
+ else:
+ bases_str = 'NULL'
+
+ self.fp.write(
+ '%(indent)spygobject_register_class(d, "%(c_name)s", %(typecode)s, &Py%(c_name)s_Type, %(bases)s);\n'
+ % dict(indent=indent_str, c_name=obj.c_name, typecode=obj.typecode, bases=bases_str))
+
+ if obj.has_new_constructor_api:
+ self.fp.write(
+ indent_str + 'pyg_set_object_has_new_constructor(%s);\n' %
+ obj.typecode)
+ else:
+ print >> sys.stderr, (
+ "Warning: Constructor for %s needs to be updated to new API\n"
+ " See http://live.gnome.org/PyGTK_2fWhatsNew28"
+ "#update-constructors") % obj.c_name
+
+ if obj.class_init_func is not None:
+ self.fp.write(
+ indent_str + 'pyg_register_class_init(%s, %s);\n' %
+ (obj.typecode, obj.class_init_func))
+
+_objects = {}
+
+def is_registered_object(c_name):
+ return c_name in _objects
+
+def get_object_by_name(c_name):
+ global _objects
+ return _objects[c_name]
+
+def register_types(parser):
+ global _objects
+ for boxed in parser.boxes:
+ argtypes.matcher.register_boxed(boxed.c_name, boxed.typecode)
+ _objects[boxed.c_name] = boxed
+ for pointer in parser.pointers:
+ argtypes.matcher.register_pointer(pointer.c_name, pointer.typecode)
+ for obj in parser.objects:
+ argtypes.matcher.register_object(obj.c_name, obj.parent, obj.typecode)
+ _objects[obj.c_name] = obj
+ for iface in parser.interfaces:
+ argtypes.matcher.register_object(iface.c_name, None, iface.typecode)
+ _objects[iface.c_name] = iface
+ for enum in parser.enums:
+ if enum.deftype == 'flags':
+ argtypes.matcher.register_flag(enum.c_name, enum.typecode)
+ else:
+ argtypes.matcher.register_enum(enum.c_name, enum.typecode)
+
+usage = 'usage: codegen.py [-o overridesfile] [-p prefix] defsfile'
+def main(argv):
+ o = override.Overrides()
+ prefix = 'pygtk'
+ outfilename = None
+ errorfilename = None
+ opts, args = getopt.getopt(argv[1:], "o:p:r:t:D:I:",
+ ["override=", "prefix=", "register=", "outfilename=",
+ "load-types=", "errorfilename=", "py_ssize_t-clean"])
+ defines = {} # -Dkey[=val] options
+ py_ssize_t_clean = False
+ for opt, arg in opts:
+ if opt in ('-o', '--override'):
+ o = override.Overrides(arg)
+ elif opt in ('-p', '--prefix'):
+ prefix = arg
+ elif opt in ('-r', '--register'):
+ # Warning: user has to make sure all -D options appear before -r
+ p = defsparser.DefsParser(arg, defines)
+ p.startParsing()
+ register_types(p)
+ del p
+ elif opt == '--outfilename':
+ outfilename = arg
+ elif opt == '--errorfilename':
+ errorfilename = arg
+ elif opt in ('-t', '--load-types'):
+ globals = {}
+ execfile(arg, globals)
+ elif opt == '-D':
+ nameval = arg.split('=')
+ try:
+ defines[nameval[0]] = nameval[1]
+ except IndexError:
+ defines[nameval[0]] = None
+ elif opt == '-I':
+ defsparser.include_path.insert(0, arg)
+ elif opt == '--py_ssize_t-clean':
+ py_ssize_t_clean = True
+ if len(args) < 1:
+ print >> sys.stderr, usage
+ return 1
+ if errorfilename:
+ sys.stderr = open(errorfilename, "w")
+ p = defsparser.DefsParser(args[0], defines)
+ if not outfilename:
+ outfilename = os.path.splitext(args[0])[0] + '.c'
+
+ p.startParsing()
+
+ register_types(p)
+ sw = SourceWriter(p, o, prefix, FileOutput(sys.stdout, outfilename))
+ sw.write(py_ssize_t_clean)
+
+ functions_coverage.printstats()
+ methods_coverage.printstats()
+ vproxies_coverage.printstats()
+ vaccessors_coverage.printstats()
+ iproxies_coverage.printstats()
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/codegen/createdefs.py b/codegen/createdefs.py
new file mode 100755
index 0000000..84d50b1
--- /dev/null
+++ b/codegen/createdefs.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+import sys
+
+def main(args):
+ output = args[1]
+ input = args[2:]
+ outfd = open(output, 'w')
+ outfd.write(';; -*- scheme -*-\n')
+ outfd.write(';; THIS FILE IS GENERATED - DO NOT EDIT\n')
+ for filename in input:
+ outfd.write('(include "%s")\n' % filename)
+ outfd.close()
+
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/codegen/definitions.py b/codegen/definitions.py
new file mode 100644
index 0000000..aca5adb
--- /dev/null
+++ b/codegen/definitions.py
@@ -0,0 +1,575 @@
+# -*- 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):
+ self.ptype = ptype
+ self.pname = pname
+ self.pdflt = pdflt
+ self.pnull = pnull
+ self.pdir = pdir
+
+ 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
+
+# We currently subclass 'str' to make impact on the rest of codegen as
+# little as possible. Later we can subclass 'object' instead, but
+# then we must find and adapt all places which expect return types to
+# be strings.
+class ReturnType(str):
+ def __new__(cls, *args, **kwds):
+ return str.__new__(cls, *args[:1])
+ def __init__(self, type_name, optional=False):
+ str.__init__(self)
+ self.optional = optional
+
+# Parameter for property based constructors
+class Property(object):
+ def __init__(self, pname, optional, argname):
+ self.pname = pname
+ self.optional = optional
+ self.argname = argname
+
+ def __len__(self): return 4
+ def __getitem__(self, i):
+ return ('', self.pname, self.optional, self.argname)[i]
+
+ 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(object):
+ docstring = "NULL"
+
+ def py_name(self):
+ return '%s.%s' % (self.module, self.name)
+
+ py_name = property(py_name)
+
+ 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 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':
+ type_name = arg[1]
+ optional = False
+ for prop in arg[2:]:
+ if prop[0] == 'optional':
+ optional = True
+ self.ret = ReturnType(type_name, optional)
+ 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
+ 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]
+ self.params.append(Parameter(ptype, pname, pdflt, pnull, pdir))
+ 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
+ for farg in parg[2:]:
+ if farg[0] == 'default':
+ pdflt = farg[1]
+ elif farg[0] == 'null-ok':
+ pnull = 1
+ self.params.append(Parameter(ptype, pname, pdflt, pnull))
+ elif arg[0] == 'properties':
+ if self.is_constructor_of is None:
+ print >> sys.stderr, "Warning: (properties ...) "\
+ "is only valid for constructors"
+ for prop in arg[1:]:
+ pname = prop[0]
+ optional = False
+ argname = pname
+ for farg in prop[1:]:
+ if farg[0] == 'optional':
+ optional = True
+ elif farg[0] == 'argname':
+ argname = farg[1]
+ self.params.append(Property(pname, optional, argname))
+ elif arg[0] == 'varargs':
+ self.varargs = arg[1] in ('t', '#t')
+ elif arg[0] == 'deprecated':
+ self.deprecated = arg[1]
+ else:
+ sys.stderr.write("Warning: %s argument unsupported\n"
+ % (arg[0],))
+ dump = 1
+ if dump:
+ self.write_defs(sys.stderr)
+
+ if self.caller_owns_return is None and self.ret is not None:
+ self.guess_return_value_ownership()
+ for item in ('c_name',):
+ if self.__dict__[item] == None:
+ self.write_defs(sys.stderr)
+ raise RuntimeError, "definition missing required %s" % (item,)
+
+ _method_write_defs = MethodDef.__dict__['write_defs']
+
+ def merge(self, old, parmerge):
+ self.caller_owns_return = old.caller_owns_return
+ self.varargs = old.varargs
+ if not parmerge:
+ self.params = copy.deepcopy(old.params)
+ return
+ # here we merge extra parameter flags accross to the new object.
+ def merge_param(param):
+ for old_param in old.params:
+ if old_param.pname == param.pname:
+ if isinstance(old_param, Property):
+ # h2def never scans Property's, therefore if
+ # we have one it was manually written, so we
+ # keep it.
+ return copy.deepcopy(old_param)
+ else:
+ param.merge(old_param)
+ return param
+ raise RuntimeError, "could not find %s in old_parameters %r" % (
+ param.pname, [p.pname for p in old.params])
+ try:
+ self.params = map(merge_param, self.params)
+ except RuntimeError:
+ # parameter names changed and we can't find a match; it's
+ # safer to keep the old parameter list untouched.
+ self.params = copy.deepcopy(old.params)
+
+ if not self.is_constructor_of:
+ try:
+ self.is_constructor_of = old.is_constructor_of
+ except AttributeError:
+ pass
+ if isinstance(old, MethodDef):
+ self.name = old.name
+ # transmogrify from function into method ...
+ self.write_defs = self._method_write_defs
+ self.of_object = old.of_object
+ del self.params[0]
+ def write_defs(self, fp=sys.stdout):
+ fp.write('(define-function ' + self.name + '\n')
+ if self.in_module:
+ fp.write(' (in-module "' + self.in_module + '")\n')
+ if self.is_constructor_of:
+ fp.write(' (is-constructor-of "' + self.is_constructor_of +'")\n')
+ if self.c_name:
+ fp.write(' (c-name "' + self.c_name + '")\n')
+ if self.typecode:
+ fp.write(' (gtype-id "' + self.typecode + '")\n')
+ if self.caller_owns_return:
+ fp.write(' (caller-owns-return #t)\n')
+ if self.unblock_threads:
+ fp.write(' (unblock-threads #t)\n')
+ if self.ret:
+ fp.write(' (return-type "' + self.ret + '")\n')
+ if self.deprecated:
+ fp.write(' (deprecated "' + self.deprecated + '")\n')
+ if self.params:
+ if isinstance(self.params[0], Parameter):
+ fp.write(' (parameters\n')
+ for ptype, pname, pdflt, pnull in self.params:
+ fp.write(' \'("' + ptype + '" "' + pname +'"')
+ if pdflt: fp.write(' (default "' + pdflt + '")')
+ if pnull: fp.write(' (null-ok)')
+ fp.write(')\n')
+ fp.write(' )\n')
+ elif isinstance(self.params[0], Property):
+ fp.write(' (properties\n')
+ for prop in self.params:
+ fp.write(' \'("' + prop.pname +'"')
+ if prop.optional: fp.write(' (optional)')
+ fp.write(')\n')
+ fp.write(' )\n')
+ else:
+ assert False, "strange parameter list %r" % self.params[0]
+ if self.varargs:
+ fp.write(' (varargs #t)\n')
+
+ fp.write(')\n\n')
diff --git a/codegen/defsconvert.py b/codegen/defsconvert.py
new file mode 100755
index 0000000..c3c2324
--- /dev/null
+++ b/codegen/defsconvert.py
@@ -0,0 +1,132 @@
+#! /usr/bin/env python
+
+import sys
+import string, re
+
+# ------------------ Create typecodes from typenames ---------
+
+_upperstr_pat1 = re.compile(r'([^A-Z])([A-Z])')
+_upperstr_pat2 = re.compile(r'([A-Z][A-Z])([A-Z][0-9a-z])')
+_upperstr_pat3 = re.compile(r'^([A-Z])([A-Z])')
+
+def to_upper_str(name):
+ """Converts a typename to the equivalent upercase and underscores
+ name. This is used to form the type conversion macros and enum/flag
+ name variables"""
+ name = _upperstr_pat1.sub(r'\1_\2', name)
+ name = _upperstr_pat2.sub(r'\1_\2', name)
+ name = _upperstr_pat3.sub(r'\1_\2', name, count=1)
+ return string.upper(name)
+
+def typecode(typename):
+ """create a typecode (eg. GTK_TYPE_WIDGET) from a typename"""
+ return string.replace(to_upper_str(typename), '_', '_TYPE_', 1)
+
+
+STATE_START = 0
+STATE_OBJECT = 1
+STATE_INTERFACE = 2
+STATE_BOXED = 3
+STATE_ENUM = 4
+STATE_FLAGS = 5
+STATE_METHOD = 6
+STATE_FUNCTION = 7
+
+def convert(infp=sys.stdin, outfp=sys.stdout):
+ state = STATE_START
+ seen_params = 0
+
+ line = infp.readline()
+ while line:
+ if line[:8] == '(object ':
+ state = STATE_OBJECT
+ seen_params = 0
+ outfp.write('(define-object ' + line[8:])
+ elif line[:11] == '(interface ':
+ state = STATE_INTERFACE
+ seen_params = 0
+ outfp.write('(define-interface ' + line[11:])
+ elif line[:7] == '(boxed ':
+ state = STATE_BOXED
+ seen_params = 0
+ outfp.write('(define-boxed ' + line[7:])
+ elif line[:6] == '(enum ':
+ state = STATE_ENUM
+ seen_params = 0
+ outfp.write('(define-enum ' + line[6:])
+ elif line[:7] == '(flags ':
+ state = STATE_FLAGS
+ seen_params = 0
+ outfp.write('(define-flags ' + line[7:])
+ elif line[:8] == '(method ':
+ state = STATE_METHOD
+ seen_params = 0
+ outfp.write('(define-method ' + line[8:])
+ elif line[:10] == '(function ':
+ state = STATE_FUNCTION
+ seen_params = 0
+ outfp.write('(define-function ' + line[10:])
+ elif line[:13] == ' (in-module ':
+ outfp.write(re.sub(r'^(\s+\(in-module\s+)(\w+)(.*)$',
+ r'\1"\2"\3', line))
+ elif line[:10] == ' (parent ':
+ outfp.write(re.sub(r'^(\s+\(parent\s+)(\w+)(\s+\((\w+)\))?(.*)$',
+ r'\1"\4\2"\5', line))
+ elif line[:14] == ' (implements ':
+ outfp.write(re.sub(r'^(\s+\(implements\s+)([^\s]+)(\s*\))$',
+ r'\1"\2"\3', line))
+ elif line[:13] == ' (of-object ':
+ outfp.write(re.sub(r'^(\s+\(of-object\s+)(\w+)(\s+\((\w+)\))?(.*)$',
+ r'\1"\4\2"\5', line))
+ elif line[:10] == ' (c-name ':
+ outfp.write(re.sub(r'^(\s+\(c-name\s+)([^\s]+)(\s*\))$',
+ r'\1"\2"\3', line))
+ if state in (STATE_OBJECT, STATE_INTERFACE, STATE_BOXED,
+ STATE_ENUM, STATE_FLAGS):
+ c_name = re.match(r'^\s+\(c-name\s+([^\s]+)\s*\)$',
+ line).group(1)
+ outfp.write(' (gtype-id "%s")\n' % typecode(c_name))
+ elif line[:15] == ' (return-type ':
+ outfp.write(re.sub(r'^(\s+\(return-type\s+)([^\s]+)(\s*\))$',
+ r'\1"\2"\3', line))
+ elif line[:13] == ' (copy-func ':
+ outfp.write(re.sub(r'^(\s+\(copy-func\s+)(\w+)(.*)$',
+ r'\1"\2"\3', line))
+ elif line[:16] == ' (release-func ':
+ outfp.write(re.sub(r'^(\s+\(release-func\s+)(\w+)(.*)$',
+ r'\1"\2"\3', line))
+ elif line[:9] == ' (field ':
+ if not seen_params:
+ outfp.write(' (fields\n')
+ seen_params = 1
+ outfp.write(re.sub(r'^\s+\(field\s+\(type-and-name\s+([^\s]+)\s+([^\s]+)\s*\)\s*\)$',
+ ' \'("\\1" "\\2")', line))
+ elif line[:9] == ' (value ':
+ if not seen_params:
+ outfp.write(' (values\n')
+ seen_params = 1
+ outfp.write(re.sub(r'^\s+\(value\s+\(name\s+([^\s]+)\)\s+\(c-name\s+([^\s]+)\s*\)\s*\)$',
+ ' \'("\\1" "\\2")', line))
+ elif line[:13] == ' (parameter ':
+ if not seen_params:
+ outfp.write(' (parameters\n')
+ seen_params = 1
+ outfp.write(re.sub(r'^\s+\(parameter\s+\(type-and-name\s+([^\s]+)\s+([^\s]+)\s*\)(\s*.*)\)$',
+ ' \'("\\1" "\\2"\\3)', line))
+ elif line[:11] == ' (varargs ':
+ if seen_params:
+ outfp.write(' )\n')
+ seen_params = 0
+ outfp.write(' (varargs #t)\n')
+ elif line[0] == ')':
+ if seen_params:
+ outfp.write(' )\n')
+ seen_params = 0
+ state = STATE_START
+ outfp.write(line)
+ else:
+ outfp.write(line)
+ line = infp.readline()
+
+if __name__ == '__main__':
+ convert()
diff --git a/codegen/defsgen.py b/codegen/defsgen.py
new file mode 100755
index 0000000..6c2e63d
--- /dev/null
+++ b/codegen/defsgen.py
@@ -0,0 +1,737 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+#
+# Copyright (C) 2006-2009 John Finlay.
+#
+# Scan the given public .h files of a GTK module (or module using
+# GTK object conventions) and generates a set of scheme defs.
+#
+# defsgen uses the ctypes module to extract information from the installed
+# module library (or libraries) to generate the object, interface, function,
+# method, virtual, enum and flags defs. defsgen uses the gobject library
+# g_type_* functions. defsgen will try to open the "libgobject-2.0.so" library
+# if one is not specified on the command line.
+#
+# Basically the operation of defsgen is:
+#
+# - open and initialize the gobject and module libraries
+# - read each .h file into a buffer which is scrubbed of extraneous data
+# - find all *_get_type() functions prototypes
+# - look in the module libraries for the get_type symbols
+# - if found run the get_type() function to retrieve the GType
+# - find the parent type name and save the object info
+# - find each function prototypes in the file and check if it has a symbol in
+# the module libraries - save the info if found
+# - extract the virtual prototypes from the Class or Iface structs and save
+# - write out the various defs.
+#
+# The command line options are:
+#
+# -l --modulelib Adds the given module library name to the list to be used
+# for finding symbols. Mor ethan one modulefile may be
+# specified. (required)
+# -L --libgobject Specifies the name of the gobject library (optional but
+# must be specified if "libgobject-2.0.so" is not availble)
+# -s --separate Create separate files for objects and function/method defs
+# using the given name as the base name (optional). If this
+# is not specified the combined object and function defs
+# will be output to sys.stdout.
+# -f --defsfile Extract defs from the given file to filter the output defs
+# that is don't output defs that are defined in the
+# defsfile. More than one deffile may be specified.
+# -D --defines Include portions of the defsfile defs that are conditional
+# on the given define, for example GDK_TARGET_X11. Only
+# useful with the --defsfile option
+# -m --modulename The prefix to be stripped from the front of function names
+# for the given module
+# -p --useprefix Use the modulename prefix as a hint to split names into
+# module and name for object and enum defs. Also used for
+# generating type codes.
+# --onlyenums Only produce defs for enums and flags
+# --onlyobjdefs Only produce defs for objects
+# --onlyvirtuals Only produce defs for virtuals
+# --genpropgetsets Experimental option to generate prop-getset annotations.
+# Not supported by codegen.py and friends.
+#
+# Examples:
+#
+# python defsgen.py -m pango -l libpango-1.0.so \
+# /usr/local/include/pango-1.0/pango/*.h >/tmp/pango.defs
+#
+# - Outputs all defs for the pango module.using the library module
+# libpango-1.0.so.
+#
+# python defsgen.py -m gdk -DGDK_TARGET_X11 -l libgdk-x11-2.0.so \
+# -l libgdk_pixbuf-2.0.so -s /tmp/gdk-2.10 \
+# -f /usr/tmp/pygtk/gtk/gdk-base.defs \
+# /usr/local/include/gtk-2.0/gdk/*.h \
+# /usr/local/include/gtk-2.0/gdk-pixbuf/*.h
+#
+# - Outputs the gdk module defs that are not contained in the defs file
+# /usr/tmp/pygtk/gtk/gdk-base.defs. Two output files are created:
+# /tmp/gdk-2.10-types.defs and /tmp/gdk-2.10.defs.
+#
+# Based on the original h2def.py program by
+# Toby D. Reeves <toby@max.rl.plh.af.mil> and
+# 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
+# Extensively modified by John Finlay to use ctypes module to extract GType
+# info from the given library and to create virtual defines.
+#
+
+import getopt
+import os
+import re, string
+import sys
+import ctypes
+import defsparser
+
+#------------------ utility defs -----------------
+
+_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 uppercase 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 name.upper()
+
+def typecode(typename, prefix, use_prefix):
+ """create a typecode (eg. GTK_TYPE_WIDGET) from a typename"""
+ tcode = to_upper_str(typename)
+ if (use_prefix and prefix and tcode.lower() != prefix
+ and tcode.lower().startswith(prefix)):
+ l = len(prefix)
+ tcode = tcode[:l] + '_TYPE' + tcode[l:]
+ else:
+ tcode = tcode.replace('_', '_TYPE_', 1)
+ return tcode
+
+_class_iface_pat = re.compile(r'\w+(Class|Iface)')
+
+def class_iface_sub(mobj):
+ '''Returns matched string if it matches a Class or Iface struct
+ otherwise returns the empty string'''
+ if not _class_iface_pat.match(mobj.group(1)):
+ return ''
+ return mobj.group(0)
+
+clean_patterns = [
+ # strip comments
+ (re.compile(r'/\*.*?\*/', re.DOTALL), ''),
+ # compact continued lines
+ (re.compile(r"\\\n", re.MULTILINE), ''),
+ # remove preprocess directives
+ (re.compile(r"""^[#].*?$""", re.MULTILINE), ''),
+ # strip DECLS macros and Windows DLL API macros
+ (re.compile(r"""G_BEGIN_DECLS|BEGIN_LIBGTOP_DECLS|G_END_DECLS|[A-Z]+_API """,
+ re.MULTILINE), ''),
+ # remove extern "C"
+ (re.compile(r'^\s*(extern)\s+"C"\s+{', re.MULTILINE), ''),
+ # remove singleline typedefs of stucts
+ (re.compile(r'^typedef\s+struct\s*[^{;\n]*;\s*$', re.MULTILINE), ''),
+ # remove all struct definitons but those for object classes and interfaces
+ (re.compile(r'^struct\s+(\w+)\s+{[^}]+}\s*;\s*$', re.MULTILINE),
+ class_iface_sub),
+ # compress multiple whitespace
+ (re.compile(r'\s+', re.MULTILINE), ' '),
+ # clean up line ends
+ (re.compile(r';\s*', re.MULTILINE), '\n'),
+ (re.compile(r'^\s*', re.MULTILINE), ''),
+ # associate *, &, and [] with type instead of variable
+ (re.compile(r' \s* ([*|&]+) \s* ([(\w]+)', re.VERBOSE), r'\1 \2'),
+ (re.compile(r'\s+ (\w+) \[ \s* \]', re.VERBOSE), r'[] \1'),
+ # make return types that are const work.
+ (re.compile(r'\s*\*\s*G_CONST_RETURN\s*\*\s*'), '** '),
+ (re.compile(r'G_CONST_RETURN |const '), 'const-'),
+ # remove typedefs of callback types
+ (re.compile(r'^typedef\s+\w+\s*\*?\s*\(\s*\*\s*\w+\)\s*\([^(]*\)\n',
+ re.MULTILINE), ''),
+ #strip GSEAL macros from the middle of function declarations:
+ (re.compile(r"""GSEAL""", re.VERBOSE), '')
+ ]
+
+def clean_buffer(buf):
+ """Cleans out extraneous data leaving function prototypes, Class and Iface
+ structs."""
+ for pat, subst in clean_patterns:
+ buf = pat.sub(subst, buf)
+ return buf
+
+# ------------------ utility classes -------------------------
+
+class ObjDef(object):
+ def __init__(self, name, type_id, parent_name, parent_type, base_name):
+ self.name = name
+ self.type = type_id
+ self.parent_name = parent_name
+ self.parent_type = parent_type
+ self.base_name = base_name
+ self.props = []
+ return
+ def __cmp__(self, other):
+ try:
+ res = cmp(self.name, other.name)
+ except AttributeError:
+ res = cmp(id(self), id(other))
+ return res
+ def set_properties(self, gobj):
+ if self.base_name == 'GObject':
+ self.props = self._get_gobject_properties(gobj)
+ elif self.base_name == 'GInterface':
+ self.props = self._get_ginterface_properties(gobj)
+
+ def _get_gobject_properties(self, gobj):
+ klass = gobj.g_type_class_ref(self.type)
+ num = ctypes.c_uint()
+ plist = gobj.g_object_class_list_properties(klass, ctypes.byref(num))
+ props = [plist[i][0].name for i in range(num.value)
+ if self.name == gobj.g_type_name(plist[i][0].owner_type)]
+ return props
+ def _get_ginterface_properties(self, gobj):
+ iface = gobj.g_type_default_interface_ref(self.type)
+ num = ctypes.c_uint()
+ plist = gobj.g_object_interface_list_properties(iface,
+ ctypes.byref(num))
+ props = [plist[i][0].name for i in range(num.value)]
+ return props
+
+# ------------------ Find object definitions -----------------
+
+split_prefix_pat = re.compile('([A-Z]+[a-z]*)([A-Za-z0-9]+)')
+
+get_type_pat = re.compile(r'''^\s*(GType|GtkType)\s+
+([a-z]\w+_get_type)\s*(\(void\)|\(\)).*$''', re.VERBOSE | re.MULTILINE)
+
+defkeys = 'GBoxed GInterface GObject gpointer GEnum GFlags'
+
+def find_defs(buf, gobj, modlib, defs):
+ """Find possible gobject, gboxed, interface, gpointer, enum and flags
+ definitions in header files.and find parent type."""
+ # find all *_get_type() functions that may represent a GObject
+ for m in get_type_pat.findall(buf):
+ func_name = m[1]
+ for lib in modlib:
+ if hasattr(lib, func_name):
+ objtype = apply(getattr(lib, func_name))
+ obj_name = gobj.g_type_name(objtype)
+ parent = gobj.g_type_parent(objtype)
+ parent_name = gobj.g_type_name(parent)
+ base_name = gobj.g_type_name(gobj.g_type_fundamental(parent))
+ #if gobj.g_type_is_a(parent, gobj.GObject):
+ # base_name = 'GObject'
+ if base_name in defkeys:
+ obj = ObjDef(obj_name, objtype, parent_name, parent,
+ base_name)
+ obj.set_properties(gobj)
+ defs[obj.base_name].append(obj)
+ break
+ return
+
+# ------------------ Find function definitions -----------------
+
+arg_split_pat = re.compile("\s*,\s*")
+
+proto_pat=re.compile(r"""^
+\s*((?:-|\w|\&|\*)+) # return type
+\s+ # skip whitespace
+([a-z]\w+)\s*[(] # match the function name until the opening (
+\s*(.*?)\s*[)].* # group the function arguments
+$""", re.IGNORECASE|re.VERBOSE|re.MULTILINE)
+
+def find_func_defs(buf, modlib, deffile, defs, verbose):
+ '''Find function prototypes in buf that have symbols in modlib
+ and save in defs.'''
+ funcs = defs['funcs'][deffile] = []
+ for m in proto_pat.findall(buf):
+ ret, func, args = m
+ if not True in [hasattr(lib, func) for lib in modlib]:
+ if verbose:
+ sys.stderr.write('no symbol for function: ' + func
+ + ' from file' + deffile + '\n')
+ else:
+ args = arg_split_pat.split(args)
+ args = [a.replace(' ','-', a.count(' ')-1) for a in args]
+ funcs.append((func, ret, args))
+ return
+
+virtual_pat = re.compile(r'''^
+\s*((?:-|\w|\&|\*)+) # return type
+\s* # skip whitespace
+\(\s*\*\s* # opening (
+([a-z]\w+)\) # match the function name until the closing )
+\s*\(\s*([^)]*)\).* # group the function arguments
+$''', re.VERBOSE|re.MULTILINE)
+
+class_iface_struct_pat = re.compile(
+ r'^struct\s+_(\w+)(?:Class|Iface)\s+{([^}]+)}\s*$', re.MULTILINE)
+
+def find_virt_defs(buf, deffile, defs):
+ '''Find virtual function prototypes in buf and save in defs.'''
+ virts = defs['virts'][deffile] = []
+ # get the Class or Iface structs
+ for m in class_iface_struct_pat.findall(buf):
+ objname, virtuals = m
+ for v in virtual_pat.findall(virtuals):
+ ret, func, args = v
+ if 'reserved' in func or args == 'void':
+ continue
+ args = arg_split_pat.split(args)
+ args = [a.replace(' ','-', a.count(' ')-1) for a in args]
+ virts.append((func, ret, args, objname))
+ return
+
+enum_pat = re.compile(r'^\s*typedef enum\s+{\s*([^}]*)}\s*([^\s]*)$',
+ re.MULTILINE)
+values_splitter = re.compile(r'\s*,\s', re.MULTILINE)
+
+def find_enums(buf, defs):
+ for vals, name in enum_pat.findall(buf):
+ if name != 'GdkCursorType':
+ isflags = '<<' in vals
+ entries = [val.split()[0] for val in values_splitter.split(vals)
+ if val.strip()]
+ if entries:
+ defs['untypedenums'][name] = (isflags, entries)
+ return
+
+# ------------------ write definitions -----------------
+
+type_pat = re.compile(r'(?:const-)?([A-Za-z0-9]+)\*?\s+')
+pointer_pat = re.compile('(.*)\*$')
+func_new_pat = re.compile('(\w+)_new$')
+getset_pat = re.compile(r'^(?:get|set)_(.*)$')
+
+def split_prefix(cname, prefix, use_prefix):
+ # use the module prefix to split the cname
+ pre = prefix.replace('_', '')
+ if use_prefix and cname.lower().startswith(pre):
+ l = len(pre)
+ module = cname[:l]
+ name = cname[l:]
+ else:
+ m = split_prefix_pat.match(cname)
+ if m:
+ module = m.group(1)
+ name = m.group(2)
+ return module, name
+
+class DefsWriter:
+ def __init__(self, defs, fp=None, prefix=None, verbose=False,
+ defsfiles=None, defines={}, genpropgetsets=False,
+ useprefix=False):
+ self.defs = defs
+ self.use_prefix = useprefix
+ self.objnames = reduce(list.__add__,
+ [[o.name for o in defs[base]]
+ for base in defkeys.split()[:3]])
+ self.othernames = reduce(list.__add__,
+ [[o.name for o in defs[base]]
+ for base in defkeys.split()[3:]])
+ self.objifacedefs = dict(reduce(list.__add__,
+ [[(o.name, o) for o in defs[base]]
+ for base in defkeys.split()[1:3]]))
+ self.fp = (fp, sys.stdout)[not fp]
+ self.prefix = prefix
+ self.verbose = verbose
+ self.genpropgetsets = genpropgetsets
+ self._c_names={}
+ for defsfile in defsfiles:
+ filter = defsparser.DefsParser(defsfile, defines)
+ filter.startParsing()
+ self._c_names.update(filter.c_name)
+ for vdef in filter.virtuals:
+ self._c_names[vdef.of_object + '.' + vdef.name] = None
+ return
+
+ def write_func_defs(self, deffiles, onlyvirts=False):
+ filter = self._c_names
+ for deffile in deffiles:
+ self.fp.write('\n;; From %s\n\n' % os.path.basename(deffile))
+ if not onlyvirts:
+ for func, ret, args in self.defs['funcs'][deffile]:
+ if not func in filter:
+ self._write_func(func, ret, args)
+ for virt, ret, args, objname in self.defs['virts'][deffile]:
+ if not objname + '.' + virt in filter:
+ self._write_virt(objname, virt, ret, args)
+ self.fp.write('\n')
+ return
+
+ def write_enum_defs(self, fp=None):
+ fp = (fp, self.fp)[not fp]
+ klassptrs = {'GEnum':ctypes.POINTER(EnumClass),
+ 'GFlags':ctypes.POINTER(FlagsClass)}
+ filter = self._c_names
+ objs = self.defs['GEnum'] + self.defs ['GFlags']
+ #objs.sort()
+ fp.write(';; Enumerations and Flags ...\n\n')
+ for obj in objs:
+ cname = name = obj.name
+ tcode = typecode(cname, self.prefix, self.use_prefix)
+ if cname in filter:
+ continue
+ if cname in self.defs['untypedenums']:
+ if tcode not in self.defs['typedefines']:
+ # no type define so skip and print as untyped enum
+ continue
+ self.defs['untypedenums'].pop(cname, None)
+ parent_name = obj.parent_name
+ klassptr = klassptrs[parent_name]
+ typename = parent_name.lower()[1:]
+ module = None
+ module, name = split_prefix(cname, self.prefix, self.use_prefix)
+ fp.write('(define-' + typename + ' ' + name + '\n')
+ if module:
+ fp.write(' (in-module "' + module + '")\n')
+ fp.write(' (c-name "' + cname + '")\n')
+ fp.write(' (gtype-id "' + tcode + '")\n')
+ fp.write(' (values\n')
+ classref = self.gobj.g_type_class_ref(obj.type)
+ itemclass = ctypes.cast(classref, klassptr).contents
+ for i in range(itemclass.n_values):
+ val = itemclass.values[i]
+ fp.write(' \'("%s" "%s")\n' % (val.value_nick,
+ val.value_name))
+ fp.write(' )\n')
+ fp.write(')\n\n')
+ if self.defs['untypedenums']:
+ self.write_untyped_enum_defs(fp)
+ return
+
+ def write_untyped_enum_defs(self, fp):
+ fp.write(';; Untyped enumerations and flags ...\n\n')
+ filter = self._c_names
+ for cname, (isflags, entries) in self.defs['untypedenums'].items():
+ if filter and cname in filter: continue
+ module, name = split_prefix(cname, self.prefix, self.use_prefix)
+ 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')
+ preindex = entries[0].rfind('_')
+ for ent in entries[1:]:
+ while (preindex > 0
+ and ent[:preindex] != entries[0][:preindex]):
+ preindex = ent[:preindex].rfind('_')
+ fp.write(' (values\n')
+ for ent in entries:
+ fp.write(' \'("%s" "%s")\n' %
+ (ent[preindex+1:].lower().replace('_', '-'), ent))
+ fp.write(' )\n')
+ fp.write(')\n\n')
+
+
+ def _write_obj_helper(self, obj, fp):
+ base_name = obj.base_name.lower()[1:]
+ cmodule = None
+ cname = name = obj.name
+ type_id = obj.type
+ parent_name = obj.parent_name
+ cmodule, name = split_prefix(cname, self.prefix, self.use_prefix)
+ fp.write('(define-' + base_name + ' ' + name + '\n')
+ if cmodule:
+ fp.write(' (in-module "' + cmodule + '")\n')
+ if base_name == 'object':
+ fp.write(' (parent "' + parent_name + '")\n')
+ fp.write(' (c-name "' + cname + '")\n')
+ fp.write(' (gtype-id "'
+ + typecode(cname, self.prefix, self.use_prefix) + '")\n')
+ n = ctypes.c_uint()
+ ifaces = self.gobj.g_type_interfaces(type_id, ctypes.byref(n))
+ for i in range(n.value):
+ iface_name = self.gobj.g_type_name(ifaces[i])
+ if iface_name in self.interfaces:
+ fp.write(' (implements "%s")\n' % iface_name)
+ if base_name == 'interface':
+ prereq = self.gobj.g_type_interface_prerequisites(type_id,
+ ctypes.byref(n))
+ for i in range(n.value):
+ fp.write(' (prerequisite "%s")\n'
+ % self.gobj.g_type_name(prereq[i]))
+ # should do something about accessible fields
+ fp.write(')\n\n')
+ return
+
+ def write_obj_defs(self, fp=None):
+ fp = (fp, self.fp)[not fp]
+ fp.write(';; -*- scheme -*-\n')
+ filter = self._c_names
+ for base in defkeys.split()[:4]:
+ base_name = base.lower()[1:]
+ fp.write('; %s definitions ...\n\n' % base_name)
+ for obj in self.defs[base]:
+ if not obj.name in filter:
+ self._write_obj_helper(obj, fp)
+ return
+
+ def _write_func(self, name, ret, args):
+ if len(args) >= 1:
+ # methods must have at least one argument
+ munged_name = name.replace('_', '')
+ m = type_pat.match(args[0])
+ if m:
+ obj = m.group(1)
+ if munged_name.startswith(obj.lower()):
+ if obj not in self.othernames:
+ self._write_method(obj, name, ret, args)
+ return
+ fname = name
+ if self.prefix:
+ fname = re.sub('^'+self.prefix+'_', '', fname)
+
+ # it is either a constructor or normal function
+ self.fp.write('(define-function ' + fname + '\n')
+ self.fp.write(' (c-name "' + name + '")\n')
+
+ # Asume that a constructor function name
+ # ends with '_new' and it returns an object pointer.
+ m = func_new_pat.match(name)
+ r = pointer_pat.match(ret)
+ if m and r:
+ cname = ''
+ # get the type name by using the _get_type function
+ func = m.group(1) + '_get_type'
+ lib = [l for l in self.modlib if hasattr(l, func)]
+ if lib:
+ cname = self.gobj.g_type_name(apply(getattr(lib[0], func)))
+ if cname and self.gobj.g_type_from_name(r.group(1)):
+ self.fp.write(' (is-constructor-of "' + cname + '")\n')
+ self._write_return(ret)
+ self._write_arguments(args)
+ return
+
+ def _write_method(self, obj, name, ret, args):
+ regex = ''.join([c+'_?' for c in obj.lower()])
+ mname, count = re.subn(regex, '', name, 1)
+ if not count and self.prefix:
+ mname = re.sub('^'+self.prefix+'_', '', mname)
+ self.fp.write('(define-method ' + mname + '\n')
+ self.fp.write(' (of-object "' + obj + '")\n')
+ self.fp.write(' (c-name "' + name + '")\n')
+ m = getset_pat.match(mname)
+ if self.genpropgetsets and m and len(args[1:]) <= 1:
+ prop = m.group(1)
+ if obj in self.objifacedefs:
+ oidef = self.objifacedefs[obj]
+ if prop.replace('_', '-') in oidef.props:
+ self.fp.write(' (prop-getset "' + prop + '")\n')
+ self._write_return(ret)
+ self._write_arguments(args[1:])
+ return
+
+ def _write_virt(self, obj, name, ret, args):
+ self.fp.write('(define-virtual ' + name + '\n')
+ self.fp.write(' (of-object "' + obj + '")\n')
+ self._write_return(ret)
+ self._write_arguments(args[1:])
+ return
+
+ def _write_return(self, ret):
+ if ret == 'void':
+ ret = 'none'
+ self.fp.write(' (return-type "' + ret + '")\n')
+ return
+
+ def _write_arguments(self, args):
+ if args and not 'void' in args:
+ varargs = ''
+ self.fp.write(' (parameters\n')
+ for arg in args:
+ if arg == '...':
+ varargs = ' (varargs #t)\n'
+ else:
+ tupleArg = tuple(arg.split())
+ if len(tupleArg) == 2:
+ self.fp.write(' \'("%s" "%s")\n' % tupleArg)
+ self.fp.write(' )\n' + varargs)
+ self.fp.write(')\n\n')
+
+# ---------- ctypes support classes for gobject library functions ----------
+
+GType = ctypes.c_uint
+
+class GTypeClass(ctypes.Structure):
+ _fields_ = [('g_type', GType)]
+
+class GTypeInstance(ctypes.Structure):
+ _fields_ = [('g_class', ctypes.POINTER(GTypeClass))]
+
+class EnumValue(ctypes.Structure):
+ _fields_ = [('value', ctypes.c_int),
+ ('value_name', ctypes.c_char_p),
+ ('value_nick', ctypes.c_char_p)]
+
+class FlagsValue(ctypes.Structure):
+ _fields_ = [('value', ctypes.c_uint),
+ ('value_name', ctypes.c_char_p),
+ ('value_nick', ctypes.c_char_p)]
+
+class EnumClass(ctypes.Structure):
+ _fields_ = [('g_type_class', GTypeClass),
+ ('minimum', ctypes.c_int),
+ ('maximum', ctypes.c_int),
+ ('n_values', ctypes.c_uint),
+ ('values', ctypes.POINTER(EnumValue))]
+
+class FlagsClass(ctypes.Structure):
+ _fields_ = [('g_type_class', GTypeClass),
+ ('mask', ctypes.c_uint),
+ ('n_values', ctypes.c_uint),
+ ('values', ctypes.POINTER(FlagsValue))]
+
+class GTypeInterface(ctypes.Structure):
+ _fields_ = [('g_type', GType),
+ ('g_instance_type', GType)]
+
+class GParamSpec(ctypes.Structure):
+ _fields_ = [('g_type_instance', GTypeInstance),
+ ('name', ctypes.c_char_p),
+ ('flags', ctypes.c_uint),
+ ('value_type', GType),
+ ('owner_type', GType)]
+
+# ------------------ Main function -----------------
+
+def main(args):
+ verbose = False
+ all = True
+ onlyenums = False
+ onlyobjdefs = False
+ onlyvirtuals = False
+ separate = False
+ modulename = None
+ defsfiles = []
+ libgobject = None
+ modulelibs = []
+ defines = {}
+ genpropgetsets = False
+ use_prefix = False
+ opts, args = getopt.getopt(args[1:], 'vs:m:f:D:L:l:p',
+ ['onlyenums', 'onlyobjdefs', 'onlyvirtuals',
+ 'modulename=', 'separate=',
+ 'defsfile=', 'defines=', 'genpropgetsets',
+ 'libgobject-', 'modulelib=', 'useprefix'])
+ for o, v in opts:
+ if o == '-v':
+ verbose = True
+ if o == '--onlyenums':
+ onlyenums = True
+ all = False
+ if o == '--onlyvirtuals':
+ onlyvirtuals = True
+ all = False
+ if o == '--onlyobjdefs':
+ onlyobjdefs = True
+ all = False
+ if o in ('-p', '--useprefix'):
+ use_prefix = True
+ if o == '--genpropgetsets':
+ genpropgetsets = True
+ if o in ('-s', '--separate'):
+ separate = v
+ if o in ('-m', '--modulename'):
+ modulename = v
+ if o in ('-L', '--libgobject'):
+ libgobject = v
+ if o in ('-l', '--modulelib'):
+ modulelibs.append(v)
+ if o in ('-f', '--defsfile'):
+ defsfiles.append(v)
+ if o in ('-D', '--defines'):
+ nameval = v.split('=')
+ try:
+ defines[nameval[0]] = nameval[1]
+ except IndexError:
+ defines[nameval[0]] = None
+
+ if not args[0:1]:
+ print 'Must specify at least one input file name'
+ return -1
+ if not modulelibs:
+ print 'Must specify one or more modulelib names'
+ return -1
+
+ # load the gobject and module libraries and init the gtype system
+ if not libgobject:
+ if verbose:
+ sys.stderr.write('Using "libgobject-2.0.so" as the libobject' \
+ 'library name by default\n')
+ gobj = ctypes.cdll.LoadLibrary('libgobject-2.0.so')
+ else:
+ gobj = ctypes.cdll.LoadLibrary(libgobject)
+
+ modlib = [ctypes.cdll.LoadLibrary(lib) for lib in modulelibs]
+
+ gobj.g_type_init()
+ gobj.g_type_name.restype = ctypes.c_char_p
+ gobj.g_type_from_name.argtypes = [ctypes.c_char_p]
+ gobj.g_type_interfaces.restype = ctypes.POINTER(ctypes.c_int)
+ gobj.g_type_interface_prerequisites.restype = ctypes.POINTER(ctypes.c_int)
+ gobj.g_object_class_list_properties.restype = ctypes.POINTER(ctypes.POINTER(GParamSpec))
+ gobj.g_object_interface_list_properties.restype = ctypes.POINTER(ctypes.POINTER(GParamSpec))
+ gobj.GObject = gobj.g_type_from_name('GObject')
+ gobj.g_object_new(gobj.GObject, None)
+
+ defs = {}
+ for key in defkeys.split():
+ defs[key] = []
+ defs['funcs'] = {}
+ defs['virts'] = {}
+ defs['untypedenums'] = {}
+ defs['typedefines'] = []
+
+ # read in all the object and function definitions
+ args.sort()
+ type_define_pat = re.compile(
+ r'^#define\s+([A-Z]\S+_TYPE_\S+)\s+.*[a-z]\w+_get_type.*$',
+ re.MULTILINE)
+ for filename in args:
+ buf = open(filename).read()
+ defs['typedefines'] += type_define_pat.findall(buf)
+ buf = clean_buffer(buf)
+ find_enums(buf, defs)
+ find_defs(buf, gobj, modlib, defs)
+ find_func_defs(buf, modlib, filename, defs, verbose)
+ find_virt_defs(buf, filename, defs)
+
+ for key in defkeys.split():
+ defs[key].sort()
+
+ methods = types = None
+ if separate:
+ methods = file(separate + '.defs', 'w')
+ types = file(separate + '-types.defs', 'w')
+
+ dw = DefsWriter(defs, methods, prefix=modulename, verbose=verbose,
+ defsfiles=defsfiles, defines=defines,
+ genpropgetsets=genpropgetsets, useprefix=use_prefix)
+ dw.interfaces = [i.name for i in defs['GInterface']]
+ dw.gobj = gobj
+ dw.modlib = modlib
+
+ if onlyobjdefs or all:
+ dw.write_obj_defs(types)
+ if separate:
+ print "Wrote object defs to %s-types.defs" % separate
+ if onlyenums or all:
+ dw.write_enum_defs(types)
+ if separate:
+ print "Wrote enum and flags defs to %s-types.defs" % separate
+ if onlyvirtuals or all:
+ dw.write_func_defs(args, onlyvirtuals)
+ if separate:
+ print "Wrote function and virtual defs to %s.defs" % separate
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/codegen/defsparser.py b/codegen/defsparser.py
new file mode 100644
index 0000000..37ba0a2
--- /dev/null
+++ b/codegen/defsparser.py
@@ -0,0 +1,153 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+import os, sys
+import scmexpr
+from definitions import BoxedDef, EnumDef, FlagsDef, FunctionDef, \
+ InterfaceDef, MethodDef, ObjectDef, PointerDef, VirtualDef
+
+include_path = ['.']
+
+class IncludeParser(scmexpr.Parser):
+ """A simple parser that follows include statements automatically"""
+ def include(self, input_filename):
+ global include_path
+ if os.path.isabs(input_filename):
+ filename = input_filename
+ # set self.filename to the include name, to handle recursive includes
+ oldfile = self.filename
+ self.filename = filename
+ self.startParsing()
+ self.filename = oldfile
+ else:
+ inc_path = [os.path.dirname(self.filename)] + include_path
+ for filename in [os.path.join(path_entry, input_filename)
+ for path_entry in inc_path]:
+ if not os.path.exists(filename):
+ continue
+ # set self.filename to the include name, to handle recursive includes
+ oldfile = self.filename
+ self.filename = filename
+ self.startParsing()
+ self.filename = oldfile
+ break
+ else:
+ raise IOError("%s not found in include path %s" % (input_filename, inc_path))
+
+class DefsParser(IncludeParser):
+ def __init__(self, arg, defines={}):
+ IncludeParser.__init__(self, arg)
+ self.objects = []
+ self.interfaces = []
+ self.enums = [] # enums and flags
+ self.boxes = [] # boxed types
+ self.pointers = [] # pointer types
+ self.functions = [] # functions and methods
+ self.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
+ 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)
+ 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 %r not found' % c_name)
+
+ 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:]:
+ #print >> sys.stderr, "-----> Handling conditional definition (%s): %s" % (args[0], arg)
+ self.handle(arg)
+ else:
+ pass
+ #print >> sys.stderr, "-----> Conditional %s is not true" % (args[0],)
+
+ def ifndef(self, *args):
+ if args[0] not in self.defines:
+ for arg in args[1:]:
+ self.handle(arg)
diff --git a/codegen/docextract.py b/codegen/docextract.py
new file mode 100644
index 0000000..eff8c5e
--- /dev/null
+++ b/codegen/docextract.py
@@ -0,0 +1,448 @@
+# -*- 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 GtkDoc:
+ def __init__(self):
+ self.name = None
+ self.block_type = '' # The block type ('function', 'signal', 'property')
+ self.params = []
+ self.annotations = []
+ self.description = ''
+ self.ret = ('', []) # (return, annotations)
+ def set_name(self, name):
+ self.name = name
+ def set_type(self, block_type):
+ self.block_type = block_type
+ def get_type(self):
+ return self.block_type
+ def add_param(self, name, description, annotations=[]):
+ if name == '...':
+ name = 'Varargs'
+ self.params.append((name, description, annotations))
+ def append_to_last_param(self, extra):
+ self.params[-1] = (self.params[-1][0], self.params[-1][1] + extra,
+ self.params[-1][2])
+ 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,
+ self.params[i][2])
+ return
+ # fall through to adding extra parameter ...
+ self.add_param(name, extra)
+ def add_annotation(self, annotation):
+ self.annotations.append(annotation)
+ def get_annotations(self):
+ return self.annotations
+ def append_to_description(self, extra):
+ self.description = self.description + extra
+ def get_description(self):
+ return self.description
+ def add_return(self, first_line, annotations=[]):
+ self.ret = (first_line, annotations)
+ def append_to_return(self, extra):
+ self.ret = (self.ret[0] + extra, self.ret[1])
+
+comment_start_pattern = re.compile(r'^\s*/\*\*\s')
+comment_end_pattern = re.compile(r'^\s*\*+/')
+comment_line_lead_pattern = re.compile(r'^\s*\*\s*')
+comment_empty_line_pattern = re.compile(r'^\s*\**\s*$')
+function_name_pattern = re.compile(r'^([a-z]\w*)\s*:?(\s*\(.*\)\s*){0,2}\s*$')
+signal_name_pattern = re.compile(r'^([A-Z]\w+::[a-z0-9-]+)\s*:?(\s*\(.*\)\s*){0,2}\s*$')
+property_name_pattern = re.compile(r'^([A-Z]\w+:[a-z0-9-]+)\s*:?(\s*\(.*\)\s*){0,2}\s*$')
+return_pattern = re.compile(r'^@?(returns:|return\s+value:)(.*\n?)$', re.IGNORECASE)
+deprecated_pattern = re.compile(r'^(deprecated\s*:\s*.*\n?)$', re.IGNORECASE)
+rename_to_pattern = re.compile(r'^(rename\s+to)\s*:\s*(.*\n?)$', re.IGNORECASE)
+param_pattern = re.compile(r'^@(\S+)\s*:(.*\n?)$')
+# Used to extract the annotations in the parameter and return descriptions
+# extracted using above [param|return]_pattern patterns.
+annotations_pattern = re.compile(r'^(?:(\s*\(.*\)\s*)*:)')
+# Used to construct the annotation lists.
+annotation_lead_pattern = re.compile(r'^\s*\(\s*(.*?)\s*\)\s*')
+
+# These patterns determine the identifier of the current comment block. They
+# are grouped in a list for easy determination of block identifiers (in
+# skip_to_identifier). The function_name_pattern should be tested for last
+# because it always matches signal and property identifiers.
+identifier_patterns = [ signal_name_pattern, property_name_pattern, function_name_pattern ]
+
+# This pattern is to match return sections that forget to have a colon (':')
+# after the initial 'Return' phrase. It is not included by default in the list
+# of final sections below because a lot of function descriptions begin with
+# 'Returns ...' and the process_description() function would stop right at that
+# first line, thinking it is a return section.
+no_colon_return_pattern = re.compile(r'^@?(returns|return\s+value)\s*(.*\n?)$', re.IGNORECASE)
+since_pattern = re.compile(r'^(since\s*:\s*.*\n?)$', re.IGNORECASE)
+
+# These patterns normally will be encountered after the description. Knowing
+# the order of their appearance is difficult so this list is used to test when
+# one begins and the other ends when processing the rest of the sections after
+# the description.
+final_section_patterns = [ return_pattern, since_pattern, deprecated_pattern, rename_to_pattern ]
+
+def parse_file(fp, doc_dict):
+ line = fp.readline()
+ while line:
+ cur_doc = GtkDoc()
+ line = skip_to_comment_block(fp, line)
+ line = skip_to_identifier(fp, line, cur_doc)
+ # See if the identifier is found (stored in the current GtkDoc by
+ # skip_to_identifier). If so, continue reading the rest of the comment
+ # block.
+ if cur_doc.name:
+ line = process_params(fp, line, cur_doc)
+ line = process_description(fp, line, cur_doc)
+ line = process_final_sections(fp, line, cur_doc)
+ # Add the current doc block to the dictionary of doc blocks.
+ doc_dict[cur_doc.name] = cur_doc
+
+# Given a list of annotations as string of the form
+# '(annotation1) (annotation2) ...' return a list of annotations of the form
+# [ (name1, value1), (name2, value2) ... ]. Not all annotations have values so
+# the values in the list of tuples could be empty ('').
+def get_annotation_list(annotations):
+ annotation_list = []
+ while annotations:
+ match = annotation_lead_pattern.match(annotations)
+ if match:
+ annotation_contents = match.group(1)
+ name, split, value = annotation_contents.strip().partition(' ')
+ annotation_list.append((name, value))
+ # Remove first occurrence to continue processing.
+ annotations = annotation_lead_pattern.sub('', annotations)
+ else:
+ break
+ return annotation_list
+
+# Given a currently read line, test that line and continue reading until the
+# beginning of a comment block is found or eof is reached. Return the last
+# read line.
+def skip_to_comment_block(fp, line):
+ while line:
+ if comment_start_pattern.match(line):
+ break
+ line = fp.readline()
+ return line
+
+# Given the current line in a comment block, continue skipping lines until a
+# non-blank line in the comment block is found or until the end of the block
+# (or eof) is reached. Returns the line where reading stopped.
+def skip_to_nonblank(fp, line):
+ while line:
+ if not comment_empty_line_pattern.match(line):
+ break
+ line = fp.readline()
+ # Stop processing if eof or end of comment block is reached.
+ if not line or comment_end_pattern.match(line):
+ break
+ return line
+
+# Given the first line of a comment block (the '/**'), see if the next
+# non-blank line is the identifier of the comment block. Stop processing if
+# the end of the block or eof is reached. Store the identifier (if there is
+# one) and its type ('function', 'signal' or 'property') in the given GtkDoc.
+# Return the line where the identifier is found or the line that stops the
+# processing (if eof or the end of the comment block is found first).
+def skip_to_identifier(fp, line, cur_doc):
+ # Skip the initial comment block line ('/**') if not eof.
+ if line: line = fp.readline()
+
+ # Now skip empty lines.
+ line = skip_to_nonblank(fp, line)
+
+ # See if the first non-blank line is the identifier.
+ if line and not comment_end_pattern.match(line):
+ # Remove the initial ' * ' in comment block line and see if there is an
+ # identifier.
+ line = comment_line_lead_pattern.sub('', line)
+ for pattern in identifier_patterns:
+ match = pattern.match(line)
+ if match:
+ # Set the GtkDoc name.
+ cur_doc.set_name(match.group(1))
+ # Get annotations and add them to the GtkDoc.
+ annotations = get_annotation_list(match.group(2))
+ for annotation in annotations:
+ cur_doc.add_annotation(annotation)
+ # Set the GtkDoc type.
+ if pattern == signal_name_pattern:
+ cur_doc.set_type('signal')
+ elif pattern == property_name_pattern:
+ cur_doc.set_type('property')
+ elif pattern == function_name_pattern:
+ cur_doc.set_type('function')
+ return line
+ return line
+
+# Given a currently read line (presumably the identifier line), read the next
+# lines, testing to see if the lines are part of parameter descriptions. If
+# so, store the parameter descriptions in the given doc block. Stop on eof and
+# return the last line that stops the processing.
+def process_params(fp, line, cur_doc):
+ # Skip the identifier line if not eof. Also skip any blank lines in the
+ # comment block. Return if eof or the end of the comment block are
+ # encountered.
+ if line: line = fp.readline()
+ line = skip_to_nonblank(fp, line)
+ if not line or comment_end_pattern.match(line):
+ return line
+
+ # Remove initial ' * ' in first non-empty comment block line.
+ line = comment_line_lead_pattern.sub('', line)
+
+ # Now process possible parameters as long as no eof or the end of the
+ # param section is not reached (which could be triggered by anything that
+ # doesn't match a '@param:..." line, even the end of the comment block).
+ match = param_pattern.match(line)
+ while line and match:
+ description = match.group(2)
+
+ # First extract the annotations from the description and save them.
+ annotations = []
+ annotation_match = annotations_pattern.match(description)
+ if annotation_match:
+ annotations = get_annotation_list(annotation_match.group(1))
+ # Remove the annotations from the description
+ description = annotations_pattern.sub('', description)
+
+ # Default to appending lines to current parameter.
+ append_func = cur_doc.append_to_last_param
+
+ # See if the return has been included as part of the parameter
+ # section and make sure that lines are added to the GtkDoc return if
+ # so.
+ if match.group(1).lower() == "returns":
+ cur_doc.add_return(description, annotations)
+ append_func = cur_doc.append_to_return
+ # If not, just add it as a regular parameter.
+ else:
+ cur_doc.add_param(match.group(1), description, annotations)
+
+ # Now read lines and append them until next parameter, beginning of
+ # description (an empty line), the end of the comment block or eof.
+ line = fp.readline()
+ while line:
+ # Stop processing if end of comment block or a blank comment line
+ # is encountered.
+ if comment_empty_line_pattern.match(line) or \
+ comment_end_pattern.match(line):
+ break
+
+ # Remove initial ' * ' in comment block line.
+ line = comment_line_lead_pattern.sub('', line)
+
+ # Break from current param processing if a new one is
+ # encountered.
+ if param_pattern.match(line): break;
+
+ # Otherwise, just append the current line and get the next line.
+ append_func(line)
+ line = fp.readline()
+
+ # Re-evaluate match for while condition
+ match = param_pattern.match(line)
+
+ # End by returning the current line.
+ return line
+
+# Having processed parameters, read the following lines into the description of
+# the current doc block until the end of the comment block, the end of file or
+# a return section is encountered.
+def process_description(fp, line, cur_doc):
+ # First skip empty lines returning on eof or end of comment block.
+ line = skip_to_nonblank(fp, line)
+ if not line or comment_end_pattern.match(line):
+ return line
+
+ # Remove initial ' * ' in non-empty comment block line.
+ line = comment_line_lead_pattern.sub('', line)
+
+ # Also remove possible 'Description:' prefix.
+ if line[:12] == 'Description:': line = line[12:]
+
+ # Used to tell if the previous line was blank and a return section
+ # uncommonly marked with 'Returns ...' instead of 'Returns: ...' has
+ # started (assume it is non-empty to begin with).
+ prev_line = 'non-empty'
+
+ # Now read lines until a new section (like a return or a since section) is
+ # encountered.
+ while line:
+ # See if the description section has ended (if the line begins with
+ # 'Returns ...' and the previous line was empty -- this loop replaces
+ # empty lines with a newline).
+ if no_colon_return_pattern.match(line) and prev_line == '\n':
+ return line
+ # Or if one of the patterns of the final sections match
+ for pattern in final_section_patterns:
+ if pattern.match(line):
+ return line
+
+ # If not, append lines to description in the doc comment block.
+ cur_doc.append_to_description(line)
+
+ prev_line = line
+ line = fp.readline()
+
+ # Stop processing on eof or at the end of comment block.
+ if not line or comment_end_pattern.match(line):
+ return line
+
+ # Remove initial ' * ' in line so that the text can be appended to the
+ # description of the comment block and make sure that if the line is
+ # empty it be interpreted as a newline.
+ line = comment_line_lead_pattern.sub('', line)
+ if not line: line = '\n'
+
+# Given the line that ended the description (the first line of one of the final
+# sections) process the final sections ('Returns:', 'Since:', etc.) until the
+# end of the comment block or eof. Return the line that ends the processing.
+def process_final_sections(fp, line, cur_doc):
+ while line and not comment_end_pattern.match(line):
+ # Remove leading ' * ' from current non-empty comment line.
+ line = comment_line_lead_pattern.sub('', line)
+ # Temporarily append the no colon return pattern to the final section
+ # patterns now that the description has been processed. It will be
+ # removed after the for loop below executes so that future descriptions
+ # that begin with 'Returns ...' are not interpreted as a return
+ # section.
+ final_section_patterns.append(no_colon_return_pattern)
+ for pattern in final_section_patterns:
+ match = pattern.match(line)
+ if match:
+ if pattern == return_pattern or \
+ pattern == no_colon_return_pattern:
+ # Dealing with a 'Returns:' so first extract the
+ # annotations from the description and save them.
+ description = match.group(2)
+ annotations = []
+ annotation_match = \
+ annotations_pattern.match(description)
+ if annotation_match:
+ annotations = \
+ get_annotation_list(annotation_match.group(1))
+ # Remove the annotations from the description
+ description = annotations_pattern.sub('', description)
+
+ # Now add the return.
+ cur_doc.add_return(description, annotations)
+ # In case more lines need to be appended.
+ append_func = cur_doc.append_to_return
+ elif pattern == rename_to_pattern:
+ # Dealing with a 'Rename to:' section (GObjectIntrospection
+ # annotation) so no further lines will be appended but this
+ # single one (and only to the annotations).
+ append_func = None
+ cur_doc.add_annotation((match.group(1),
+ match.group(2)))
+ else:
+ # For all others ('Since:' and 'Deprecated:') just append
+ # the line to the description for now.
+ cur_doc.append_to_description(line)
+ # In case more lines need to be appended.
+ append_func = cur_doc.append_to_description
+
+ # Stop final section pattern matching for loop since a match
+ # has already been found.
+ break
+
+ # Remove the no colon return pattern (which was temporarily added in
+ # the just executed loop) from the list of final section patterns.
+ final_section_patterns.pop()
+
+ line = fp.readline()
+
+ # Now continue appending lines to current section until a new one is
+ # found or an eof or the end of the comment block is encountered.
+ finished = False
+ while not finished and line and \
+ not comment_end_pattern.match(line):
+ # Remove leading ' * ' from line and make sure that if it is empty,
+ # it be interpreted as a newline.
+ line = comment_line_lead_pattern.sub('', line)
+ if not line: line = '\n'
+
+ for pattern in final_section_patterns:
+ if pattern.match(line):
+ finished = True
+ break
+
+ # Break out of loop if a new section is found (determined in above
+ # inner loop).
+ if finished: break
+
+ # Now it's safe to append line.
+ if append_func: append_func(line)
+
+ # Get the next line to continue processing.
+ line = fp.readline()
+
+ return line
+
+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':
+ sys.stderr.write("Processing " + path + '\n')
+ 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_pattern = re.compile(r'^<!-- ##### (\w+) (\w+) ##### -->$')
+def parse_tmpl(fp, doc_dict):
+ cur_doc = None
+
+ line = fp.readline()
+ while line:
+ match = tmpl_section_pattern.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 = GtkDoc()
+ 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_to_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_to_description(line)
+ else:
+ cur_doc.append_to_description(line)
+
+ line = fp.readline()
+
+def extract_tmpl(dirs, doc_dict=None):
+ if not doc_dict: doc_dict = {}
+ for dir in dirs:
+ for file in os.listdir(dir):
+ if file in ('.', '..'): continue
+ path = os.path.join(dir, file)
+ if os.path.isdir(path):
+ continue
+ if len(file) > 2 and file[-2:] == '.sgml':
+ parse_tmpl(open(path, 'r'), doc_dict)
+ return doc_dict
diff --git a/codegen/docextract_to_xml.py b/codegen/docextract_to_xml.py
new file mode 100755
index 0000000..7ac1053
--- /dev/null
+++ b/codegen/docextract_to_xml.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+#
+# This litte script outputs the C doc comments to an XML format.
+# So far it's only used by gtkmm (The C++ bindings). Murray Cumming.
+# Usage example:
+# # ./docextract_to_xml.py -s /gnome/head/cvs/gtk+/gtk/ -s /gnome/head/cvs/gtk+/docs/reference/gtk/tmpl/ > gtk_docs.xml
+
+import getopt
+import re
+import string
+import sys
+
+import docextract
+
+def usage():
+ sys.stderr.write('usage: docextract_to_xml.py ' +
+ '[-s /src/dir | --source-dir=/src/dir] ' +
+ '[-a | --with-annotations] [-p | --with-properties] ' +
+ '[-i | --with-signals ]\n')
+ sys.exit(1)
+
+# Translates special texts to &... HTML acceptable format. Also replace
+# occurrences of '/*' and '*/' with '/ *' and '* /' respectively to avoid
+# comment errors (note the spaces). Some function descriptions include C++
+# multi-line comments which cause errors when the description is included in a
+# C++ Doxygen comment block.
+def escape_text(unescaped_text):
+ # Escape every "&" not part of an entity reference
+ escaped_text = re.sub(r'&(?![A-Za-z]+;)', '&amp;', unescaped_text)
+
+ # These weird entities turn up in the output...
+ escaped_text = string.replace(escaped_text, '&mdash;', '&#8212;')
+ escaped_text = string.replace(escaped_text, '&ast;', '*')
+ escaped_text = string.replace(escaped_text, '&percnt;', '%')
+ escaped_text = string.replace(escaped_text, '&commat;', '@')
+ escaped_text = string.replace(escaped_text, '&num;', '&#35;')
+ escaped_text = string.replace(escaped_text, '&nbsp;', '&#160;')
+ # This represents a '/' before or after an '*' so replace with slash but
+ # with spaces.
+ escaped_text = string.replace(escaped_text, '&sol;', ' / ')
+
+ # Escape for both tag contents and attribute values
+ escaped_text = string.replace(escaped_text, '<', '&lt;')
+ escaped_text = string.replace(escaped_text, '>', '&gt;')
+ escaped_text = string.replace(escaped_text, '"', '&quot;')
+
+ # Replace C++ comment begin and ends to ones that don't affect Doxygen.
+ escaped_text = string.replace(escaped_text, '/*', '/ *')
+ escaped_text = string.replace(escaped_text, '*/', '* /')
+
+ return escaped_text
+
+def print_annotations(annotations):
+ for annotation in annotations:
+ print "<annotation name=" + annotation[0] + ">" + \
+ escape_text(annotation[1]) + "</annotation>"
+
+if __name__ == '__main__':
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "d:s:o:api",
+ ["source-dir=", "with-annotations",
+ "with-properties", "with-signals"])
+ except getopt.error, e:
+ sys.stderr.write('docextract_to_xml.py: %s\n' % e)
+ usage()
+ source_dirs = []
+ with_annotations = False
+ with_signals = False
+ with_properties = False
+ for opt, arg in opts:
+ if opt in ('-s', '--source-dir'):
+ source_dirs.append(arg)
+ if opt in ('-a', '--with-annotations'):
+ with_annotations = True
+ if opt in ('-p', '--with-properties'):
+ with_properties = True
+ if opt in ('-i', '--with-signals'):
+ with_signals = True
+ if len(args) != 0:
+ usage()
+
+ docs = docextract.extract(source_dirs);
+ docextract.extract_tmpl(source_dirs, docs); #Try the tmpl sgml files too.
+
+ # print d.docs
+
+ if docs:
+
+ print "<root>"
+
+ for name, value in docs.items():
+ # Get the type of comment block ('function', 'signal' or
+ # 'property') (the value is a GtkDoc).
+ block_type = value.get_type()
+
+ # Skip signals if the option was not specified.
+ if block_type == 'signal' and not with_signals:
+ continue
+ # Likewise for properties.
+ elif block_type == 'property' and not with_properties:
+ continue
+
+ print "<" + block_type + " name=\"" + escape_text(name) + "\">"
+
+ print "<description>"
+ print escape_text(value.get_description())
+ print "</description>"
+
+ # Loop through the parameters if not dealing with a property:
+ if block_type != 'property':
+ print "<parameters>"
+ for name, description, annotations in value.params:
+ print "<parameter name=\"" + escape_text(name) + "\">"
+ print "<parameter_description>" + escape_text(description) + "</parameter_description>"
+
+ if with_annotations:
+ print_annotations(annotations)
+
+ print "</parameter>"
+
+ print "</parameters>"
+
+ # Show the return-type (also if not dealing with a property):
+ if with_annotations:
+ print "<return>"
+ print "<return_description>" + escape_text(value.ret[0]) + \
+ "</return_description>"
+ print_annotations(value.ret[1])
+ print "</return>"
+ else:
+ print "<return>" + escape_text(value.ret[0]) + "</return>"
+
+ if with_annotations:
+ print_annotations(value.get_annotations())
+
+ print "</" + block_type + ">\n"
+
+ print "</root>"
diff --git a/codegen/docgen.py b/codegen/docgen.py
new file mode 100755
index 0000000..b9e2f67
--- /dev/null
+++ b/codegen/docgen.py
@@ -0,0 +1,766 @@
+#!/usr/bin/env python
+import getopt
+import os
+import re
+import sys
+
+import definitions
+import defsparser
+import docextract
+import override
+
+
+class Node:
+
+ def __init__(self, name, interfaces=[]):
+ self.name = name
+ self.interfaces = interfaces
+ self.subclasses = []
+
+ def add_child(self, node):
+ self.subclasses.append(node)
+
+
+def build_object_tree(parser):
+ # reorder objects so that parent classes come first ...
+ objects = parser.objects[:]
+ pos = 0
+ while pos < len(objects):
+ parent = objects[pos].parent
+ for i in range(pos+1, len(objects)):
+ if objects[i].c_name == parent:
+ objects.insert(i+1, objects[pos])
+ del objects[pos]
+ break
+ else:
+ pos = pos + 1
+
+ root = Node(None)
+ nodes = {None: root}
+ for obj_def in objects:
+ parent_name = obj_def.parent
+ if parent_name == 'GObject':
+ parent_name = None
+ parent_node = nodes[parent_name]
+ 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):
+ self._fp = None
+ # 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 + self.parser.interfaces +
+ self.parser.boxes + self.parser.pointers):
+ if not obj.c_name in self.classmap:
+ 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)
+ self._fp = open(filename, 'w')
+ self.write_full_hierarchy(hierarchy)
+ self._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)
+ self._fp = open(filename, 'w')
+ if isinstance(obj_def, definitions.ObjectDef):
+ self.output_object_docs(obj_def)
+ elif isinstance(obj_def, definitions.InterfaceDef):
+ self.output_interface_docs(obj_def)
+ elif isinstance(obj_def, definitions.BoxedDef):
+ self.output_boxed_docs(obj_def)
+ elif isinstance(obj_def, definitions.PointerDef):
+ self.output_boxed_docs(obj_def)
+ self._fp.close()
+ files[os.path.basename(filename)] = obj_def
+
+ if not files:
+ return
+
+ output_filename = self.create_toc_filename(output_prefix)
+ self._fp = open(output_filename, 'w')
+ self.output_toc(files)
+ self._fp.close()
+
+ def output_object_docs(self, obj_def):
+ self.write_class_header(obj_def.c_name)
+
+ self.write_heading('Synopsis')
+ self.write_synopsis(obj_def)
+ self.close_section()
+
+ # 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')
+ self.write_hierarchy(obj_def.c_name, ancestry)
+ self.close_section()
+
+ constructor = self.parser.find_constructor(obj_def, self.overrides)
+ if constructor:
+ self.write_heading('Constructor')
+ self.write_constructor(constructor,
+ self.docs.get(constructor.c_name, None))
+ self.close_section()
+
+ 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')
+ for method in methods:
+ self.write_method(method, self.docs.get(method.c_name, None))
+ self.close_section()
+
+ self.write_class_footer(obj_def.c_name)
+
+ def get_methods_for_object(self, obj_def):
+ methods = []
+ for method in self.parser.find_methods(obj_def):
+ if not self.overrides.is_ignored(method.c_name):
+ methods.append(method)
+ return methods
+
+ def output_interface_docs(self, int_def):
+ self.write_class_header(int_def.c_name)
+
+ self.write_heading('Synopsis')
+ self.write_synopsis(int_def)
+ self.close_section()
+
+ methods = self.get_methods_for_object(int_def)
+ if methods:
+ self.write_heading('Methods')
+ for method in methods:
+ self.write_method(method, self.docs.get(method.c_name, None))
+ self.close_section()
+ self.write_class_footer(int_def.c_name)
+
+ def output_boxed_docs(self, box_def):
+ self.write_class_header(box_def.c_name)
+
+ self.write_heading('Synopsis')
+ self.write_synopsis(box_def)
+ self.close_section()
+
+ constructor = self.parser.find_constructor(box_def, self.overrides)
+ if constructor:
+ self.write_heading('Constructor')
+ self.write_constructor(constructor,
+ self.docs.get(constructor.c_name, None))
+ self.close_section()
+
+ methods = self.get_methods_for_object(box_def)
+ if methods:
+ self.write_heading('Methods')
+ for method in methods:
+ self.write_method(method, self.docs.get(method.c_name, None))
+ self.close_section()
+
+ self.write_class_footer(box_def.c_name)
+
+ def output_toc(self, files):
+ self._fp.write('TOC\n\n')
+ for filename in sorted(files):
+ obj_def = files[filename]
+ self._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 + '-' + obj_name.lower() + '.txt'
+
+ def create_toc_filename(self, output_prefix):
+ return self.create_filename(self, 'docs', output_prefix)
+
+ def write_full_hierarchy(self, hierarchy):
+
+ def handle_node(node, indent=''):
+ for child in node.subclasses:
+ self._fp.write(indent + node.name)
+ if node.interfaces:
+ self._fp.write(' (implements ')
+ self._fp.write(', '.join(node.interfaces))
+ self._fp.write(')\n')
+ else:
+ self._fp.write('\n')
+ handle_node(child, indent + ' ')
+ handle_node(hierarchy)
+
+ def serialize_params(self, func_def):
+ params = []
+ for param in func_def.params:
+ params.append(param[1])
+ return ', '.join(params)
+
+ # these need to handle default args ...
+
+ def create_constructor_prototype(self, func_def):
+ return '%s(%s)' % (func_def.is_constructor_of,
+ self.serialize_params(func_def))
+
+ def create_function_prototype(self, func_def):
+ return '%s(%s)' % (func_def.name,
+ self.serialize_params(func_def))
+
+ def create_method_prototype(self, meth_def):
+ return '%s.%s(%s)' % (meth_def.of_object,
+ meth_def.name,
+ self.serialize_params(meth_def))
+
+ def write_class_header(self, obj_name):
+ self._fp.write('Class %s\n' % obj_name)
+ self._fp.write('======%s\n\n' % ('=' * len(obj_name)))
+
+ def write_class_footer(self, obj_name):
+ pass
+
+ def write_heading(self, text):
+ self._fp.write('\n' + text + '\n' + ('-' * len(text)) + '\n')
+
+ def close_section(self):
+ pass
+
+ def write_synopsis(self, obj_def):
+ self._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:
+ self._fp.write('(%s)' % ', '.join(bases, ))
+ self._fp.write(':\n')
+
+ constructor = self.parser.find_constructor(obj_def, self.overrides)
+ if constructor:
+ prototype = self.create_constructor_prototype(constructor)
+ self._fp.write(' def %s\n' % prototype)
+
+ for method in self.get_methods_for_object(obj_def):
+ prototype = self.create_method_prototype(method)
+ self._fp.write(' def %s\n' % prototype)
+
+ def write_hierarchy(self, obj_name, ancestry):
+ indent = ''
+ for name, interfaces in ancestry:
+ self._fp.write(indent + '+-- ' + name)
+ if interfaces:
+ self._fp.write(' (implements ')
+ self._fp.write(', '.join(interfaces))
+ self._fp.write(')\n')
+ else:
+ self._fp.write('\n')
+ indent = indent + ' '
+ self._fp.write('\n')
+
+ def write_constructor(self, func_def, func_doc):
+ prototype = self.create_constructor_prototype(func_def)
+ self._fp.write(prototype + '\n\n')
+ for type, name, dflt, null in func_def.params:
+ self.write_parameter(name, func_doc)
+ self.write_return_value(func_def, func_doc)
+ if func_doc and func_doc.description:
+ self._fp.write(func_doc.description)
+ self._fp.write('\n\n\n')
+
+ def write_method(self, meth_def, func_doc):
+ prototype = self.create_method_prototype(meth_def)
+ self._fp.write(prototype + '\n\n')
+ for type, name, dflt, null in meth_def.params:
+ self.write_parameter(name, func_doc)
+ self.write_return_value(meth_def, func_doc)
+ if func_doc and func_doc.description:
+ self._fp.write('\n')
+ self._fp.write(func_doc.description)
+ self._fp.write('\n\n')
+
+ def write_parameter(self, param_name, func_doc):
+ if func_doc:
+ descr = func_doc.get_param_description(param_name)
+ else:
+ descr = 'a ' + type
+ self._fp.write(' ' + param_name + ': ' + descr + '\n')
+
+ def write_return_value(self, meth_def, func_doc):
+ 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
+ self._fp.write(' Returns: ' + descr + '\n')
+
+CLASS_HEADER_TEMPLATE = """<refentry id="%(entryid)s">
+ <refmeta>
+ <refentrytitle>%(name)s</refentrytitle>
+ <manvolnum>3</manvolnum>
+ <refmiscinfo>%(miscinfo)s</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>%(name)s</refname><refpurpose></refpurpose>
+ </refnamediv>
+
+"""
+VARIABLE_TEMPLATE = """<varlistentry>
+ <term><parameter>%(parameter)s</parameter>&nbsp;:</term>
+ <listitem><simpara>%(description)s</simpara></listitem>
+ </varlistentry>
+"""
+
+DOCBOOK_HEADER = """<?xml version="1.0" standalone="no"?>
+<!DOCTYPE synopsis PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
+"""
+
+
+class DocbookDocWriter(DocWriter):
+
+ def __init__(self):
+ DocWriter.__init__(self)
+
+ self._function_pat = re.compile(r'(\w+)\s*\(\)')
+ self._parameter_pat = re.compile(r'\@(\w+)')
+ self._constant_pat = re.compile(r'\%(-?\w+)')
+ self._symbol_pat = re.compile(r'#([\w-]+)')
+
+ self._transtable = ['-'] * 256
+ # make string -> reference translation func
+ for digit in '0123456789':
+ self._transtable[ord(digit)] = digit
+
+ for letter in 'abcdefghijklmnopqrstuvwxyz':
+ self._transtable[ord(letter)] = letter
+ self._transtable[ord(letter.upper())] = letter
+ self._transtable = ''.join(self._transtable)
+
+ def create_filename(self, obj_name, output_prefix):
+ '''Create output filename for this particular object'''
+ stem = output_prefix + '-' + obj_name.lower()
+ return stem + '.xml'
+
+ def create_toc_filename(self, output_prefix):
+ return self.create_filename('classes', output_prefix)
+
+ def make_class_ref(self, obj_name):
+ return 'class-' + obj_name.translate(self._transtable)
+
+ def make_method_ref(self, meth_def):
+ return 'method-%s--%s' % (
+ meth_def.of_object.translate(self._transtable),
+ meth_def.name.translate(self._transtable))
+
+ def _format_function(self, match):
+ info = self.parser.c_name.get(match.group(1), None)
+ if info:
+ if isinstance(info, defsparser.FunctionDef):
+ return self._format_funcdef(info)
+ if isinstance(info, defsparser.MethodDef):
+ return self._format_method(info)
+
+ # fall through through
+ return '<function>%s()</function>' % (match.group(1), )
+
+ def _format_funcdef(self, info):
+ if info.is_constructor_of is not None:
+ # should have a link here
+ return '<methodname>%s()</methodname>' % (
+ self.pyname(info.is_constructor_of), )
+ else:
+ return '<function>%s()</function>' % (info.name, )
+
+ def _format_param(self, match):
+ return '<parameter>%s</parameterdliteral>' % (match.group(1), )
+
+ def _format_const(self, match):
+ return '<literal>%s</literal>' % (match.group(1), )
+
+ def _format_method(self, info):
+ return ('<link linkend="%s">'
+ '<methodname>%s.%s</methodname>'
+ '</link>') % (self.make_method_ref(info),
+ self.pyname(info.of_object),
+ info.name)
+
+ def _format_object(self, info):
+ return ('<link linkend="%s">'
+ '<classname>%s</classname>'
+ '</link>') % (self.make_class_ref(info.c_name),
+ self.pyname(info.c_name))
+
+ def _format_symbol(self, match):
+ info = self.parser.c_name.get(match.group(1), None)
+ if info:
+ if isinstance(info, defsparser.FunctionDef):
+ return self._format_funcdef(info)
+ elif isinstance(info, defsparser.MethodDef):
+ return self._format_method(info)
+ elif isinstance(info, (defsparser.ObjectDef,
+ defsparser.InterfaceDef,
+ defsparser.BoxedDef,
+ defsparser.PointerDef)):
+ return self._format_object(info)
+
+ # fall through through
+ return '<literal>%s</literal>' % (match.group(1), )
+
+ 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 = text.strip().split('\n')
+ for index in range(len(lines)):
+ if lines[index].strip() == '':
+ lines[index] = '</para>\n<para>'
+ continue
+ return '<para>%s</para>' % ('\n'.join(lines), )
+
+ # write out hierarchy
+
+ def write_full_hierarchy(self, hierarchy):
+
+ def handle_node(node, indent=''):
+ if node.name:
+ self._fp.write('%s<link linkend="%s">%s</link>' %
+ (indent, self.make_class_ref(node.name),
+ self.pyname(node.name)))
+ if node.interfaces:
+ self._fp.write(' (implements ')
+ for i in range(len(node.interfaces)):
+ self._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:
+ self._fp.write(', ')
+ self._fp.write(')\n')
+ else:
+ self._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, indent)
+
+ self._fp.write(DOCBOOK_HEADER)
+ self._fp.write('<synopsis>')
+ handle_node(hierarchy)
+ self._fp.write('</synopsis>\n')
+
+ # these need to handle default args ...
+
+ def create_constructor_prototype(self, func_def):
+ xml = ['<constructorsynopsis language="python">\n']
+ xml.append(' <methodname>__init__</methodname>\n')
+ for type, name, dflt, null in func_def.params:
+ xml.append(' <methodparam><parameter>')
+ xml.append(name)
+ xml.append('</parameter>')
+ if dflt:
+ xml.append('<initializer>')
+ xml.append(dflt)
+ xml.append('</initializer>')
+ xml.append('</methodparam>\n')
+ if not func_def.params:
+ xml.append(' <methodparam></methodparam>')
+ xml.append(' </constructorsynopsis>')
+ return ''.join(xml)
+
+ def create_function_prototype(self, func_def):
+ xml = ['<funcsynopsis language="python">\n <funcprototype>\n']
+ xml.append(' <funcdef><function>')
+ xml.append(func_def.name)
+ xml.append('</function></funcdef>\n')
+ for type, name, dflt, null in func_def.params:
+ xml.append(' <paramdef><parameter>')
+ xml.append(name)
+ xml.append('</parameter>')
+ if dflt:
+ xml.append('<initializer>')
+ xml.append(dflt)
+ xml.append('</initializer>')
+ xml.append('</paramdef>\n')
+ if not func_def.params:
+ xml.append(' <paramdef></paramdef')
+ xml.append(' </funcprototype>\n </funcsynopsis>')
+ return ''.join(xml)
+
+ def create_method_prototype(self, meth_def, addlink=0):
+ xml = ['<methodsynopsis language="python">\n']
+ xml.append(' <methodname>')
+ if addlink:
+ xml.append('<link linkend="%s">' % self.make_method_ref(meth_def))
+ xml.append(self.pyname(meth_def.name))
+ if addlink:
+ xml.append('</link>')
+ xml.append('</methodname>\n')
+ for type, name, dflt, null in meth_def.params:
+ xml.append(' <methodparam><parameter>')
+ xml.append(name)
+ xml.append('</parameter>')
+ if dflt:
+ xml.append('<initializer>')
+ xml.append(dflt)
+ xml.append('</initializer>')
+ xml.append('</methodparam>\n')
+ if not meth_def.params:
+ xml.append(' <methodparam></methodparam>')
+ xml.append(' </methodsynopsis>')
+ return ''.join(xml)
+
+ def write_class_header(self, obj_name):
+ self._fp.write(DOCBOOK_HEADER)
+ self._fp.write(CLASS_HEADER_TEMPLATE % dict(
+ entryid=self.make_class_ref(obj_name),
+ name=self.pyname(obj_name),
+ miscinfo="PyGTK Docs"))
+
+ def write_class_footer(self, obj_name):
+ self._fp.write('</refentry>\n')
+
+ def write_heading(self, text):
+ self._fp.write(' <refsect1>\n')
+ self._fp.write(' <title>' + text + '</title>\n\n')
+
+ def close_section(self):
+ self._fp.write(' </refsect1>\n')
+
+ def write_synopsis(self, obj_def):
+ self._fp.write('<classsynopsis language="python">\n')
+ self._fp.write(' <ooclass><classname>%s</classname></ooclass>\n'
+ % self.pyname(obj_def.c_name))
+ if isinstance(obj_def, definitions.ObjectDef):
+ if obj_def.parent:
+ self._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:
+ self._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):
+ self._fp.write(' <ooclass><classname>gobject.GInterface'
+ '</classname></ooclass>\n')
+ elif isinstance(obj_def, definitions.BoxedDef):
+ self._fp.write(' <ooclass><classname>gobject.GBoxed'
+ '</classname></ooclass>\n')
+ elif isinstance(obj_def, definitions.PointerDef):
+ self._fp.write(' <ooclass><classname>gobject.GPointer'
+ '</classname></ooclass>\n')
+
+ constructor = self.parser.find_constructor(obj_def, self.overrides)
+ if constructor:
+ self._fp.write(
+ '%s\n' % self.create_constructor_prototype(constructor))
+ for method in self.get_methods_for_object(obj_def):
+ self._fp.write(
+ '%s\n' % self.create_method_prototype(method, addlink=1))
+ self._fp.write('</classsynopsis>\n\n')
+
+ def write_hierarchy(self, obj_name, ancestry):
+ self._fp.write('<synopsis>')
+ indent = ''
+ for name, interfaces in ancestry:
+ self._fp.write(
+ '%s+-- <link linkend="%s">%s</link>' %
+ (indent, self.make_class_ref(name), self.pyname(name)))
+ if interfaces:
+ self._fp.write(' (implements ')
+ for i in range(len(interfaces)):
+ self._fp.write('<link linkend="%s">%s</link>' %
+ (self.make_class_ref(interfaces[i]),
+ self.pyname(interfaces[i])))
+ if i != len(interfaces) - 1:
+ self._fp.write(', ')
+ self._fp.write(')\n')
+ else:
+ self._fp.write('\n')
+ indent = indent + ' '
+ self._fp.write('</synopsis>\n\n')
+
+ def write_params(self, params, ret, func_doc):
+ if not params and (not ret or ret == 'none'):
+ return
+ self._fp.write(' <variablelist>\n')
+ for type, name, dflt, null in params:
+ if func_doc:
+ descr = func_doc.get_param_description(name).strip()
+ else:
+ descr = 'a ' + type
+ self._fp.write(VARIABLE_TEMPLATE % dict(
+ parameter=name,
+ description=self.reformat_text(descr, singleline=1)))
+ if ret and ret != 'none':
+ if func_doc and func_doc.ret:
+ descr = func_doc.ret.strip()
+ else:
+ descr = 'a ' + ret
+ self._fp.write(VARIABLE_TEMPLATE % dict(
+ parameter='Returns',
+ description=self.reformat_text(descr, singleline=1)))
+ self._fp.write(' </variablelist>\n')
+
+ def write_constructor(self, func_def, func_doc):
+ prototype = self.create_constructor_prototype(func_def)
+ self._fp.write('<programlisting>%s</programlisting>\n' % prototype)
+ self.write_params(func_def.params, func_def.ret, func_doc)
+
+ if func_doc and func_doc.description:
+ self._fp.write(self.reformat_text(func_doc.description))
+ self._fp.write('\n\n\n')
+
+ def write_method(self, meth_def, func_doc):
+ self._fp.write(' <refsect2 id="%s">\n' % (
+ self.make_method_ref(meth_def), ))
+ self._fp.write(' <title>%s.%s</title>\n\n' % (
+ self.pyname(meth_def.of_object),
+ meth_def.name))
+ prototype = self.create_method_prototype(meth_def)
+ self._fp.write('<programlisting>%s</programlisting>\n' % prototype)
+ self.write_params(meth_def.params, meth_def.ret, func_doc)
+ if func_doc and func_doc.description:
+ self._fp.write(self.reformat_text(func_doc.description))
+ self._fp.write(' </refsect2>\n\n\n')
+
+ def output_toc(self, files, fp=sys.stdout):
+ self._fp.write(DOCBOOK_HEADER)
+
+ #self._fp.write('<reference id="class-reference">\n')
+ #self._fp.write(' <title>Class Documentation</title>\n')
+ #for filename, obj_def in files:
+ # self._fp.write('&' +
+ # obj_def.c_name.translate(self._transtable) + ';\n')
+ #self._fp.write('</reference>\n')
+
+ self._fp.write('<reference id="class-reference" '
+ 'xmlns:xi="http://www.w3.org/2001/XInclude">\n')
+ self._fp.write(' <title>Class Reference</title>\n')
+ for filename in sorted(files):
+ self._fp.write(' <xi:include href="%s"/>\n' % filename)
+ self._fp.write('</reference>\n')
+
+
+def main(args):
+ try:
+ opts, args = getopt.getopt(args[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')
+ return 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')
+ return 1
+
+ d = DocbookDocWriter()
+ d.add_sourcedirs(source_dirs)
+ d.add_docs(defs_file, overrides_file, 'gio')
+ d.output_docs(output_prefix)
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/codegen/h2def.py b/codegen/h2def.py
new file mode 100755
index 0000000..17617fa
--- /dev/null
+++ b/codegen/h2def.py
@@ -0,0 +1,631 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# 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://mail.gnome.org/archives/gtk-devel-list/2000-January/msg00070.html
+# Updated to be PEP-8 compatible and refactored to use OOP
+#
+# Scan the given public .h files of a GTK module (or module using
+# GTK object conventions) and generates a set of scheme defs.
+#
+# h2def searches through a header file looking for function prototypes and
+# generates a scheme style defenition for each prototype.
+# Basically the operation of h2def is:
+#
+# - read each .h file into a buffer which is scrubbed of extraneous data
+# - find all object defenitions:
+# - find all structures that may represent a GtkObject
+# - find all structures that might represent a class
+# - find all structures that may represent a GtkObject subclass
+# - find all structures that might represent a class/Iface inherited from
+# GTypeInterface
+# - find all enum defenitions
+# - write out the defs
+#
+# The command line options are:
+#
+# -s --separate Create separate files for objects and function/method defs
+# using the given name as the base name (optional). If this
+# is not specified the combined object and function defs
+# will be output to sys.stdout.
+# -f --defsfilter Extract defs from the given file to filter the output defs
+# that is don't output defs that are defined in the
+# defsfile. More than one deffile may be specified.
+# -m --modulename The prefix to be stripped from the front of function names
+# for the given module
+# -n --namespace The module or namespace name to be used, for example
+# WebKit where h2def is unable to detect the module name
+# automatically. it also sets the gtype-id prefix.
+# --onlyenums Only produce defs for enums and flags
+# --onlyobjdefs Only produce defs for objects
+# -v Verbose output
+#
+# Examples:
+#
+# python h2def.py /usr/local/include/pango-1.0/pango/*.h >/tmp/pango.defs
+#
+# - Outputs all defs for the pango module.
+#
+# python h2def.py -m gdk -s /tmp/gdk-2.10 \
+# -f /usr/tmp/pygtk/gtk/gdk-base.defs \
+# /usr/local/include/gtk-2.0/gdk/*.h \
+# /usr/local/include/gtk-2.0/gdk-pixbuf/*.h
+#
+# - Outputs the gdk module defs that are not contained in the defs file
+# /usr/tmp/pygtk/gtk/gdk-base.defs. Two output files are created:
+# /tmp/gdk-2.10-types.defs and /tmp/gdk-2.10.defs.
+#
+# python h2def.py -n WebKit /usr/incude/webkit-1.0/webkit/*.h \
+# >/tmp/webkit.defs
+#
+# - Outputs all the defs for webkit module, setting the module name to WebKit
+# and the gtype-id prefix to WEBKIT_ which can't be detected automatically.
+#
+
+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, namespace=None):
+ """create a typecode (eg. GTK_TYPE_WIDGET) from a typename"""
+ if namespace:
+ return string.replace(string.upper(namespace) + "_" + to_upper_str(typename[len(namespace):]), '_', '_TYPE_', 1)
+
+ return string.replace(to_upper_str(typename), '_', '_TYPE_', 1)
+
+
+# ------------------ Find object definitions -----------------
+# Strips the comments from buffer
+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, '')
+
+# Strips the dll API from buffer, for example WEBKIT_API
+def strip_dll_api(buf):
+ pat = re.compile("[A-Z]*_API ")
+ buf = pat.sub("", buf)
+ return buf
+
+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)
+
+ # filter out dll api
+ buf = strip_dll_api(buf)
+
+ maybeobjdefs = [] # contains all possible objects from file
+
+ # first find all structures that look like they may represent a GtkObject
+ pat = re.compile("struct\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(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(1)))
+ pos = m.end()
+
+ # now find all structures that look like they might represent a class:
+ pat = re.compile("struct\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(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\s+_(" + 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\s+_(" + 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)
+
+ # strip dll api macros
+ buf = strip_dll_api(buf)
+
+ # strip # directives
+ pat = re.compile(r"""^[#].*?$""", re.MULTILINE)
+ buf = pat.sub('', 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)
+
+ # dll api
+ buf = strip_dll_api(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 = re.sub(r'\s*\*\s*G_CONST_RETURN\s*\*\s*', '** ', buf)
+ buf = string.replace(buf, 'G_CONST_RETURN ', 'const-')
+ buf = string.replace(buf, 'const ', 'const-')
+
+ #strip GSEAL macros from the middle of function declarations:
+ pat = re.compile(r"""GSEAL""", re.VERBOSE)
+ buf = pat.sub('', buf)
+
+ 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, ns=None, verbose=False,
+ defsfilter=None):
+ if not fp:
+ fp = sys.stdout
+
+ self.fp = fp
+ self.prefix = prefix
+ self.namespace = ns
+ 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] = obj
+ for obj in filter.enums:
+ self._enums[obj.c_name] = obj
+
+ 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
+ if self.namespace:
+ module = self.namespace
+ name = cname[len(self.namespace):]
+ else:
+ 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, self.namespace) + '")\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 ((len(prefix) and prefix[-1] != '_') or 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
+ if self.namespace:
+ cname = klass[len(self.namespace):]
+ cmodule = self.namespace
+ else:
+ m = split_prefix_pat.match(klass)
+ cname = klass
+ cmodule = None
+ 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, self.namespace) + '")\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
+ namespace = None
+ defsfilter = None
+ opts, args = getopt.getopt(args[1:], 'vs:m:n:f:',
+ ['onlyenums', 'onlyobjdefs',
+ 'modulename=', 'namespace=',
+ '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 ('-n', '--namespace'):
+ namespace = 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, ns=namespace,
+ 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, ns=namespace,
+ verbose=verbose, defsfilter=defsfilter)
+
+ if onlyenums:
+ dw.write_enum_defs(enums)
+ elif onlyobjdefs:
+ dw.write_obj_defs(objdefs)
+ else:
+ dw.write_obj_defs(objdefs)
+ dw.write_enum_defs(enums)
+
+ for filename in args:
+ dw.write_def(filename)
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/codegen/mergedefs.py b/codegen/mergedefs.py
new file mode 100755
index 0000000..773e499
--- /dev/null
+++ b/codegen/mergedefs.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+
+import optparse
+
+import defsparser
+
+parser = optparse.OptionParser(
+ usage="usage: %prog [options] generated-defs old-defs")
+parser.add_option("-p", "--merge-parameters",
+ help="Merge changes in function/methods parameter lists",
+ action="store_true", dest="parmerge", default=False)
+(options, args) = parser.parse_args()
+
+if len(args) != 2:
+ parser.error("wrong number of arguments")
+
+newp = defsparser.DefsParser(args[0])
+oldp = defsparser.DefsParser(args[1])
+
+newp.startParsing()
+oldp.startParsing()
+
+newp.merge(oldp, options.parmerge)
+
+newp.write_defs()
diff --git a/codegen/missingdefs.py b/codegen/missingdefs.py
new file mode 100755
index 0000000..f0017e7
--- /dev/null
+++ b/codegen/missingdefs.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+
+import sys
+import defsparser
+
+if len(sys.argv) < 3:
+ sys.stderr.write("Usage: missingdefs.py generated-defs old-defs\n")
+ sys.exit(1)
+
+newp = defsparser.DefsParser(sys.argv[1])
+oldp = defsparser.DefsParser(sys.argv[2])
+
+newp.startParsing()
+oldp.startParsing()
+
+newp.printMissing(oldp)
diff --git a/codegen/mkskel.py b/codegen/mkskel.py
new file mode 100755
index 0000000..61f520b
--- /dev/null
+++ b/codegen/mkskel.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+
+import sys, os, getopt
+
+module_init_template = \
+'/* -*- Mode: C; c-basic-offset: 4 -*- */\n' + \
+'#ifdef HAVE_CONFIG_H\n' + \
+'# include "config.h"\n' + \
+'#endif\n' + \
+'#include <Python.h>\n' + \
+'#include <pygtk.h>\n' + \
+'\n' + \
+'/* include any extra headers needed here */\n' + \
+'\n' + \
+'void %(prefix)s_register_classes(PyObject *d);\n' + \
+'extern PyMethodDef %(prefix)s_functions[];\n' + \
+'\n' + \
+'DL_EXPORT(void)\n' + \
+'init%(module)s(void)\n' + \
+'{\n' + \
+' PyObject *m, *d;\n' + \
+'\n' + \
+' /* perform any initialisation required by the library here */\n' + \
+'\n' + \
+' m = Py_InitModule("%(module)s", %(prefix)s_functions);\n' + \
+' d = PyModule_GetDict(m);\n' + \
+'\n' + \
+' init_pygtk();\n' + \
+'\n' + \
+' %(prefix)s_register_classes(d);\n' + \
+'\n' + \
+' /* add anything else to the module dictionary (such as constants) */\n' +\
+'\n' + \
+' if (PyErr_Occurred())\n' + \
+' Py_FatalError("could not initialise module %(module)s");\n' + \
+'}\n'
+
+override_template = \
+'/* -*- Mode: C; c-basic-offset: 4 -*- */\n' + \
+'%%%%\n' + \
+'headers\n' + \
+'/* include any required headers here */\n' + \
+'%%%%\n' + \
+'init\n' + \
+' /* include any code here that needs to be executed before the\n' + \
+' * extension classes get initialised */\n' + \
+'%%%%\n' + \
+'\n' + \
+'/* you should add appropriate ignore, ignore-glob and\n' + \
+' * override sections here */\n'
+
+def open_with_backup(file):
+ if os.path.exists(file):
+ try:
+ os.rename(file, file+'~')
+ except OSError:
+ # fail silently if we can't make a backup
+ pass
+ return open(file, 'w')
+
+def write_skels(fileprefix, prefix, module):
+ fp = open_with_backup(fileprefix+'module.c')
+ fp.write(module_init_template % { 'prefix': prefix, 'module': module })
+ fp.close()
+ fp = open_with_backup(fileprefix+'.override')
+ fp.write(override_template % { 'prefix': prefix, 'module': module })
+ fp.close()
+
+if __name__ == '__main__':
+ opts, args = getopt.getopt(sys.argv[1:], 'f:p:m:h',
+ ['file-prefix=', 'prefix=', 'module=', 'help'])
+ fileprefix = None
+ prefix = None
+ module = None
+ for opt, arg in opts:
+ if opt in ('-f', '--file-prefix'):
+ fileprefix = arg
+ elif opt in ('-p', '--prefix'):
+ prefix = arg
+ elif opt in ('-m', '--module'):
+ module = arg
+ elif opt in ('-h', '--help'):
+ print 'usage: mkskel.py -f fileprefix -p prefix -m module'
+ sys.exit(0)
+ if not fileprefix or not prefix or not module:
+ print 'usage: mkskel.py -f fileprefix -p prefix -m module'
+ sys.exit(1)
+ write_skels(fileprefix, prefix, module)
diff --git a/codegen/override.py b/codegen/override.py
new file mode 100644
index 0000000..bba5e42
--- /dev/null
+++ b/codegen/override.py
@@ -0,0 +1,285 @@
+# -*- 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 python_type as c_name [for arg_type]
+# Last ('for') clause is optional. If present, the type will be
+# imported only if given 'arg_type' is registered.
+import_pat = re.compile(r'\s*import\s+(\S+)\.([^\s.]+)\s+as\s+(\S+)(\s+for\s+(\S+))?')
+
+class Overrides:
+ def __init__(self, filename=None):
+ 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.dynamicnamespace = False
+ if filename:
+ self.handle_file(filename)
+
+ def handle_file(self, filename):
+ oldpath = os.getcwd()
+
+ fp = open(filename, 'r')
+ dirname = os.path.dirname(os.path.abspath(filename))
+
+ if dirname != oldpath:
+ os.chdir(dirname)
+
+ # read all the components of the file ...
+ bufs = []
+ startline = 1
+ lines = []
+ line = fp.readline()
+ linenum = 1
+ while line:
+ if line == '%%\n' or line == '%%':
+ if lines:
+ bufs.append((string.join(lines, ''), startline))
+ startline = linenum + 1
+ lines = []
+ else:
+ lines.append(line)
+ line = fp.readline()
+ linenum = linenum + 1
+ if lines:
+ bufs.append((string.join(lines, ''), startline))
+ if not bufs: return
+
+ for buf, startline in bufs:
+ self.__parse_override(buf, startline, filename)
+
+ os.chdir(oldpath)
+
+ def __parse_override(self, buffer, startline, filename):
+ pos = string.find(buffer, '\n')
+ if pos >= 0:
+ line = buffer[:pos]
+ rest = buffer[pos+1:]
+ else:
+ line = buffer ; rest = ''
+ words = string.split(line)
+ command = words[0]
+ if (command == 'ignore' or
+ command == 'ignore-' + sys.platform):
+ "ignore/ignore-platform [functions..]"
+ for func in words[1:]:
+ self.ignores[func] = 1
+ for func in string.split(rest):
+ self.ignores[func] = 1
+ elif (command == 'ignore-glob' or
+ command == 'ignore-glob-' + sys.platform):
+ "ignore-glob/ignore-glob-platform [globs..]"
+ for func in words[1:]:
+ self.glob_ignores.append(func)
+ for func in string.split(rest):
+ self.glob_ignores.append(func)
+ elif (command == '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:
+ module, pyname, cname, conditional, importing_for = match.groups()
+ self.imports.append((module, pyname, cname, importing_for or None))
+ 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
+ elif command == 'options':
+ for option in words[1:]:
+ if option == 'dynamicnamespace':
+ self.dynamicnamespace = True
+
+ def is_ignored(self, name):
+ if self.ignores.has_key(name):
+ return 1
+ for glob in self.glob_ignores:
+ if fnmatch.fnmatchcase(name, glob):
+ return 1
+ return 0
+
+ def is_type_ignored(self, name):
+ return name in self.type_ignores
+
+ def is_overriden(self, name):
+ return self.overrides.has_key(name)
+
+ def is_already_included(self, name):
+ return self.overridden.has_key(name)
+
+ def override(self, name):
+ self.overridden[name] = 1
+ return self.overrides[name]
+
+ def define(self, klass, name):
+ self.overridden[class2cname(klass, name)] = 1
+ return self.defines[klass][name]
+
+ def function(self, name):
+ return self.functions[name]
+
+ def getstartline(self, name):
+ return self.startlines[name]
+
+ def wants_kwargs(self, name):
+ return self.kwargs.has_key(name)
+
+ def wants_noargs(self, name):
+ return self.noargs.has_key(name)
+
+ def wants_onearg(self, name):
+ return self.onearg.has_key(name)
+
+ def is_staticmethod(self, name):
+ return self.staticmethod.has_key(name)
+
+ def is_classmethod(self, name):
+ return self.classmethod.has_key(name)
+
+ def attr_is_overriden(self, attr):
+ return self.override_attrs.has_key(attr)
+
+ def attr_override(self, attr):
+ return self.override_attrs[attr]
+
+ def slot_is_overriden(self, slot):
+ return self.override_slots.has_key(slot)
+
+ def slot_override(self, slot):
+ return self.override_slots[slot]
+
+ def get_headers(self):
+ return self.headers
+
+ def get_body(self):
+ return self.body
+
+ def get_init(self):
+ return self.init
+
+ def get_imports(self):
+ return self.imports
+
+ def get_defines_for(self, klass):
+ return self.defines.get(klass, {})
+
+ def get_functions(self):
+ return self.functions
diff --git a/codegen/pygobject-codegen-2.0.in b/codegen/pygobject-codegen-2.0.in
new file mode 100644
index 0000000..c5c912e
--- /dev/null
+++ b/codegen/pygobject-codegen-2.0.in
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+prefix=@prefix@
+datarootdir=@datarootdir@
+datadir=@datadir@
+codegendir=${datadir}/pygobject/2.0/codegen
+
+PYTHONPATH=$codegendir
+export PYTHONPATH
+
+exec @PYTHON@ $codegendir/codegen.py "$@"
diff --git a/codegen/reversewrapper.py b/codegen/reversewrapper.py
new file mode 100644
index 0000000..b96e12e
--- /dev/null
+++ b/codegen/reversewrapper.py
@@ -0,0 +1,912 @@
+### -*- 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.check_exception_code = MemoryCodeSink()
+ self.cleanup_actions = []
+ self.pyargv_items = []
+ self.pyargv_optional_items = []
+ self.pyret_parse_items = [] # list of (format_spec, parameter)
+ self.code_sinks_stack = [self.body]
+
+ 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 push_code_sink(self, code_sink):
+ self.code_sinks_stack.insert(0, code_sink)
+
+ def pop_code_sink(self):
+ return self.code_sinks_stack.pop(0)
+
+
+ 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.code_sinks_stack[0]
+ 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.push_code_sink(code_sink)
+ try:
+ self.return_type.write_error_return()
+ finally:
+ self.pop_code_sink()
+
+ 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_XDECREF(py_retval);")
+ self.check_exception_code.flush_to(self.body)
+ self.write_code(None, 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_XDECREF(py_retval);")
+ self.check_exception_code.flush_to(self.body)
+ self.write_code(None, 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 self.pyret_parse_items == [("", "")]:
+ ## special case when there are no return parameters
+ self.write_code(
+ code=None,
+ failure_expression='py_retval != Py_None',
+ failure_exception=('PyErr_SetString(PyExc_TypeError, '
+ '"virtual method should return None");'))
+ else:
+ 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
+ params = ["py_retval",
+ '"%s"' % "".join([format for format, param in self.pyret_parse_items])]
+ params.extend([param for format, param in self.pyret_parse_items if param])
+ self.write_code(code=None, failure_expression=(
+ '!PyArg_ParseTuple(%s)' % (', '.join(params),)))
+
+ 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):
+
+ supports_optional = False
+
+ 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)
+ elif self.props.get('nullok', False):
+ self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+ self.wrapper.write_code(code=("if (%s)\n"
+ " py_%s = PyString_FromString(%s);\n"
+ "else {\n"
+ " Py_INCREF(Py_None);\n"
+ " py_%s = Py_None;\n"
+ "}\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)
+ else:
+ 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_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 self.props.get('c_type', 'char *').replace('const-', 'const ')
+ #return "char *"
+
+ def write_decl(self):
+ self.wrapper.add_declaration("%s retval;" % self.get_c_type())
+ #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*', 'const-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.add_pyret_parse_item("", "", prepend=True)
+
+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):
+
+ supports_optional = True
+
+ def get_c_type(self):
+ return self.props.get('c_type', 'GObject *')
+
+ def write_decl(self):
+ if not self.props.get('optional'):
+ self.wrapper.add_declaration("%s retval;" % self.get_c_type())
+ else:
+ self.wrapper.add_declaration("%s retval = NULL;" % self.get_c_type())
+
+ def write_error_return(self):
+ self.wrapper.write_code("return NULL;")
+
+ def write_conversion(self):
+ if not self.props.get('optional'):
+ 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);")
+ else:
+ self.wrapper.write_code(
+ code=None,
+ failure_expression="py_retval != Py_None && !PyObject_TypeCheck(py_retval, &PyGObject_Type)",
+ failure_exception='PyErr_SetString(PyExc_TypeError, "retval should be None or a GObject");')
+ self.wrapper.write_code("if (py_retval != Py_None) {\n"
+ " retval = (%s) pygobject_get(py_retval);\n"
+ " g_object_ref((GObject *) retval);\n"
+ "}\n"
+ % self.get_c_type())
+
+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 argtypes.ArgTypeConfigurationError(
+ "cannot use int* parameter without direction")
+ if props["direction"] not in ("out", "inout"):
+ raise argtypes.ArgTypeConfigurationError(
+ "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 GtkTreePathReturn(ReturnType):
+ def get_c_type(self):
+ return self.props.get('c_type', 'GtkTreePath *')
+ def write_decl(self):
+ self.wrapper.add_declaration("GtkTreePath * retval;")
+ def write_error_return(self):
+ self.wrapper.write_code("return NULL;")
+ def write_conversion(self):
+ self.wrapper.write_code(
+ "retval = pygtk_tree_path_from_pyobject(py_retval);\n",
+ failure_expression=('!retval'),
+ failure_exception=(
+ 'PyErr_SetString(PyExc_TypeError, "retval should be a GtkTreePath");'))
+
+argtypes.matcher.register_reverse_ret("GtkTreePath*", GtkTreePathReturn)
+
+
+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 argtypes.ArgTypeConfigurationError(
+ "cannot use double* parameter without direction")
+ if props["direction"] not in ("out", ): # inout not yet implemented
+ raise argtypes.ArgTypeConfigurationError(
+ "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.add_pyret_parse_item("d", "&retval", prepend=True)
+
+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(code = None,
+ failure_expression=("!pyg_boxed_check(py_retval, %s)" %
+ (self.props['typecode'],)),
+ failure_exception=(
+ '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 GdkRegionPtrReturn(GBoxedReturn):
+ def write_error_return(self):
+ self.wrapper.write_code("return gdk_region_new();")
+ def write_conversion(self):
+ self.props['typecode'] = 'PYGDK_TYPE_REGION'
+ self.props['typename'] = 'GdkRegion'
+ super(GdkRegionPtrReturn, self).write_conversion()
+
+argtypes.matcher.register_reverse_ret("GdkRegion*", GdkRegionPtrReturn)
+
+
+class PangoFontDescriptionReturn(GBoxedReturn):
+ def write_error_return(self):
+ self.wrapper.write_code("return pango_font_description_new();")
+ def write_conversion(self):
+ self.props['typecode'] = 'PANGO_TYPE_FONT_DESCRIPTION'
+ self.props['typename'] = 'PangoFontDescription'
+ super(PangoFontDescriptionReturn, self).write_conversion()
+
+argtypes.matcher.register_reverse_ret("PangoFontDescription*",
+ PangoFontDescriptionReturn)
+
+
+class PangoFontMetricsReturn(GBoxedReturn):
+ def write_error_return(self):
+ self.wrapper.write_code("return pango_font_metrics_new();")
+ def write_conversion(self):
+ self.props['typecode'] = 'PANGO_TYPE_FONT_METRICS'
+ self.props['typename'] = 'PangoFontMetrics'
+ super(PangoFontMetricsReturn, self).write_conversion()
+
+argtypes.matcher.register_reverse_ret("PangoFontMetrics*",
+ PangoFontMetricsReturn)
+
+
+class PangoLanguageReturn(GBoxedReturn):
+ def write_error_return(self):
+ self.wrapper.write_code("return pango_language_from_string(\"\");")
+ def write_conversion(self):
+ self.props['typecode'] = 'PANGO_TYPE_LANGUAGE'
+ self.props['typename'] = 'PangoLanguage'
+ super(PangoLanguageReturn, self).write_conversion()
+
+argtypes.matcher.register_reverse_ret("PangoLanguage*", PangoLanguageReturn)
+
+
+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 GErrorParam(Parameter):
+ def get_c_type(self):
+ return self.props.get('c_type').replace('**', ' **')
+ def convert_c2py(self):
+ self.wrapper.write_code(code=None,
+ failure_expression=("pyg_gerror_exception_check(%s)" % self.name),
+ code_sink=self.wrapper.check_exception_code)
+
+argtypes.matcher.register_reverse('GError**', GErrorParam)
+
+
+class PyGObjectMethodParam(Parameter):
+ def __init__(self, wrapper, name, method_name, **props):
+ Parameter.__init__(self, wrapper, name, **props)
+ self.method_name = method_name
+
+ def get_c_type(self):
+ return self.props.get('c_type', 'GObject *')
+
+ def convert_c2py(self):
+ self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
+ self.wrapper.write_code(code=("py_%s = pygobject_new((GObject *) %s);" %
+ (self.name, self.name)),
+ cleanup=("Py_DECREF(py_%s);" % self.name),
+ failure_expression=("!py_%s" % self.name))
+ self.wrapper.set_call_target("py_%s" % self.name, self.method_name)
+
+
+class CallbackInUserDataParam(Parameter):
+ def __init__(self, wrapper, name, free_it, **props):
+ Parameter.__init__(self, wrapper, name, **props)
+ self.free_it = free_it
+
+ def get_c_type(self):
+ return "gpointer"
+
+ def convert_c2py(self):
+ self.wrapper.add_declaration("PyObject **_user_data;")
+ cleanup = self.free_it and ("g_free(%s);" % self.name) or None
+ self.wrapper.write_code(code=("_real_user_data = (PyObject **) %s;"
+ % self.name),
+ cleanup=cleanup)
+
+ self.wrapper.add_declaration("PyObject *py_func;")
+ cleanup = self.free_it and "Py_DECREF(py_func);" or None
+ self.wrapper.write_code(code="py_func = _user_data[0];",
+ cleanup=cleanup)
+ self.wrapper.set_call_target("py_func")
+
+ self.wrapper.add_declaration("PyObject *py_user_data;")
+ cleanup = self.free_it and "Py_XDECREF(py_user_data);" or None
+ self.wrapper.write_code(code="py_user_data = _user_data[1];",
+ cleanup=cleanup)
+ self.wrapper.add_pyargv_item("py_user_data", optional=True)
+
+def _test():
+ import sys
+
+ if 1:
+ wrapper = ReverseWrapper("this_is_the_c_function_name", is_static=True)
+ wrapper.set_return_type(StringReturn(wrapper))
+ wrapper.add_parameter(PyGObjectMethodParam(wrapper, "self", method_name="do_xxx"))
+ wrapper.add_parameter(StringParam(wrapper, "param2", optional=True))
+ wrapper.add_parameter(GObjectParam(wrapper, "param3"))
+ #wrapper.add_parameter(InoutIntParam(wrapper, "param4"))
+ wrapper.generate(FileCodeSink(sys.stderr))
+
+ if 0:
+ wrapper = ReverseWrapper("this_a_callback_wrapper")
+ wrapper.set_return_type(VoidReturn(wrapper))
+ wrapper.add_parameter(StringParam(wrapper, "param1", optional=False))
+ wrapper.add_parameter(GObjectParam(wrapper, "param2"))
+ wrapper.add_parameter(CallbackInUserDataParam(wrapper, "data", free_it=True))
+ wrapper.generate(FileCodeSink(sys.stderr))
+
+if __name__ == '__main__':
+ _test()
diff --git a/codegen/scanvirtuals.py b/codegen/scanvirtuals.py
new file mode 100755
index 0000000..c108737
--- /dev/null
+++ b/codegen/scanvirtuals.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+import re
+import sys
+
+
+def main():
+ rx = re.compile(r'^\s*([\w\s\*]+)\(\s*\*\s*(\w+)\s*\)\s*\(([^()]*)\);',
+ re.DOTALL|re.MULTILINE)
+ for f in sys.argv[1:]:
+ #print ";; From", f
+ buf = file(f).read()
+ for m in rx.findall(buf):
+ return_type = m[0].strip()
+ if 'typedef' in return_type:
+ continue
+ if return_type == 'void':
+ return_type = 'none'
+ return_type = return_type.replace(' ', '')
+ virtual_name = m[1]
+ if 'reserved' in virtual_name:
+ continue
+ params = []
+ if not m[2]:
+ print >> sys.stderr, repr(m)
+ continue
+ for param in map(str.strip, m[2].split(',')):
+ if '*' in param:
+ tokens = param.split('*')
+ ptype = tokens[0].strip() + '*'*(len(tokens) - 1)
+ pname = tokens[-1].strip()
+ else:
+ if param == 'void':
+ continue
+ ptype, pname = map(str.strip, param.split())
+ ptype = ptype.replace('const ', 'const-')
+ while '[]' in pname:
+ pname = pname.replace('[]', '')
+ ptype += '[]'
+ params.append((ptype, pname))
+ if not params:
+ continue
+ objname = params[0][0].replace('*', '')
+ print '(define-virtual', virtual_name
+ print ' (of-object "%s")' % objname
+ print ' (return-type "%s")' % return_type
+ if len(params) > 1:
+ print ' (parameters'
+ for param in params[1:]:
+ print ' \'("%s" "%s")' % param
+ print ' )'
+ print ')'
+
+if __name__ == '__main__':
+ main()
diff --git a/codegen/scmexpr.py b/codegen/scmexpr.py
new file mode 100755
index 0000000..02f2e4b
--- /dev/null
+++ b/codegen/scmexpr.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+from __future__ import generators
+
+import string
+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`