diff options
Diffstat (limited to 'python/extract.py')
-rw-r--r-- | python/extract.py | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/python/extract.py b/python/extract.py new file mode 100644 index 00000000..460af5ab --- /dev/null +++ b/python/extract.py @@ -0,0 +1,237 @@ +import commands +import glob +import re +import os +import string +import sys + +def clean_func(buf): + buf = strip_comments(buf) + pat = re.compile(r"""\\\n""", re.MULTILINE) + buf = pat.sub('',buf) + pat = re.compile(r"""^[#].*?$""", re.MULTILINE) + buf = pat.sub('',buf) + pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""", re.MULTILINE) + buf = pat.sub('',buf) + pat = re.compile(r"""\s+""", re.MULTILINE) + buf = pat.sub(' ',buf) + pat = re.compile(r""";\s*""", re.MULTILINE) + buf = pat.sub('\n',buf) + buf = buf.lstrip() + #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) +# buf = string.replace(buf, 'G_CONST_RETURN ', 'const-') + buf = string.replace(buf, 'const ', '') + return buf + +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, '') + +def find_enums(buf): + enums = [] + buf = strip_comments(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]) + enums.append((name, isflags, entries)) + + pos = m.end() + return enums + +#typedef unsigned int dbus_bool_t; +#typedef struct { +# +# } +#typedef struct FooStruct FooStruct; +# typedef void (* DBusAddWatchFunction) (DBusWatch *watch, +# void *data); + +def find_typedefs(buf): + typedefs = [] + buf = re.sub('\n', ' ', strip_comments(buf)) + typedef_pat = re.compile( + r"""typedef\s*(?P<type>\w*) + \s* + ([(]\s*\*\s*(?P<callback>[\w* ]*)[)]|{([^}]*)}|) + \s* + (?P<args1>[(](?P<args2>[\s\w*,_]*)[)]|[\w ]*)""", + re.MULTILINE | re.VERBOSE) + pat = re.compile(r"""\s+""", re.MULTILINE) + pos = 0 + while pos < len(buf): + m = typedef_pat.search(buf, pos) + if not m: + break + if m.group('type') == 'enum': + pos = m.end() + continue + if m.group('args2') != None: + args = pat.sub(' ', m.group('args2')) + + current = '%s (* %s) (%s)' % (m.group('type'), + m.group('callback'), + args) + else: + current = '%s %s' % (m.group('type'), m.group('args1')) + typedefs.append(current) + pos = m.end() + return typedefs + +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 find_functions(buf): + functions = [] + 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: + continue + + func = m.group('func') + 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) + + functions.append((func, ret, args)) + return functions + +class Writer: + def __init__(self, filename, enums, typedefs, functions): + if not (enums or typedefs or functions): + return + print 'cdef extern from "%s":' % filename + + self.output_enums(enums) + self.output_typedefs(typedefs) + self.output_functions(functions) + + print ' pass' + print + + def output_enums(self, enums): + for enum in enums: + print ' ctypedef enum %s:' % enum[0] + if enum[1] == 0: + for item in enum[2]: + print ' %s' % item + else: + i = 0 + for item in enum[2]: + print ' %s' % item +# print ' %s = 1 << %d' % (item, i) + i += 1 + print + def output_typedefs(self, typedefs): + for typedef in typedefs: + if typedef.find('va_list') != -1: + continue + + parts = typedef.split() + if parts[0] == 'struct': + if parts[-2] == parts[-1]: + parts = parts[:-1] + print ' ctypedef %s' % ' '.join(parts) + else: + print ' ctypedef %s' % typedef + + def output_functions(self, functions): + for func, ret, args in functions: + if func[0] == '_': + continue + + str = ', '.join(args) + if str.find('...') != -1: + continue + if str.find('va_list') != -1: + continue + if str.strip() == 'void': + continue + print ' %-20s %s (%s)' % (ret, func, str) + +def do_buffer(name, buffer): + functions = find_functions(buffer) + typedefs = find_typedefs(buffer) + enums = find_enums(buffer) + + Writer(name, enums, typedefs, functions) + +def do_header(filename, name=None): + if name == None: + name = filename + + buffer = "" + for line in open(filename).readlines(): + if line[0] == '#': + continue + buffer += line + + print '# -- %s -- ' % filename + do_buffer(name, buffer) + +filename = sys.argv[1] + +if filename.endswith('.h'): + do_header(filename) + raise SystemExit + +cppflags = "" + +for flag in sys.argv[2:]: + cppflags = cppflags + " " + flag + +fd = open(filename) + +for line in fd.readlines(): + if line.startswith('#include'): + filename = line.split(' ')[1][1:-2] + command = "echo '%s'|cpp %s" % (line, cppflags) + sys.stderr.write('running %s' % (command)) + output = commands.getoutput(command) + do_buffer(filename, output) + else: + print line[:-1] |