diff options
Diffstat (limited to 'codegen/defsgen.py')
-rw-r--r-- | codegen/defsgen.py | 656 |
1 files changed, 0 insertions, 656 deletions
diff --git a/codegen/defsgen.py b/codegen/defsgen.py deleted file mode 100644 index 69c6d684..00000000 --- a/codegen/defsgen.py +++ /dev/null @@ -1,656 +0,0 @@ -#!/usr/bin/env python -# -*- Mode: Python; py-indent-offset: 4 -*- -# -# Copyright (C) 2006 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 -# --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 -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): - """create a typecode (eg. GTK_TYPE_WIDGET) from a typename""" - return to_upper_str(typename).replace('_', '_TYPE_', 1) - -_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 - (re.compile(r"""G_BEGIN_DECLS|BEGIN_LIBGTOP_DECLS|G_END_DECLS""", - 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 enum definitions - (re.compile(r'^typedef enum\s+{[^}]*}[^;]*;\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'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), '') - ] - -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 - -# ------------------ 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)_(.*)$') - -class DefsWriter: - def __init__(self, defs, fp=None, prefix=None, verbose=False, - defsfiles=None, defines={}, genpropgetsets=False): - self.defs = defs - 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 - if cname in filter: - continue - parent_name = obj.parent_name - klassptr = klassptrs[parent_name] - typename = parent_name.lower()[1:] - module = None - m = split_prefix_pat.match(cname) - if m: - module = m.group(1) - name = m.group(2) - fp.write('(define-' + typename + ' ' + name + '\n') - if module: - fp.write(' (in-module "' + module + '")\n') - fp.write(' (c-name "' + cname + '")\n') - fp.write(' (gtype-id "' + typecode(cname) + '")\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') - return - - 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 - m = split_prefix_pat.match(cname) - if m: - cmodule = m.group(1) - name = m.group(2) - 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) + '")\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 self.objifacedefs.has_key(obj): - 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 - opts, args = getopt.getopt(args[1:], 'vs:m:f:D:L:l:', - ['onlyenums', 'onlyobjdefs', 'onlyvirtuals', - 'modulename=', 'separate=', - 'defsfile=', 'defines=', 'genpropgetsets', - 'libgobject-', 'modulelib=']) - 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 == '--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') - - defs = {} - for key in defkeys.split(): - defs[key] = [] - defs['funcs'] = {} - defs['virts'] = {} - - # read in all the object and function definitions - args.sort() - for filename in args: - buf = open(filename).read() - buf = clean_buffer(buf) - 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) - 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)) |