~ubuntu-branches/ubuntu/precise/gst0.10-python/precise

« back to all changes in this revision

Viewing changes to codegen/h2def.py

  • Committer: Bazaar Package Importer
  • Author(s): Loic Minier
  • Date: 2006-06-25 19:37:45 UTC
  • Revision ID: james.westby@ubuntu.com-20060625193745-9yeg0wq56r24n57x
Tags: upstream-0.10.4
ImportĀ upstreamĀ versionĀ 0.10.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
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.
 
5
# GPL'ed
 
6
# Toby D. Reeves <toby@max.rl.plh.af.mil>
 
7
 
 
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
 
11
 
 
12
 
 
13
import string, sys, re, types
 
14
 
 
15
# ------------------ Create typecodes from typenames ---------
 
16
 
 
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])')
 
20
 
 
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
 
24
    name variables"""
 
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)
 
29
 
 
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)
 
33
 
 
34
 
 
35
# ------------------ Find object definitions -----------------
 
36
 
 
37
def strip_comments(buf):
 
38
    parts = []
 
39
    lastpos = 0
 
40
    while 1:
 
41
        pos = string.find(buf, '/*', lastpos)
 
42
        if pos >= 0:
 
43
            parts.append(buf[lastpos:pos])
 
44
            pos = string.find(buf, '*/', pos)
 
45
            if pos >= 0:
 
46
                lastpos = pos + 2
 
47
            else:
 
48
                break
 
49
        else:
 
50
            parts.append(buf[lastpos:])
 
51
            break
 
52
    return string.join(parts, '')
 
53
 
 
54
obj_name_pat = "[A-Z][a-z]*[A-Z][A-Za-z0-9]*"
 
55
 
 
56
split_prefix_pat = re.compile('([A-Z]+[a-z]*)([A-Za-z0-9]+)')
 
57
 
 
58
def find_obj_defs(buf, objdefs=[]):
 
59
    """
 
60
    Try to find object definitions in header files.
 
61
    """
 
62
 
 
63
    # filter out comments from buffer.
 
64
    buf = strip_comments(buf)
 
65
 
 
66
    maybeobjdefs = []  # contains all possible objects from file
 
67
 
 
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)
 
71
    pos = 0
 
72
    while pos < len(buf):
 
73
        m = pat.search(buf, pos)
 
74
        if not m: break
 
75
        maybeobjdefs.append((m.group(1), m.group(2)))
 
76
        pos = m.end()
 
77
 
 
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)
 
82
    pos = 0
 
83
    while pos < len(buf):
 
84
        m = pat.search(buf, pos)
 
85
        if not m: break
 
86
        maybeobjdefs.append((m.group(2), m.group(2)))
 
87
        pos = m.end()
 
88
 
 
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)
 
92
    pos = 0
 
93
    while pos < len(buf):
 
94
        m = pat.search(buf, pos)
 
95
        if not m: break
 
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.
 
99
        if t in maybeobjdefs:
 
100
            objdefs.append(t)
 
101
        pos = m.end()
 
102
 
 
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)
 
106
    pos = 0
 
107
    while pos < len(buf):
 
108
        m = pat.search(buf, pos)
 
109
        if not m: break
 
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:
 
114
            objdefs.append(t)
 
115
        pos = m.end()
 
116
 
 
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)
 
120
    pos = 0
 
121
    while pos < len(buf):
 
122
        m = pat.search(buf, pos)
 
123
        if not m: break
 
124
        t = (m.group(1), '')
 
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:
 
129
            objdefs.append(t)
 
130
        pos = m.end()
 
131
 
 
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)
 
135
    pos = 0
 
136
    while pos < len(buf):
 
137
        m = pat.search(buf, pos)
 
138
        if not m: break
 
139
        t = (m.group(1), '')
 
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:
 
144
            objdefs.append(t)
 
145
        pos = m.end()
 
146
 
 
147
def sort_obj_defs(objdefs):
 
148
    objdefs.sort()  # not strictly needed, but looks nice
 
149
    pos = 0
 
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])
 
156
                del objdefs[pos]
 
157
                break
 
158
        else:
 
159
            pos = pos + 1
 
160
    return objdefs
 
161
 
 
162
def write_obj_defs(objdefs, output):
 
163
    if type(output)==types.StringType:
 
164
        fp=open(output,'w')
 
165
    elif type(output)==types.FileType:
 
166
        fp=output
 
167
    else:
 
168
        fp=sys.stdout
 
169
 
 
170
    fp.write(';; -*- scheme -*-\n')
 
171
    fp.write('; object definitions ...\n')
 
172
 
 
173
    for klass, parent in objdefs:
 
174
        m = split_prefix_pat.match(klass)
 
175
        cmodule = None
 
176
        cname = klass
 
177
        if m:
 
178
            cmodule = m.group(1)
 
179
            cname = m.group(2)
 
180
 
 
181
        fp.write('(define-object ' + cname + '\n')
 
182
        if cmodule:
 
183
            fp.write('  (in-module "' + cmodule + '")\n')
 
184
        if parent:
 
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
 
189
        fp.write(')\n\n')
 
190
 
 
191
# ------------------ Find enum definitions -----------------
 
192
 
 
193
def find_enum_defs(buf, enums=[]):
 
194
    # strip comments
 
195
    # bulk comments
 
196
    buf = strip_comments(buf)
 
197
 
 
198
    buf = re.sub('\n', ' ', buf)
 
199
    
 
200
    enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)')
 
201
    splitter = re.compile(r'\s*,\s', re.MULTILINE)
 
202
    pos = 0
 
203
    while pos < len(buf):
 
204
        m = enum_pat.search(buf, pos)
 
205
        if not m: break
 
206
 
 
207
        name = m.group(2)
 
208
        vals = m.group(1)
 
209
        isflags = string.find(vals, '<<') >= 0
 
210
        entries = []
 
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))
 
216
        
 
217
        pos = m.end()
 
218
 
 
219
def write_enum_defs(enums, output=None):
 
220
    if type(output)==types.StringType:
 
221
        fp=open(output,'w')
 
222
    elif type(output)==types.FileType:
 
223
        fp=output
 
224
    else:
 
225
        fp=sys.stdout
 
226
 
 
227
    fp.write(';; Enumerations and flags ...\n\n')
 
228
    trans = string.maketrans(string.uppercase + '_', string.lowercase + '-')
 
229
    for cname, isflags, entries in enums:
 
230
        name = cname
 
231
        module = None
 
232
        m = split_prefix_pat.match(cname)
 
233
        if m:
 
234
            module = m.group(1)
 
235
            name = m.group(2)
 
236
        if isflags:
 
237
            fp.write('(define-flags ' + name + '\n')
 
238
        else:
 
239
            fp.write('(define-enum ' + name + '\n')
 
240
        if module:
 
241
            fp.write('  (in-module "' + module + '")\n')
 
242
        fp.write('  (c-name "' + cname + '")\n')
 
243
        fp.write('  (gtype-id "' + typecode(cname) + '")\n')
 
244
        prefix = entries[0]
 
245
        for ent in entries:
 
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):
 
249
                prefix = prefix[:-1]
 
250
        prefix_len = len(prefix)
 
251
        fp.write('  (values\n')
 
252
        for ent in entries:
 
253
            fp.write('    \'("%s" "%s")\n' %
 
254
                     (string.translate(ent[prefix_len:], trans), ent))
 
255
        fp.write('  )\n')
 
256
        fp.write(')\n\n')
 
257
 
 
258
# ------------------ Find function definitions -----------------
 
259
 
 
260
def clean_func(buf):
 
261
    """
 
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.
 
265
    """
 
266
    # bulk comments
 
267
    buf = strip_comments(buf)
 
268
 
 
269
    # compact continued lines
 
270
    pat = re.compile(r"""\\\n""", re.MULTILINE) 
 
271
    buf=pat.sub('',buf)
 
272
 
 
273
    # Preprocess directives
 
274
    pat = re.compile(r"""^[#].*?$""", re.MULTILINE) 
 
275
    buf=pat.sub('',buf)
 
276
 
 
277
    #typedefs, stucts, and enums
 
278
    pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""", re.MULTILINE) 
 
279
    buf=pat.sub('',buf)
 
280
 
 
281
    #strip DECLS macros
 
282
    pat = re.compile(r"""G_BEGIN_DECLS|BEGIN_LIBGTOP_DECLS""", re.MULTILINE) 
 
283
    buf=pat.sub('',buf)
 
284
 
 
285
    #extern "C"
 
286
    pat = re.compile(r"""^\s*(extern)\s+\"C\"\s+{""", re.MULTILINE) 
 
287
    buf=pat.sub('',buf)
 
288
 
 
289
    #multiple whitespace
 
290
    pat = re.compile(r"""\s+""", re.MULTILINE) 
 
291
    buf=pat.sub(' ',buf)
 
292
 
 
293
    #clean up line ends
 
294
    pat = re.compile(r""";\s*""", re.MULTILINE) 
 
295
    buf=pat.sub('\n',buf)
 
296
    buf = buf.lstrip()
 
297
 
 
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)
 
304
 
 
305
    # make return types that are const work.
 
306
    buf = string.replace(buf, 'G_CONST_RETURN ', 'const-')
 
307
    buf = string.replace(buf, 'const ', 'const-')
 
308
 
 
309
    return buf
 
310
 
 
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)
 
317
#"""
 
318
arg_split_pat = re.compile("\s*,\s*")
 
319
 
 
320
def define_func(buf,fp, prefix):
 
321
    buf=clean_func(buf)
 
322
    buf=string.split(buf,'\n')
 
323
    for p in buf:
 
324
        if len(p)==0: continue
 
325
        m=proto_pat.match(p)
 
326
        if m==None:
 
327
            if verbose:
 
328
                sys.stderr.write('No match:|%s|\n'%p)
 
329
            continue
 
330
        func = m.group('func')
 
331
        if func[0] == '_':
 
332
            continue
 
333
        ret = m.group('ret')
 
334
        args=m.group('args')
 
335
        args=arg_split_pat.split(args)
 
336
        for i in range(len(args)):
 
337
            spaces = string.count(args[i], ' ')
 
338
            if spaces > 1:
 
339
                args[i] = string.replace(args[i], ' ', '-', spaces - 1)
 
340
                
 
341
        write_func(fp, func, ret, args, prefix)
 
342
 
 
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$')
 
346
 
 
347
def write_func(fp, name, ret, args, prefix):
 
348
    if len(args) >= 1:
 
349
        # methods must have at least one argument
 
350
        munged_name = string.replace(name, '_', '')
 
351
        m = get_type_pat.match(args[0])
 
352
        if m:
 
353
            obj = m.group(2)
 
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)
 
357
                if prefix:
 
358
                    l = len(prefix) + 1
 
359
                    if mname[:l] == prefix and mname[l+1] == '_':
 
360
                        mname = mname[l+1:]
 
361
                fp.write('(define-method ' + mname + '\n')
 
362
                fp.write('  (of-object "' + obj + '")\n')
 
363
                fp.write('  (c-name "' + name + '")\n')
 
364
                if ret != 'void':
 
365
                    fp.write('  (return-type "' + ret + '")\n')
 
366
                else:
 
367
                    fp.write('  (return-type "none")\n')
 
368
                is_varargs = 0
 
369
                has_args = len(args) > 1
 
370
                for arg in args[1:]:
 
371
                    if arg == '...':
 
372
                        is_varargs = 1
 
373
                    elif arg in ('void', 'void '):
 
374
                        has_args = 0
 
375
                if has_args:
 
376
                    fp.write('  (parameters\n')
 
377
                    for arg in args[1:]:
 
378
                        if arg != '...':
 
379
                            tupleArg = tuple(string.split(arg))
 
380
                            if len(tupleArg) == 2:
 
381
                                fp.write('    \'("%s" "%s")\n' % tupleArg)
 
382
                    fp.write('  )\n')
 
383
                if is_varargs:
 
384
                    fp.write('  (varargs #t)\n')
 
385
                fp.write(')\n\n')
 
386
                return
 
387
    if prefix:
 
388
        l = len(prefix)
 
389
        if name[:l] == prefix and name[l] == '_':
 
390
            fname = name[l+1:]
 
391
        else:
 
392
            fname = name
 
393
    else:
 
394
        fname = name
 
395
    # it is either a constructor or normal function
 
396
    fp.write('(define-function ' + fname + '\n')
 
397
    fp.write('  (c-name "' + name + '")\n')
 
398
 
 
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:
 
403
        cname = ''
 
404
        for s in m.group(1).split ('_'):
 
405
            cname += s.title()
 
406
        if cname != '':
 
407
            fp.write('  (is-constructor-of "' + cname + '")\n')
 
408
 
 
409
    if ret != 'void':
 
410
        fp.write('  (return-type "' + ret + '")\n')
 
411
    else:
 
412
        fp.write('  (return-type "none")\n')
 
413
    is_varargs = 0
 
414
    has_args = len(args) > 0
 
415
    for arg in args:
 
416
        if arg == '...':
 
417
            is_varargs = 1
 
418
        elif arg in ('void', 'void '):
 
419
            has_args = 0
 
420
    if has_args:
 
421
        fp.write('  (parameters\n')
 
422
        for arg in args:
 
423
            if arg != '...':
 
424
                tupleArg = tuple(string.split(arg))
 
425
                if len(tupleArg) == 2:
 
426
                    fp.write('    \'("%s" "%s")\n' % tupleArg)
 
427
        fp.write('  )\n')
 
428
    if is_varargs:
 
429
        fp.write('  (varargs #t)\n')
 
430
    fp.write(')\n\n')
 
431
 
 
432
def write_def(input,output=None, prefix=None):
 
433
    fp = open(input)
 
434
    buf = fp.read()
 
435
    fp.close()
 
436
 
 
437
    if type(output) == types.StringType:
 
438
        fp = open(output,'w')
 
439
    elif type(output) == types.FileType:
 
440
        fp = output
 
441
    else:
 
442
        fp = sys.stdout
 
443
 
 
444
    fp.write('\n;; From %s\n\n' % input)
 
445
    buf = define_func(buf, fp, prefix)
 
446
    fp.write('\n')
 
447
 
 
448
# ------------------ Main function -----------------
 
449
 
 
450
verbose=0
 
451
def main(args):
 
452
    import getopt
 
453
    global verbose
 
454
 
 
455
    onlyenums = 0
 
456
    onlyobjdefs = 0
 
457
    separate = 0
 
458
    modulename = None
 
459
    opts, args = getopt.getopt(args[1:], 'vs:m:',
 
460
                               ['onlyenums', 'onlyobjdefs',
 
461
                                'modulename=', 'separate='])
 
462
    for o, v in opts:
 
463
        if o == '-v':
 
464
            verbose = 1
 
465
        if o == '--onlyenums':
 
466
            onlyenums = 1
 
467
        if o == '--onlyobjdefs':
 
468
            onlyobjdefs = 1
 
469
        if o in ('-s', '--separate'):
 
470
            separate = v
 
471
        if o in ('-m', '--modulename'):
 
472
            modulename = v
 
473
            
 
474
    if not args[0:1]:
 
475
        print 'Must specify at least one input file name'
 
476
        return -1
 
477
 
 
478
    # read all the object definitions in
 
479
    objdefs = []
 
480
    enums = []
 
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)
 
486
 
 
487
    if separate:
 
488
        types = file(separate + '-types.defs', 'w')
 
489
        methods = file(separate + '.defs', 'w')
 
490
        
 
491
        write_obj_defs(objdefs,types)
 
492
        write_enum_defs(enums,types)
 
493
        types.close()
 
494
        print "Wrote %s-types.defs" % separate
 
495
        
 
496
        for filename in args:
 
497
            write_def(filename,methods,prefix=modulename)
 
498
        methods.close()
 
499
        print "Wrote %s.defs" % separate
 
500
    else:
 
501
        if onlyenums:
 
502
            write_enum_defs(enums,None)
 
503
        elif onlyobjdefs:
 
504
            write_obj_defs(objdefs,None)
 
505
        else:
 
506
            write_obj_defs(objdefs,None)
 
507
            write_enum_defs(enums,None)
 
508
 
 
509
            for filename in args:
 
510
                write_def(filename,None,prefix=modulename)
 
511
            
 
512
if __name__ == '__main__':
 
513
    sys.exit(main(sys.argv))