blob: 294285461c38c5e09bfcb6b08b14c8f6b206d674 [file] [log] [blame]
Daniel Veillardd2897fd2002-01-30 16:37:32 +00001#!/usr/bin/python -u
2#
3# generate python wrappers from the XML API description
4#
5
6functions = {}
7
8import os
9import xmllib
10try:
11 import sgmlop
12except ImportError:
13 sgmlop = None # accelerator not available
14
15debug = 0
16
17if sgmlop:
18 class FastParser:
19 """sgmlop based XML parser. this is typically 15x faster
20 than SlowParser..."""
21
22 def __init__(self, target):
23
24 # setup callbacks
25 self.finish_starttag = target.start
26 self.finish_endtag = target.end
27 self.handle_data = target.data
28
29 # activate parser
30 self.parser = sgmlop.XMLParser()
31 self.parser.register(self)
32 self.feed = self.parser.feed
33 self.entity = {
34 "amp": "&", "gt": ">", "lt": "<",
35 "apos": "'", "quot": '"'
36 }
37
38 def close(self):
39 try:
40 self.parser.close()
41 finally:
42 self.parser = self.feed = None # nuke circular reference
43
44 def handle_entityref(self, entity):
45 # <string> entity
46 try:
47 self.handle_data(self.entity[entity])
48 except KeyError:
49 self.handle_data("&%s;" % entity)
50
51else:
52 FastParser = None
53
54
55class SlowParser(xmllib.XMLParser):
56 """slow but safe standard parser, based on the XML parser in
57 Python's standard library."""
58
59 def __init__(self, target):
60 self.unknown_starttag = target.start
61 self.handle_data = target.data
62 self.unknown_endtag = target.end
63 xmllib.XMLParser.__init__(self)
64
65def getparser(target = None):
66 # get the fastest available parser, and attach it to an
67 # unmarshalling object. return both objects.
68 if target == None:
69 target = docParser()
70 if FastParser:
71 return FastParser(target), target
72 return SlowParser(target), target
73
74class docParser:
75 def __init__(self):
76 self._methodname = None
77 self._data = []
78 self.in_function = 0
79
80 def close(self):
81 if debug:
82 print "close"
83
84 def getmethodname(self):
85 return self._methodname
86
87 def data(self, text):
88 if debug:
89 print "data %s" % text
90 self._data.append(text)
91
92 def start(self, tag, attrs):
93 if debug:
94 print "start %s, %s" % (tag, attrs)
95 if tag == 'function':
96 self._data = []
97 self.in_function = 1
98 self.function = None
99 self.function_args = []
100 self.function_descr = None
101 self.function_return = None
102 self.function_file = None
103 if attrs.has_key('name'):
104 self.function = attrs['name']
105 if attrs.has_key('file'):
106 self.function_file = attrs['file']
107 elif tag == 'info':
108 self._data = []
109 elif tag == 'arg':
110 if self.in_function == 1:
111 self.function_arg_name = None
112 self.function_arg_type = None
113 self.function_arg_info = None
114 if attrs.has_key('name'):
115 self.function_arg_name = attrs['name']
116 if attrs.has_key('type'):
117 self.function_arg_type = attrs['type']
118 if attrs.has_key('info'):
119 self.function_arg_info = attrs['info']
120 elif tag == 'return':
121 if self.in_function == 1:
122 self.function_return_type = None
123 self.function_return_info = None
124 if attrs.has_key('type'):
125 self.function_return_type = attrs['type']
126 if attrs.has_key('info'):
127 self.function_return_info = attrs['info']
128
129
130 def end(self, tag):
131 if debug:
132 print "end %s" % tag
133 if tag == 'function':
134 if self.function != None:
135 function(self.function, self.function_descr,
136 self.function_return, self.function_args,
137 self.function_file)
138 self.in_function = 0
139 elif tag == 'arg':
140 if self.in_function == 1:
141 self.function_args.append([self.function_arg_name,
142 self.function_arg_type,
143 self.function_arg_info])
144 elif tag == 'return':
145 if self.in_function == 1:
146 self.function_return = [self.function_return_type,
147 self.function_return_info]
148 elif tag == 'info':
149 str = ''
150 for c in self._data:
151 str = str + c
152 if self.in_function == 1:
153 self.function_descr = str
154
155
156def function(name, desc, ret, args, file):
157 global functions
158
159 functions[name] = (desc, ret, args, file)
160
161skipped_modules = {
162 'xmlmemory': None,
163}
164py_types = {
165 'void': (None, None, None),
166 'int': ('i', None, "int"),
167 'xmlChar': ('c', None, "int"),
168 'char *': ('s', None, "charPtr"),
169 'const char *': ('s', None, "charPtr"),
170 'xmlChar *': ('s', None, "xmlCharPtr"),
171 'const xmlChar *': ('s', None, "xmlCharPtr"),
172}
173
174unknown_types = {}
175
176def print_function_wrapper(name, output):
177 global py_types
178 global unknown_types
179 global functions
180 global skipped_modules
181
182 try:
183 (desc, ret, args, file) = functions[name]
184 except:
185 print "failed to get function %s infos"
186 return
187
188 if skipped_modules.has_key(file):
189 return 0
190
191 c_call = "";
192 format=""
193 format_args=""
194 c_args=""
195 c_return=""
196 for arg in args:
197 c_args = c_args + " %s %s;\n" % (arg[1], arg[0])
198 if py_types.has_key(arg[1]):
199 (f, t, n) = py_types[arg[1]]
200 if f != None:
201 format = format + f
202 if t != None:
203 format_args = format_args + ", &%s" % (t)
204 format_args = format_args + ", &%s" % (arg[0])
205 if c_call != "":
206 c_call = c_call + ", ";
207 c_call = c_call + "%s" % (arg[0])
208 else:
209 if unknown_types.has_key(arg[1]):
210 lst = unknown_types[arg[1]]
211 lst.append(name)
212 else:
213 unknown_types[arg[1]] = [name]
214 return -1
215 if format != "":
216 format = format + ":%s" % (name)
217
218 if ret[0] == 'void':
219 c_call = "\n %s(%s);\n" % (name, c_call);
220 ret_convert = " Py_INCREF(Py_None);\n return(Py_None);\n"
221 elif py_types.has_key(ret[0]):
222 (f, t, n) = py_types[ret[0]]
223 c_return = " %s c_retval;\n" % (ret[0])
224 c_call = "\n c_retval = %s(%s);\n" % (name, c_call);
225 ret_convert = " py_retval = libxml_%sWrap(c_retval);\n return(py_retval);\n" % (n)
226 else:
227 if unknown_types.has_key(ret[0]):
228 lst = unknown_types[ret[0]]
229 lst.append(name)
230 else:
231 unknown_types[ret[0]] = [name]
232 return -1
233
234 output.write("PyObject *\n")
235 output.write("libxml_%s(PyObject *self, PyObject *args) {\n" % (name))
236 if ret[0] != 'void':
237 output.write(" PyObject *py_retval;\n")
238 if c_return != "":
239 output.write(c_return)
240 if c_args != "":
241 output.write(c_args)
242 if format != "":
243 output.write("\n if (!PyArg_ParseTuple(args, \"%s\"%s))\n" %
244 (format, format_args))
245 output.write(" return(NULL);\n")
246
247 output.write(c_call)
248 output.write(ret_convert)
249 output.write("}\n\n")
250 return 1
251
252try:
253 f = open("libxml2-api.xml")
254 data = f.read()
255 (parser, target) = getparser()
256 parser.feed(data)
257 parser.close()
258except IOError, msg:
259 print file, ":", msg
260
261print "Found %d functions in libxml2-api.xml" % (len(functions.keys()))
262nb_wrap = 0
263failed = 0
264skipped = 0
265
266wrapper = open("libxml2-py.c", "w")
267wrapper.write("/* Generated */\n\n")
268wrapper.write("#include <Python.h>\n")
269wrapper.write("#include <libxml/tree.h>\n")
270wrapper.write("#include \"libxml_wrap.h\"\n")
271wrapper.write("#include \"libxml2-py.h\"\n\n")
272for function in functions.keys():
273 ret = print_function_wrapper(function, wrapper)
274 if ret < 0:
275 failed = failed + 1
276 if ret == 1:
277 nb_wrap = nb_wrap + 1
278 if ret == 0:
279 skipped = skipped + 1
280wrapper.close()
281
282print "Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap,
283 failed, skipped);
284print "Missing type converters: %s" % (unknown_types.keys())