2
# -*- Mode: Python; py-indent-offset: 4 -*-
3
# Search through a header file looking for function prototypes.
4
# For each prototype, generate a scheme style definition.
6
# Toby D. Reeves <toby@max.rl.plh.af.mil>
8
# Modified by James Henstridge <james@daa.com.au> to output stuff in
9
# Havoc's new defs format. Info on this format can be seen at:
10
# http://www.gnome.org/mailing-lists/archives/gtk-devel-list/2000-January/0085.shtml
13
import string, sys, re, types
15
# ------------------ Create typecodes from typenames ---------
17
_upperstr_pat1 = re.compile(r'([^A-Z])([A-Z])')
18
_upperstr_pat2 = re.compile(r'([A-Z][A-Z])([A-Z][0-9a-z])')
19
_upperstr_pat3 = re.compile(r'^([A-Z])([A-Z])')
21
def to_upper_str(name):
22
"""Converts a typename to the equivalent upercase and underscores
23
name. This is used to form the type conversion macros and enum/flag
25
name = _upperstr_pat1.sub(r'\1_\2', name)
26
name = _upperstr_pat2.sub(r'\1_\2', name)
27
name = _upperstr_pat3.sub(r'\1_\2', name, count=1)
28
return string.upper(name)
30
def typecode(typename):
31
"""create a typecode (eg. GTK_TYPE_WIDGET) from a typename"""
32
return string.replace(to_upper_str(typename), '_', '_TYPE_', 1)
35
# ------------------ Find object definitions -----------------
37
def strip_comments(buf):
41
pos = string.find(buf, '/*', lastpos)
43
parts.append(buf[lastpos:pos])
44
pos = string.find(buf, '*/', pos)
50
parts.append(buf[lastpos:])
52
return string.join(parts, '')
54
obj_name_pat = "[A-Z][a-z]*[A-Z][A-Za-z0-9]*"
56
split_prefix_pat = re.compile('([A-Z]+[a-z]*)([A-Za-z0-9]+)')
58
def find_obj_defs(buf, objdefs=[]):
60
Try to find object definitions in header files.
63
# filter out comments from buffer.
64
buf = strip_comments(buf)
66
maybeobjdefs = [] # contains all possible objects from file
68
# first find all structures that look like they may represent a GtkObject
69
pat = re.compile("struct _(" + obj_name_pat + ")\s*{\s*" +
70
"(" + obj_name_pat + ")\s+", re.MULTILINE)
73
m = pat.search(buf, pos)
75
maybeobjdefs.append((m.group(1), m.group(2)))
78
# handle typedef struct { ... } style struct defs.
79
pat = re.compile("typedef struct\s+[_\w]*\s*{\s*" +
80
"(" + obj_name_pat + ")\s+[^}]*}\s*" +
81
"(" + obj_name_pat + ")\s*;", re.MULTILINE)
84
m = pat.search(buf, pos)
86
maybeobjdefs.append((m.group(2), m.group(2)))
89
# now find all structures that look like they might represent a class:
90
pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" +
91
"(" + obj_name_pat + ")Class\s+", re.MULTILINE)
94
m = pat.search(buf, pos)
96
t = (m.group(1), m.group(2))
97
# if we find an object structure together with a corresponding
98
# class structure, then we have probably found a GtkObject subclass.
103
pat = re.compile("typedef struct\s+[_\w]*\s*{\s*" +
104
"(" + obj_name_pat + ")Class\s+[^}]*}\s*" +
105
"(" + obj_name_pat + ")Class\s*;", re.MULTILINE)
107
while pos < len(buf):
108
m = pat.search(buf, pos)
110
t = (m.group(2), m.group(1))
111
# if we find an object structure together with a corresponding
112
# class structure, then we have probably found a GtkObject subclass.
113
if t in maybeobjdefs:
117
# now find all structures that look like they might represent a class inherited from GTypeInterface:
118
pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" +
119
"GTypeInterface\s+", re.MULTILINE)
121
while pos < len(buf):
122
m = pat.search(buf, pos)
125
t2 = (m.group(1)+'Class', 'GTypeInterface')
126
# if we find an object structure together with a corresponding
127
# class structure, then we have probably found a GtkObject subclass.
128
if t2 in maybeobjdefs:
132
# now find all structures that look like they might represent an Iface inherited from GTypeInterface:
133
pat = re.compile("struct _(" + obj_name_pat + ")Iface\s*{\s*" +
134
"GTypeInterface\s+", re.MULTILINE)
136
while pos < len(buf):
137
m = pat.search(buf, pos)
140
t2 = (m.group(1)+'Iface', 'GTypeInterface')
141
# if we find an object structure together with a corresponding
142
# class structure, then we have probably found a GtkObject subclass.
143
if t2 in maybeobjdefs:
147
def sort_obj_defs(objdefs):
148
objdefs.sort() # not strictly needed, but looks nice
150
while pos < len(objdefs):
151
klass,parent = objdefs[pos]
152
for i in range(pos+1, len(objdefs)):
153
# parent below subclass ... reorder
154
if objdefs[i][0] == parent:
155
objdefs.insert(i+1, objdefs[pos])
162
def write_obj_defs(objdefs, output):
163
if type(output)==types.StringType:
165
elif type(output)==types.FileType:
170
fp.write(';; -*- scheme -*-\n')
171
fp.write('; object definitions ...\n')
173
for klass, parent in objdefs:
174
m = split_prefix_pat.match(klass)
181
fp.write('(define-object ' + cname + '\n')
183
fp.write(' (in-module "' + cmodule + '")\n')
185
fp.write(' (parent "' + parent + '")\n')
186
fp.write(' (c-name "' + klass + '")\n')
187
fp.write(' (gtype-id "' + typecode(klass) + '")\n')
188
# should do something about accessible fields
191
# ------------------ Find enum definitions -----------------
193
def find_enum_defs(buf, enums=[]):
196
buf = strip_comments(buf)
198
buf = re.sub('\n', ' ', buf)
200
enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)')
201
splitter = re.compile(r'\s*,\s', re.MULTILINE)
203
while pos < len(buf):
204
m = enum_pat.search(buf, pos)
209
isflags = string.find(vals, '<<') >= 0
211
for val in splitter.split(vals):
212
if not string.strip(val): continue
213
entries.append(string.split(val)[0])
214
if name != 'GdkCursorType':
215
enums.append((name, isflags, entries))
219
def write_enum_defs(enums, output=None):
220
if type(output)==types.StringType:
222
elif type(output)==types.FileType:
227
fp.write(';; Enumerations and flags ...\n\n')
228
trans = string.maketrans(string.uppercase + '_', string.lowercase + '-')
229
for cname, isflags, entries in enums:
232
m = split_prefix_pat.match(cname)
237
fp.write('(define-flags ' + name + '\n')
239
fp.write('(define-enum ' + name + '\n')
241
fp.write(' (in-module "' + module + '")\n')
242
fp.write(' (c-name "' + cname + '")\n')
243
fp.write(' (gtype-id "' + typecode(cname) + '")\n')
246
# shorten prefix til we get a match ...
247
# and handle GDK_FONT_FONT, GDK_FONT_FONTSET case
248
while ent[:len(prefix)] != prefix or len(prefix) >= len(ent):
250
prefix_len = len(prefix)
251
fp.write(' (values\n')
253
fp.write(' \'("%s" "%s")\n' %
254
(string.translate(ent[prefix_len:], trans), ent))
258
# ------------------ Find function definitions -----------------
262
Ideally would make buf have a single prototype on each line.
263
Actually just cuts out a good deal of junk, but leaves lines
264
where a regex can figure prototypes out.
267
buf = strip_comments(buf)
269
# compact continued lines
270
pat = re.compile(r"""\\\n""", re.MULTILINE)
273
# Preprocess directives
274
pat = re.compile(r"""^[#].*?$""", re.MULTILINE)
277
#typedefs, stucts, and enums
278
pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""", re.MULTILINE)
282
pat = re.compile(r"""G_BEGIN_DECLS|BEGIN_LIBGTOP_DECLS""", re.MULTILINE)
286
pat = re.compile(r"""^\s*(extern)\s+\"C\"\s+{""", re.MULTILINE)
290
pat = re.compile(r"""\s+""", re.MULTILINE)
294
pat = re.compile(r""";\s*""", re.MULTILINE)
295
buf=pat.sub('\n',buf)
298
#associate *, &, and [] with type instead of variable
299
#pat=re.compile(r'\s+([*|&]+)\s*(\w+)')
300
pat=re.compile(r' \s* ([*|&]+) \s* (\w+)',re.VERBOSE)
301
buf=pat.sub(r'\1 \2', buf)
302
pat=re.compile(r'\s+ (\w+) \[ \s* \]',re.VERBOSE)
303
buf=pat.sub(r'[] \1', buf)
305
# make return types that are const work.
306
buf = string.replace(buf, 'G_CONST_RETURN ', 'const-')
307
buf = string.replace(buf, 'const ', 'const-')
311
proto_pat=re.compile(r"""
312
(?P<ret>(-|\w|\&|\*)+\s*) # return type
313
\s+ # skip whitespace
314
(?P<func>\w+)\s*[(] # match the function name until the opening (
315
\s*(?P<args>.*?)[)] # group the function arguments
316
""", re.IGNORECASE|re.VERBOSE)
318
arg_split_pat = re.compile("\s*,\s*")
320
def define_func(buf,fp, prefix):
322
buf=string.split(buf,'\n')
324
if len(p)==0: continue
328
sys.stderr.write('No match:|%s|\n'%p)
330
func = m.group('func')
335
args=arg_split_pat.split(args)
336
for i in range(len(args)):
337
spaces = string.count(args[i], ' ')
339
args[i] = string.replace(args[i], ' ', '-', spaces - 1)
341
write_func(fp, func, ret, args, prefix)
343
get_type_pat = re.compile(r'(const-)?([A-Za-z0-9]+)\*?\s+')
344
pointer_pat = re.compile('.*\*$')
345
func_new_pat = re.compile('(\w+)_new$')
347
def write_func(fp, name, ret, args, prefix):
349
# methods must have at least one argument
350
munged_name = string.replace(name, '_', '')
351
m = get_type_pat.match(args[0])
354
if munged_name[:len(obj)] == string.lower(obj):
355
regex = string.join(map(lambda x: x+'_?',string.lower(obj)),'')
356
mname = re.sub(regex, '', name, 1)
359
if mname[:l] == prefix and mname[l+1] == '_':
361
fp.write('(define-method ' + mname + '\n')
362
fp.write(' (of-object "' + obj + '")\n')
363
fp.write(' (c-name "' + name + '")\n')
365
fp.write(' (return-type "' + ret + '")\n')
367
fp.write(' (return-type "none")\n')
369
has_args = len(args) > 1
373
elif arg in ('void', 'void '):
376
fp.write(' (parameters\n')
379
tupleArg = tuple(string.split(arg))
380
if len(tupleArg) == 2:
381
fp.write(' \'("%s" "%s")\n' % tupleArg)
384
fp.write(' (varargs #t)\n')
389
if name[:l] == prefix and name[l] == '_':
395
# it is either a constructor or normal function
396
fp.write('(define-function ' + fname + '\n')
397
fp.write(' (c-name "' + name + '")\n')
399
# Hmmm... Let's asume that a constructor function name
400
# ends with '_new' and it returns a pointer.
401
m = func_new_pat.match(name)
402
if pointer_pat.match(ret) and m:
404
for s in m.group(1).split ('_'):
407
fp.write(' (is-constructor-of "' + cname + '")\n')
410
fp.write(' (return-type "' + ret + '")\n')
412
fp.write(' (return-type "none")\n')
414
has_args = len(args) > 0
418
elif arg in ('void', 'void '):
421
fp.write(' (parameters\n')
424
tupleArg = tuple(string.split(arg))
425
if len(tupleArg) == 2:
426
fp.write(' \'("%s" "%s")\n' % tupleArg)
429
fp.write(' (varargs #t)\n')
432
def write_def(input,output=None, prefix=None):
437
if type(output) == types.StringType:
438
fp = open(output,'w')
439
elif type(output) == types.FileType:
444
fp.write('\n;; From %s\n\n' % input)
445
buf = define_func(buf, fp, prefix)
448
# ------------------ Main function -----------------
459
opts, args = getopt.getopt(args[1:], 'vs:m:',
460
['onlyenums', 'onlyobjdefs',
461
'modulename=', 'separate='])
465
if o == '--onlyenums':
467
if o == '--onlyobjdefs':
469
if o in ('-s', '--separate'):
471
if o in ('-m', '--modulename'):
475
print 'Must specify at least one input file name'
478
# read all the object definitions in
481
for filename in args:
482
buf = open(filename).read()
483
find_obj_defs(buf, objdefs)
484
find_enum_defs(buf, enums)
485
objdefs = sort_obj_defs(objdefs)
488
types = file(separate + '-types.defs', 'w')
489
methods = file(separate + '.defs', 'w')
491
write_obj_defs(objdefs,types)
492
write_enum_defs(enums,types)
494
print "Wrote %s-types.defs" % separate
496
for filename in args:
497
write_def(filename,methods,prefix=modulename)
499
print "Wrote %s.defs" % separate
502
write_enum_defs(enums,None)
504
write_obj_defs(objdefs,None)
506
write_obj_defs(objdefs,None)
507
write_enum_defs(enums,None)
509
for filename in args:
510
write_def(filename,None,prefix=modulename)
512
if __name__ == '__main__':
513
sys.exit(main(sys.argv))