_dbus_bindings: Expose name-validation functions to Python code.
[dbus-python-phuang.git] / dbus / extract.py
blob28ae202c68acd36652a2488201a55b4ebbfa3196
1 import commands
2 import re
3 import string
4 import sys
6 def clean_func(buf):
7 buf = strip_comments(buf)
8 pat = re.compile(r"""\\\n""", re.MULTILINE)
9 buf = pat.sub('',buf)
10 pat = re.compile(r"""^[#].*?$""", re.MULTILINE)
11 buf = pat.sub('',buf)
12 pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""", re.MULTILINE)
13 buf = pat.sub('',buf)
14 pat = re.compile(r"""\s+""", re.MULTILINE)
15 buf = pat.sub(' ',buf)
16 pat = re.compile(r""";\s*""", re.MULTILINE)
17 buf = pat.sub('\n',buf)
18 buf = buf.lstrip()
19 #pat=re.compile(r'\s+([*|&]+)\s*(\w+)')
20 pat = re.compile(r' \s+ ([*|&]+) \s* (\w+)',re.VERBOSE)
21 buf = pat.sub(r'\1 \2', buf)
22 pat = re.compile(r'\s+ (\w+) \[ \s* \]',re.VERBOSE)
23 buf = pat.sub(r'[] \1', buf)
24 # buf = string.replace(buf, 'G_CONST_RETURN ', 'const-')
25 buf = string.replace(buf, 'const ', '')
26 return buf
28 def strip_comments(buf):
29 parts = []
30 lastpos = 0
31 while 1:
32 pos = string.find(buf, '/*', lastpos)
33 if pos >= 0:
34 parts.append(buf[lastpos:pos])
35 pos = string.find(buf, '*/', pos)
36 if pos >= 0:
37 lastpos = pos + 2
38 else:
39 break
40 else:
41 parts.append(buf[lastpos:])
42 break
43 return string.join(parts, '')
45 def find_enums(buf):
46 enums = []
47 buf = strip_comments(buf)
48 buf = re.sub('\n', ' ', buf)
50 enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)')
51 splitter = re.compile(r'\s*,\s', re.MULTILINE)
52 pos = 0
53 while pos < len(buf):
54 m = enum_pat.search(buf, pos)
55 if not m: break
57 name = m.group(2)
58 vals = m.group(1)
59 isflags = string.find(vals, '<<') >= 0
60 entries = []
61 for val in splitter.split(vals):
62 if not string.strip(val): continue
63 entries.append(string.split(val)[0])
64 enums.append((name, isflags, entries))
66 pos = m.end()
67 return enums
69 #typedef unsigned int dbus_bool_t;
70 #typedef struct {
72 # }
73 #typedef struct FooStruct FooStruct;
74 # typedef void (* DBusAddWatchFunction) (DBusWatch *watch,
75 # void *data);
77 def find_typedefs(buf):
78 typedefs = []
79 buf = re.sub('\n', ' ', strip_comments(buf))
80 typedef_pat = re.compile(
81 r"""typedef\s*(?P<type>\w*)
82 \s*
83 ([(]\s*\*\s*(?P<callback>[\w* ]*)[)]|{([^}]*)}|)
84 \s*
85 (?P<args1>[(](?P<args2>[\s\w*,_]*)[)]|[\w ]*)""",
86 re.MULTILINE | re.VERBOSE)
87 pat = re.compile(r"""\s+""", re.MULTILINE)
88 pos = 0
89 while pos < len(buf):
90 m = typedef_pat.search(buf, pos)
91 if not m:
92 break
93 if m.group('type') == 'enum':
94 pos = m.end()
95 continue
96 if m.group('args2') != None:
97 args = pat.sub(' ', m.group('args2'))
99 current = '%s (* %s) (%s)' % (m.group('type'),
100 m.group('callback'),
101 args)
102 else:
103 current = '%s %s' % (m.group('type'), m.group('args1'))
104 typedefs.append(current)
105 pos = m.end()
106 return typedefs
108 proto_pat = re.compile(r"""
109 (?P<ret>(-|\w|\&|\*|\s)+\s*) # return type
110 \s+ # skip whitespace
111 (?P<func>\w+)\s*[(] # match the function name until the opening (
112 (?P<args>.*?)[)] # group the function arguments
113 """, re.IGNORECASE|re.VERBOSE)
114 arg_split_pat = re.compile("\s*,\s*")
117 def find_functions(buf):
118 functions = []
119 buf = clean_func(buf)
120 buf = string.split(buf,'\n')
121 for p in buf:
122 if len(p) == 0:
123 continue
124 m = proto_pat.match(p)
125 if m == None:
126 continue
128 func = m.group('func')
129 ret = m.group('ret')
130 args = m.group('args')
131 args = arg_split_pat.split(args)
132 # for i in range(len(args)):
133 # spaces = string.count(args[i], ' ')
134 # if spaces > 1:
135 # args[i] = string.replace(args[i], ' ', '-', spaces - 1)
137 functions.append((func, ret, args))
138 return functions
140 class Writer:
141 def __init__(self, filename, enums, typedefs, functions):
142 if not (enums or typedefs or functions):
143 return
144 print 'cdef extern from "%s":' % filename
146 self.output_enums(enums)
147 self.output_typedefs(typedefs)
148 self.output_functions(functions)
150 print ' pass'
151 print
153 def output_enums(self, enums):
154 for enum in enums:
155 print ' ctypedef enum %s:' % enum[0]
156 if enum[1] == 0:
157 for item in enum[2]:
158 print ' %s' % item
159 else:
160 i = 0
161 for item in enum[2]:
162 print ' %s' % item
163 # print ' %s = 1 << %d' % (item, i)
164 i += 1
165 print
166 def output_typedefs(self, typedefs):
167 for typedef in typedefs:
168 if typedef.find('va_list') != -1:
169 continue
171 parts = typedef.split()
172 if parts[0] == 'struct':
173 if parts[-2] == parts[-1]:
174 parts = parts[:-1]
175 print ' ctypedef %s' % ' '.join(parts)
176 else:
177 print ' ctypedef %s' % typedef
179 def output_functions(self, functions):
180 for func, ret, args in functions:
181 if func[0] == '_':
182 continue
184 str = ', '.join(args)
185 if str.find('...') != -1:
186 continue
187 if str.find('va_list') != -1:
188 continue
189 if str.strip() == 'void':
190 continue
191 print ' %-20s %s (%s)' % (ret, func, str)
193 def do_buffer(name, buffer):
194 functions = find_functions(buffer)
195 typedefs = find_typedefs(buffer)
196 enums = find_enums(buffer)
198 Writer(name, enums, typedefs, functions)
200 def do_header(filename, name=None):
201 if name == None:
202 name = filename
204 buffer = ""
205 for line in open(filename).readlines():
206 if line[0] == '#':
207 continue
208 buffer += line
210 print '# -- %s -- ' % filename
211 do_buffer(name, buffer)
213 def main(filename, flags, output=None):
214 old_stdout = None
215 if output is not None:
216 old_stdout = sys.stdout
217 sys.stdout = output
219 if filename.endswith('.h'):
220 do_header(filename)
221 return
223 cppflags = ' '.join(flags)
225 fd = open(filename)
226 for line in fd:
227 match = re.match('#include [<"]([^">]+)[">]$', line)
229 if match:
230 filename = match.group(1)
231 print >>sys.stderr, "matched %s" % (filename)
232 command = "echo '%s'|cpp %s" % (line, cppflags)
233 output = commands.getoutput(command)
234 print >>sys.stderr, "output %s" % (output)
235 do_buffer(filename, output)
236 else:
237 print line[:-1]
238 fd.close()
240 if old_stdout is not None:
241 sys.stdout = old_stdout
243 if __name__ == '__main__':
244 main(sys.argv[1], sys.argv[2:])