/
xml2cython.py
224 lines (195 loc) · 6.47 KB
/
xml2cython.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#!/usr/bin/python
"""\
xml2cython: process xml files generated by gccxml and generate cython code
Usage:
xml2cython header xmlfile
By default, xml2cython pull out every function available in the xmlfile. There
are some basic filter you can use to limit the functions pulled out:
- -f/--filter-function-name: only pull out functions whose name match the
given string.
- -l/--location-filter: only pull out function which are declared in a file
whose name matches the given string.
Example:
xml2cython -f 'foo_' -l 'foo' header xmlfile
Will only pull out functions whose name match foo_ and which are declared
in file whose name match foo. Using regular expression instead of simple
strings should work"""
import getopt
import sys
import re
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
import cycodegenlib
from cycodegenlib.tp_puller import TypePuller
from cycodegenlib.misc import classify, query_items
from cycodegenlib.cycodegen import generate_cython
def generate_main(xml, output, lfilter=None, ffilter=None, funcs_list=None):
items, named, locations = query_items(xml)
funcs, tpdefs, enumvals, enums, structs, vars, unions, anoenums = \
classify(items, locations, lfilter=lfilter)
if ffilter is None:
ffilter = lambda x: True
if funcs_list:
kept_funcs = [i for i in funcs.values() if ffilter(i.name) \
and i.name in funcs_list]
else:
kept_funcs = [i for i in funcs.values() if ffilter(i.name)]
puller = TypePuller(items)
for f in kept_funcs:
puller.pull(f)
needed = puller.values()
# Filter "anonymous" enumerations according to location
if lfilter:
anoenumvals = []
for v in anoenums.values():
anoenumvals.extend(v.values)
else:
anoenumvals = enumvals.values()
# Order 'anonymous' enum values alphabetically
def cmpenum(a, b):
return cmp(a.name, b.name)
anoenumvals.sort(cmpenum)
# List of items to generate code for
gen = list(needed) #+ kept_funcs
generate_cython(output, gen, anoenumvals)
class Usage(Exception):
def __init__(self, msg):
self.msg = """\
usage: xml2cython [options] headerfile xmlfile
%s""" % msg
def main(argv=None):
if argv is None:
argv = sys.argv
# parse command line options
try:
try:
opts, args = getopt.getopt(argv[1:], "ho:l:f:i:V",
["help", "output", "location-filter",
"function-name-filter",
"input-file-filter", "--version"])
except getopt.error, msg:
raise Usage(msg)
except Usage, e:
print >>sys.stderr, e.msg
print >>sys.stderr, "for help use --help"
return 2
# process options
output = None
lfilter_str = None
ffilter_str = None
ifilter = None
for o, a in opts:
if o in ("-h", "--help"):
print __doc__
return 0
elif o in ("-o", "--output"):
output = a
elif o in ("-l", "--location-filter"):
lfilter_str = a
elif o in ("-f", "--function-name-filter"):
ffilter_str = a
elif o in ("-i", "--input-file-filter"):
ifilter = a
elif o in ("-V", "--version"):
print "xml2cython: use cycodegenlib version", cycodegenlib.version
return 0
if len(args) != 2:
print >>sys.stderr, "Error, exactly one input file must be specified"
print >>sys.stderr, "for help use --help"
return 2
header_input = args[0]
xml_input = args[1]
lfilter = None
if lfilter_str:
lfilter = re.compile(lfilter_str).search
ffilter = None
if ffilter_str:
ffilter = re.compile(ffilter_str).search
# Input file filter
funcs = []
if ifilter:
a = open(ifilter, 'r')
try:
funcs.extend(a.read().splitlines())
finally:
a.close()
# Generate cython code
out = StringIO()
try:
generate_main(xml_input, out, lfilter=lfilter,
ffilter=ffilter, funcs_list=funcs)
if output:
f = open(output, 'w')
try:
f.write("# This file was generated by cycodegenlib, DO NOT EDIT\n")
f.write("# Generated by command %s\n" % " ".join(argv))
f.write("# Codegenlib version %s\n" % cycodegenlib.version)
f.write("cdef extern from '%s':\n" % header_input)
f.write(out.getvalue())
finally:
f.close()
else:
print out.getvalue()
finally:
out.close()
if __name__ == '__main__':
sys.exit(main())
# #root = 'asoundlib'
# #root = 'CoreAudio_AudioHardware'
# root = 'foo'
# header_name = '%s.h' % root
# #header_matcher = re.compile('alsa')
# header_matcher = re.compile(header_name)
# #header_matcher = re.compile('AudioHardware')
# xml_name = '%s.xml' % root
# pyx_name = '_%s.pyx' % root
# if sys.platform[:7] == 'darwin':
# so_name = root
# else:
# so_name = 'lib%s.so' % root
#
# items, named, locations = query_items(xml_name)
# funcs, tpdefs, enumvals, enums, structs, vars, unions = \
# classify(items, locations, lfilter=header_matcher.search)
#
# #arguments = signatures_types(funcs.values())
# #print "Need to pull out arguments", [named[i] for i in arguments]
#
# puller = TypePuller(items)
# for f in funcs.values():
# puller.pull(f)
#
# needed = puller.values()
# #print "Pulled out items:", [named[i] for i in needed]
#
# # Order 'anonymous' enum values alphabetically
# def cmpenum(a, b):
# return cmp(a.name, b.name)
# anoenumvals = enumvals.values()
# anoenumvals.sort(cmpenum)
#
# # List of items to generate code for
# #gen = enumvals.values() + list(needed) + funcs.values()
# gen = list(needed) + funcs.values()
#
# #gen_names = [named[i] for i in gen]
#
# cython_code = [cy_generate(i) for i in gen]
#
# output = open(pyx_name, 'w')
# output.write("cdef extern from '%s':\n" % header_name)
# output.write("\tcdef enum:\n")
# for i in anoenumvals:
# output.write("\t\t%s = %d\n" % (i.name, int(i.value)))
# for i in cython_code:
# if not i:
# continue
# if len(i) > 1:
# output.write("\t%s\n" % i[0])
# for j in i[1:]:
# output.write("\t%s\n" % j)
# else:
# output.write("\t%s\n" % i[0])
# output.close()