summaryrefslogtreecommitdiff
path: root/codegen/h2def.py
diff options
context:
space:
mode:
authorJames Henstridge <jamesh@src.gnome.org>2000-06-26 13:44:38 +0000
committerJames Henstridge <jamesh@src.gnome.org>2000-06-26 13:44:38 +0000
commit73611e4e7f46ec744195016e86afd291bc1fce4c (patch)
treec4871600e0d48b1c9d878a9999909dd3567e3f2c /codegen/h2def.py
parent274e99eec56e070b9721f0d2f5cc0a98d2e211ea (diff)
downloadpygtk-73611e4e7f46ec744195016e86afd291bc1fce4c.tar.gz
Commit codegen stuff to head from extension-class-branch
Diffstat (limited to 'codegen/h2def.py')
-rwxr-xr-xcodegen/h2def.py345
1 files changed, 345 insertions, 0 deletions
diff --git a/codegen/h2def.py b/codegen/h2def.py
new file mode 100755
index 00000000..95220427
--- /dev/null
+++ b/codegen/h2def.py
@@ -0,0 +1,345 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# Search through a header file looking for function prototypes.
+# For each prototype, generate a scheme style definition.
+# GPL'ed
+# Toby D. Reeves <toby@max.rl.plh.af.mil>
+
+# Modified by James Henstridge <james@daa.com.au> to output stuff in
+# Havoc's new defs format. Info on this format can be seen at:
+# http://www.gnome.org/mailing-lists/archives/gtk-devel-list/2000-January/0085.shtml
+
+
+import string, sys, re, types
+
+# ------------------ Find object definitions -----------------
+
+obj_name_pat = "[A-Z][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.
+ pat = re.compile(r"""/[*](.|\n)*?[*]/""", re.MULTILINE)
+ buf=pat.sub('',buf)
+
+ # first find all structures that look like they may represent a GtkObject
+ pat = re.compile("struct _(" + obj_name_pat + ")\s*{\s*" +
+ "(" + obj_name_pat + ")\s+", re.MULTILINE)
+ maybeobjdefs = [] # contains all possible objects from file
+ 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()
+
+ # now find all structures that look like they might represent a class:
+ pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" +
+ "(" + obj_name_pat + ")Class\s+", re.MULTILINE)
+ pos = 0
+ while pos < len(buf):
+ m = pat.search(buf, pos)
+ if not m: break
+ t = (m.group(1), m.group(2))
+ # if we find an object structure together with a corresponding
+ # class structure, then we have probably found a GtkObject subclass.
+ if t in maybeobjdefs:
+ objdefs.append(t)
+ pos = m.end()
+
+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
+
+def write_obj_defs(objdefs, output):
+ if type(output)==types.StringType:
+ fp=open(output,'w')
+ elif type(output)==types.FileType:
+ fp=output
+ else:
+ fp=sys.stdout
+
+ fp.write(';; -*- scheme -*-\n')
+ fp.write('; object definitions ...\n')
+
+ pat = re.compile('([A-Z][a-z]+)([A-Za-z0-9]+)')
+ for klass, parent in objdefs:
+ m = pat.match(klass)
+ cmodule = None
+ cname = klass
+ if m:
+ cmodule = m.group(1)
+ cname = m.group(2)
+ if parent:
+ m = pat.match(parent)
+ pmodule = None
+ pname = parent
+ if m:
+ pmodule = m.group(1)
+ pname = m.group(2)
+
+ fp.write('(object ' + cname + '\n')
+ if cmodule:
+ fp.write(' (in-module ' + cmodule + ')\n')
+ if parent:
+ fp.write(' (parent ' + pname)
+ if pmodule: fp.write(' (' + pmodule + ')')
+ fp.write(')\n')
+ fp.write(' (c-name ' + klass + ')\n')
+ # should do something about accessible fields
+ fp.write(')\n\n')
+
+# ------------------ Find enum definitions -----------------
+
+def find_enum_defs(buf, enums=[]):
+ # strip comments
+ # bulk comments
+ pat = re.compile(r"""/[*](.|\n)*?[*]/""", 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):
+ entries.append(string.split(val)[0])
+ enums.append((name, isflags, entries))
+
+ pos = m.end()
+
+def write_enum_defs(enums, output=None):
+ if type(output)==types.StringType:
+ fp=open(output,'w')
+ elif type(output)==types.FileType:
+ fp=output
+ else:
+ fp=sys.stdout
+
+ fp.write(';; Enumerations and flags ...\n\n')
+ pat = re.compile('([A-Z][a-z]+)([A-Za-z0-9]+)')
+ trans = string.maketrans(string.uppercase + '_', string.lowercase + '-')
+ for cname, isflags, entries in enums:
+ name = cname
+ module = None
+ m = pat.match(cname)
+ if m:
+ module = m.group(1)
+ name = m.group(2)
+ if isflags:
+ fp.write('(flags ' + name + '\n')
+ else:
+ fp.write('(enum ' + name + '\n')
+ if module:
+ fp.write(' (in-module ' + module + ')\n')
+ fp.write(' (c-name ' + cname + ')\n')
+ prefix = entries[0]
+ for ent in entries:
+ # shorten prefix til we get a match ...
+ while ent[:len(prefix)] != prefix:
+ prefix = prefix[:-1]
+ for ent in entries:
+ fp.write(' (value (name ' +
+ string.translate(ent[len(prefix):], trans) +
+ ') (c-name ' + ent + '))\n')
+ fp.write(')\n\n')
+
+# ------------------ Find function definitions -----------------
+
+#comment_pat = re.compile(r"""(/[*](.|\n)*?[*]/)|(^;.*$)""", re.MULTILINE)
+
+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
+ 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)
+
+ #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)
+
+ #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)
+
+ 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 (
+(?P<args>.*?)[)] # group the function arguments
+""", re.IGNORECASE|re.VERBOSE)
+#"""
+arg_split_pat = re.compile("\s*,\s*")
+
+def define_func(buf,fp):
+ buf=clean_func(buf)
+ buf=string.split(buf,'\n')
+ for p in buf:
+ if len(p)==0: continue
+ m=proto_pat.match(p)
+ if m==None:
+ if verbose:
+ sys.stderr.write('No match:|%s|\n'%p)
+ continue
+ func = m.group('func')
+ ret = m.group('ret')
+ ret = string.replace(ret, 'const ', 'const-')
+ args=m.group('args')
+ args=arg_split_pat.split(args,', ')
+
+ for i in range(len(args)):
+ args[i] = string.replace(args[i], 'const ', 'const-')
+
+ write_func(fp, func, ret, args)
+
+get_type_pat = re.compile(r'(const-)?([A-Za-z0-9]+)\*?\s+')
+get_mod_pat = re.compile('([A-Z][a-z]+)([A-Za-z0-9]+)')
+
+def write_func(fp, name, ret, args):
+ if len(args) >= 1:
+ # methods must have at least one argument
+ munged_name = string.replace(name, '_', '')
+ m = get_type_pat.match(args[0])
+ if m:
+ obj = m.group(2)
+ if munged_name[:len(obj)] == string.lower(obj):
+ regex = string.join(map(lambda x: x+'_?',string.lower(obj)),'')
+ mname = re.sub(regex, '', name)
+ fp.write('(method ' + mname + '\n')
+ m = get_mod_pat.match(obj)
+ if m:
+ fp.write(' (of-object ' + m.group(2) +
+ ' (' + m.group(1) + '))\n')
+ fp.write(' (c-name ' + name + ')\n')
+ if ret != 'void':
+ fp.write(' (return-type ' + ret + ')\n')
+ else:
+ fp.write(' (return-type none)\n')
+ for arg in args[1:]:
+ if arg == '...':
+ fp.write(' (varargs t)\n')
+ elif arg in ('void', 'void '):
+ pass
+ else:
+ fp.write(' (parameter (type-and-name ' + arg + '))\n')
+ fp.write(')\n\n')
+ return
+ # it is either a constructor or normal function
+ # FIXME: put in constructor check
+ fp.write('(function ' + name + '\n')
+ # do in-module thingee
+ fp.write(' (c-name ' + name + ')\n')
+ if ret != 'void':
+ fp.write(' (return-type ' + ret + ')\n')
+ else:
+ fp.write(' (return-type none)\n')
+ for arg in args:
+ if arg == '...':
+ fp.write(' (varargs t)\n')
+ elif arg == 'void':
+ pass
+ else:
+ fp.write(' (parameter (type-and-name ' + arg + '))\n')
+ fp.write(')\n\n')
+
+def write_def(input,output=None):
+ fp = open(input)
+ buf = fp.read()
+ fp.close()
+
+ if type(output) == types.StringType:
+ fp = open(output,'w')
+ elif type(output) == types.FileType:
+ fp = output
+ else:
+ fp = sys.stdout
+
+ fp.write('\n;; From %s\n\n' % input)
+ buf = define_func(buf, fp)
+ fp.write('\n')
+
+# ------------------ Glue code -----------------
+
+def make_gdk_defs():
+ """ This is intended to be run only by the package maintainer!!! """
+ p='/usr/local/src/gtk+-1.2.6/gdk/'
+ gdk= [
+ 'gdk.h',
+ 'gdkrgb.h',
+ #'gdktypes.h'
+ ]
+ fp=open('_gdk_func.defs','w')
+ for h in gdk:
+ write_def(p+h,fp)
+ fp.close()
+
+verbose=0
+if __name__ == '__main__':
+ import getopt
+
+ opts, args = getopt.getopt(sys.argv[1:], 'v')
+ for o, v in opts:
+ if o=='-v': verbose=1
+
+ if not args[0:1]:
+ print 'Must specify at least one input file name'
+ sys.exit(-1)
+
+ # read all the object definitions in
+ objdefs = []
+ enums = []
+ for filename in args:
+ buf = open(filename).read()
+ find_obj_defs(buf, objdefs)
+ if len(filename) > 11 and filename[-11:] == 'gtkobject.h':
+ objdefs.append(('GtkObject', None))
+ find_enum_defs(buf, enums)
+ objdefs = sort_obj_defs(objdefs)
+ write_obj_defs(objdefs,None)
+ write_enum_defs(enums,None)
+
+ for filename in args:
+ write_def(filename,None)