blob: 09009a2c580edcd5eb4c9cd082d8fccc96ed3176 [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
Daniel Veillard36ed5292002-01-30 23:49:06 +00008import string
Daniel Veillard1971ee22002-01-31 20:29:19 +00009
10#######################################################################
11#
12# That part if purely the API acquisition phase from the
13# XML API description
14#
15#######################################################################
16import os
Daniel Veillardd2897fd2002-01-30 16:37:32 +000017import xmllib
18try:
19 import sgmlop
20except ImportError:
21 sgmlop = None # accelerator not available
22
23debug = 0
24
25if sgmlop:
26 class FastParser:
Daniel Veillard01a6d412002-02-11 18:42:20 +000027 """sgmlop based XML parser. this is typically 15x faster
28 than SlowParser..."""
Daniel Veillardd2897fd2002-01-30 16:37:32 +000029
Daniel Veillard01a6d412002-02-11 18:42:20 +000030 def __init__(self, target):
Daniel Veillardd2897fd2002-01-30 16:37:32 +000031
Daniel Veillard01a6d412002-02-11 18:42:20 +000032 # setup callbacks
33 self.finish_starttag = target.start
34 self.finish_endtag = target.end
35 self.handle_data = target.data
Daniel Veillardd2897fd2002-01-30 16:37:32 +000036
Daniel Veillard01a6d412002-02-11 18:42:20 +000037 # activate parser
38 self.parser = sgmlop.XMLParser()
39 self.parser.register(self)
40 self.feed = self.parser.feed
41 self.entity = {
42 "amp": "&", "gt": ">", "lt": "<",
43 "apos": "'", "quot": '"'
44 }
Daniel Veillardd2897fd2002-01-30 16:37:32 +000045
Daniel Veillard01a6d412002-02-11 18:42:20 +000046 def close(self):
47 try:
48 self.parser.close()
49 finally:
50 self.parser = self.feed = None # nuke circular reference
Daniel Veillardd2897fd2002-01-30 16:37:32 +000051
Daniel Veillard01a6d412002-02-11 18:42:20 +000052 def handle_entityref(self, entity):
53 # <string> entity
54 try:
55 self.handle_data(self.entity[entity])
56 except KeyError:
57 self.handle_data("&%s;" % entity)
Daniel Veillardd2897fd2002-01-30 16:37:32 +000058
59else:
60 FastParser = None
61
62
63class SlowParser(xmllib.XMLParser):
64 """slow but safe standard parser, based on the XML parser in
65 Python's standard library."""
66
67 def __init__(self, target):
Daniel Veillard01a6d412002-02-11 18:42:20 +000068 self.unknown_starttag = target.start
69 self.handle_data = target.data
70 self.unknown_endtag = target.end
71 xmllib.XMLParser.__init__(self)
Daniel Veillardd2897fd2002-01-30 16:37:32 +000072
73def getparser(target = None):
74 # get the fastest available parser, and attach it to an
75 # unmarshalling object. return both objects.
76 if target == None:
Daniel Veillard01a6d412002-02-11 18:42:20 +000077 target = docParser()
Daniel Veillardd2897fd2002-01-30 16:37:32 +000078 if FastParser:
Daniel Veillard01a6d412002-02-11 18:42:20 +000079 return FastParser(target), target
Daniel Veillardd2897fd2002-01-30 16:37:32 +000080 return SlowParser(target), target
81
82class docParser:
83 def __init__(self):
84 self._methodname = None
Daniel Veillard01a6d412002-02-11 18:42:20 +000085 self._data = []
86 self.in_function = 0
Daniel Veillardd2897fd2002-01-30 16:37:32 +000087
88 def close(self):
89 if debug:
Daniel Veillard01a6d412002-02-11 18:42:20 +000090 print "close"
Daniel Veillardd2897fd2002-01-30 16:37:32 +000091
92 def getmethodname(self):
93 return self._methodname
94
95 def data(self, text):
96 if debug:
Daniel Veillard01a6d412002-02-11 18:42:20 +000097 print "data %s" % text
Daniel Veillardd2897fd2002-01-30 16:37:32 +000098 self._data.append(text)
99
100 def start(self, tag, attrs):
101 if debug:
Daniel Veillard01a6d412002-02-11 18:42:20 +0000102 print "start %s, %s" % (tag, attrs)
103 if tag == 'function':
104 self._data = []
105 self.in_function = 1
106 self.function = None
107 self.function_args = []
108 self.function_descr = None
109 self.function_return = None
110 self.function_file = None
111 if attrs.has_key('name'):
112 self.function = attrs['name']
113 if attrs.has_key('file'):
114 self.function_file = attrs['file']
115 elif tag == 'info':
116 self._data = []
117 elif tag == 'arg':
118 if self.in_function == 1:
119 self.function_arg_name = None
120 self.function_arg_type = None
121 self.function_arg_info = None
122 if attrs.has_key('name'):
123 self.function_arg_name = attrs['name']
124 if attrs.has_key('type'):
125 self.function_arg_type = attrs['type']
126 if attrs.has_key('info'):
127 self.function_arg_info = attrs['info']
128 elif tag == 'return':
129 if self.in_function == 1:
130 self.function_return_type = None
131 self.function_return_info = None
132 self.function_return_field = None
133 if attrs.has_key('type'):
134 self.function_return_type = attrs['type']
135 if attrs.has_key('info'):
136 self.function_return_info = attrs['info']
137 if attrs.has_key('field'):
138 self.function_return_field = attrs['field']
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000139
140
141 def end(self, tag):
142 if debug:
Daniel Veillard01a6d412002-02-11 18:42:20 +0000143 print "end %s" % tag
144 if tag == 'function':
145 if self.function != None:
146 function(self.function, self.function_descr,
147 self.function_return, self.function_args,
148 self.function_file)
149 self.in_function = 0
150 elif tag == 'arg':
151 if self.in_function == 1:
152 self.function_args.append([self.function_arg_name,
153 self.function_arg_type,
154 self.function_arg_info])
155 elif tag == 'return':
156 if self.in_function == 1:
157 self.function_return = [self.function_return_type,
158 self.function_return_info,
159 self.function_return_field]
160 elif tag == 'info':
161 str = ''
162 for c in self._data:
163 str = str + c
164 if self.in_function == 1:
165 self.function_descr = str
166
167
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000168def function(name, desc, ret, args, file):
169 global functions
170
171 functions[name] = (desc, ret, args, file)
172
Daniel Veillard1971ee22002-01-31 20:29:19 +0000173#######################################################################
174#
175# Some filtering rukes to drop functions/types which should not
176# be exposed as-is on the Python interface
177#
178#######################################################################
Daniel Veillard36ed5292002-01-30 23:49:06 +0000179
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000180skipped_modules = {
181 'xmlmemory': None,
Daniel Veillard96fe0952002-01-30 20:52:23 +0000182 'DOCBparser': None,
183 'SAX': None,
184 'hash': None,
185 'list': None,
186 'threads': None,
Daniel Veillard1971ee22002-01-31 20:29:19 +0000187 'xpointer': None,
Daniel Veillard96fe0952002-01-30 20:52:23 +0000188}
189skipped_types = {
190 'int *': "usually a return type",
191 'xmlSAXHandlerPtr': "not the proper interface for SAX",
192 'htmlSAXHandlerPtr': "not the proper interface for SAX",
Daniel Veillard96fe0952002-01-30 20:52:23 +0000193 'xmlRMutexPtr': "thread specific, skipped",
194 'xmlMutexPtr': "thread specific, skipped",
195 'xmlGlobalStatePtr': "thread specific, skipped",
196 'xmlListPtr': "internal representation not suitable for python",
197 'xmlBufferPtr': "internal representation not suitable for python",
198 'FILE *': None,
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000199}
Daniel Veillard1971ee22002-01-31 20:29:19 +0000200
201#######################################################################
202#
203# Table of remapping to/from the python type or class to the C
204# counterpart.
205#
206#######################################################################
207
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000208py_types = {
Daniel Veillard96fe0952002-01-30 20:52:23 +0000209 'void': (None, None, None, None),
210 'int': ('i', None, "int", "int"),
211 'long': ('i', None, "int", "int"),
212 'double': ('d', None, "double", "double"),
213 'unsigned int': ('i', None, "int", "int"),
214 'xmlChar': ('c', None, "int", "int"),
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000215 'unsigned char *': ('z', None, "charPtr", "char *"),
216 'char *': ('z', None, "charPtr", "char *"),
Daniel Veillardc575b992002-02-08 13:28:40 +0000217 'const char *': ('z', None, "charPtrConst", "const char *"),
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000218 'xmlChar *': ('z', None, "xmlCharPtr", "xmlChar *"),
Daniel Veillardc575b992002-02-08 13:28:40 +0000219 'const xmlChar *': ('z', None, "xmlCharPtrConst", "const xmlChar *"),
Daniel Veillard96fe0952002-01-30 20:52:23 +0000220 'xmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
221 'const xmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
222 'xmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
223 'const xmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
224 'xmlDtdPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
225 'const xmlDtdPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
226 'xmlDtd *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
227 'const xmlDtd *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
228 'xmlAttrPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
229 'const xmlAttrPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
230 'xmlAttr *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
231 'const xmlAttr *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
232 'xmlEntityPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
233 'const xmlEntityPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
234 'xmlEntity *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
235 'const xmlEntity *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
Daniel Veillard1971ee22002-01-31 20:29:19 +0000236 'xmlElementPtr': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
237 'const xmlElementPtr': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
238 'xmlElement *': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
239 'const xmlElement *': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
240 'xmlAttributePtr': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
241 'const xmlAttributePtr': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
242 'xmlAttribute *': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
243 'const xmlAttribute *': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
244 'xmlNsPtr': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
245 'const xmlNsPtr': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
246 'xmlNs *': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
247 'const xmlNs *': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
Daniel Veillard96fe0952002-01-30 20:52:23 +0000248 'xmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
249 'const xmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
250 'xmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
251 'const xmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
252 'htmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
253 'const htmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
254 'htmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
255 'const htmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
256 'htmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
257 'const htmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
258 'htmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
259 'const htmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
Daniel Veillard1971ee22002-01-31 20:29:19 +0000260 'xmlXPathContextPtr': ('O', "xmlXPathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"),
261 'xmlXPathContext *': ('O', "xpathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"),
Daniel Veillard7db38712002-02-07 16:39:11 +0000262 'xmlXPathParserContextPtr': ('O', "xmlXPathParserContext", "xmlXPathParserContextPtr", "xmlXPathParserContextPtr"),
Daniel Veillard3ce52572002-02-03 15:08:05 +0000263 'xmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
264 'xmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
265 'htmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
266 'htmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
Daniel Veillard7db38712002-02-07 16:39:11 +0000267 'xmlCatalogPtr': ('O', "catalog", "xmlCatalogPtr", "xmlCatalogPtr"),
268 'FILE *': ('O', "File", "FILEPtr", "FILE *"),
Daniel Veillard1971ee22002-01-31 20:29:19 +0000269}
270
271py_return_types = {
272 'xmlXPathObjectPtr': ('O', "foo", "xmlXPathObjectPtr", "xmlXPathObjectPtr"),
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000273}
274
275unknown_types = {}
276
Daniel Veillard1971ee22002-01-31 20:29:19 +0000277#######################################################################
278#
279# This part writes the C <-> Python stubs libxml2-py.[ch] and
280# the table libxml2-export.c to add when registrering the Python module
281#
282#######################################################################
283
284def skip_function(name):
285 if name[0:12] == "xmlXPathWrap":
286 return 1
287# if name[0:11] == "xmlXPathNew":
288# return 1
289 return 0
290
Daniel Veillard96fe0952002-01-30 20:52:23 +0000291def print_function_wrapper(name, output, export, include):
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000292 global py_types
293 global unknown_types
294 global functions
295 global skipped_modules
296
297 try:
Daniel Veillard01a6d412002-02-11 18:42:20 +0000298 (desc, ret, args, file) = functions[name]
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000299 except:
300 print "failed to get function %s infos"
301 return
302
303 if skipped_modules.has_key(file):
304 return 0
Daniel Veillard1971ee22002-01-31 20:29:19 +0000305 if skip_function(name) == 1:
306 return 0
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000307
308 c_call = "";
309 format=""
310 format_args=""
311 c_args=""
312 c_return=""
Daniel Veillard96fe0952002-01-30 20:52:23 +0000313 c_convert=""
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000314 for arg in args:
Daniel Veillard01a6d412002-02-11 18:42:20 +0000315 # This should be correct
316 if arg[1][0:6] == "const ":
317 arg[1] = arg[1][6:]
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000318 c_args = c_args + " %s %s;\n" % (arg[1], arg[0])
Daniel Veillard01a6d412002-02-11 18:42:20 +0000319 if py_types.has_key(arg[1]):
320 (f, t, n, c) = py_types[arg[1]]
321 if f != None:
322 format = format + f
323 if t != None:
324 format_args = format_args + ", &pyobj_%s" % (arg[0])
325 c_args = c_args + " PyObject *pyobj_%s;\n" % (arg[0])
326 c_convert = c_convert + \
327 " %s = (%s) Py%s_Get(pyobj_%s);\n" % (arg[0],
328 arg[1], t, arg[0]);
329 else:
330 format_args = format_args + ", &%s" % (arg[0])
331 if c_call != "":
332 c_call = c_call + ", ";
333 c_call = c_call + "%s" % (arg[0])
334 else:
335 if skipped_types.has_key(arg[1]):
336 return 0
337 if unknown_types.has_key(arg[1]):
338 lst = unknown_types[arg[1]]
339 lst.append(name)
340 else:
341 unknown_types[arg[1]] = [name]
342 return -1
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000343 if format != "":
344 format = format + ":%s" % (name)
345
346 if ret[0] == 'void':
Daniel Veillard01a6d412002-02-11 18:42:20 +0000347 if file == "python_accessor":
348 c_call = "\n %s->%s = %s;\n" % (args[0][0], args[1][0],
349 args[1][0])
350 else:
351 c_call = "\n %s(%s);\n" % (name, c_call);
352 ret_convert = " Py_INCREF(Py_None);\n return(Py_None);\n"
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000353 elif py_types.has_key(ret[0]):
Daniel Veillard01a6d412002-02-11 18:42:20 +0000354 (f, t, n, c) = py_types[ret[0]]
355 c_return = " %s c_retval;\n" % (ret[0])
356 if file == "python_accessor" and ret[2] != None:
357 c_call = "\n c_retval = %s->%s;\n" % (args[0][0], ret[2])
358 else:
359 c_call = "\n c_retval = %s(%s);\n" % (name, c_call);
360 ret_convert = " py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c)
361 ret_convert = ret_convert + " return(py_retval);\n"
Daniel Veillard1971ee22002-01-31 20:29:19 +0000362 elif py_return_types.has_key(ret[0]):
Daniel Veillard01a6d412002-02-11 18:42:20 +0000363 (f, t, n, c) = py_return_types[ret[0]]
364 c_return = " %s c_retval;\n" % (ret[0])
Daniel Veillard1971ee22002-01-31 20:29:19 +0000365 c_call = "\n c_retval = %s(%s);\n" % (name, c_call);
Daniel Veillard01a6d412002-02-11 18:42:20 +0000366 ret_convert = " py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c)
367 ret_convert = ret_convert + " return(py_retval);\n"
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000368 else:
Daniel Veillard01a6d412002-02-11 18:42:20 +0000369 if skipped_types.has_key(ret[0]):
370 return 0
371 if unknown_types.has_key(ret[0]):
372 lst = unknown_types[ret[0]]
373 lst.append(name)
374 else:
375 unknown_types[ret[0]] = [name]
376 return -1
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000377
Daniel Veillard96fe0952002-01-30 20:52:23 +0000378 include.write("PyObject * ")
379 include.write("libxml_%s(PyObject *self, PyObject *args);\n" % (name))
Daniel Veillard9589d452002-02-02 10:28:17 +0000380
Daniel Veillard5e5c2d02002-02-09 18:03:01 +0000381 export.write(" { \"%s\", libxml_%s, METH_VARARGS, NULL },\n" %
382 (name, name))
Daniel Veillard9589d452002-02-02 10:28:17 +0000383
384 if file == "python":
385 # Those have been manually generated
Daniel Veillard01a6d412002-02-11 18:42:20 +0000386 return 1
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000387 if file == "python_accessor" and ret[0] != "void" and ret[2] == None:
388 # Those have been manually generated
Daniel Veillard01a6d412002-02-11 18:42:20 +0000389 return 1
Daniel Veillard9589d452002-02-02 10:28:17 +0000390
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000391 output.write("PyObject *\n")
392 output.write("libxml_%s(PyObject *self, PyObject *args) {\n" % (name))
393 if ret[0] != 'void':
Daniel Veillard01a6d412002-02-11 18:42:20 +0000394 output.write(" PyObject *py_retval;\n")
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000395 if c_return != "":
Daniel Veillard01a6d412002-02-11 18:42:20 +0000396 output.write(c_return)
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000397 if c_args != "":
Daniel Veillard01a6d412002-02-11 18:42:20 +0000398 output.write(c_args)
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000399 if format != "":
Daniel Veillard01a6d412002-02-11 18:42:20 +0000400 output.write("\n if (!PyArg_ParseTuple(args, \"%s\"%s))\n" %
401 (format, format_args))
402 output.write(" return(NULL);\n")
Daniel Veillard96fe0952002-01-30 20:52:23 +0000403 if c_convert != "":
Daniel Veillard01a6d412002-02-11 18:42:20 +0000404 output.write(c_convert)
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000405
406 output.write(c_call)
407 output.write(ret_convert)
408 output.write("}\n\n")
409 return 1
410
411try:
Daniel Veillard63276972002-01-31 23:49:05 +0000412 f = open("../doc/libxml2-api.xml")
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000413 data = f.read()
414 (parser, target) = getparser()
415 parser.feed(data)
416 parser.close()
417except IOError, msg:
418 print file, ":", msg
419
Daniel Veillard9589d452002-02-02 10:28:17 +0000420n = len(functions.keys())
421print "Found %d functions in libxml2-api.xml" % (n)
422
423py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject")
424try:
425 f = open("libxml2-python-api.xml")
426 data = f.read()
427 (parser, target) = getparser()
428 parser.feed(data)
429 parser.close()
430except IOError, msg:
431 print file, ":", msg
432
433
434print "Found %d functions in libxml2-python-api.xml" % (
435 len(functions.keys()) - n)
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000436nb_wrap = 0
437failed = 0
438skipped = 0
439
Daniel Veillard96fe0952002-01-30 20:52:23 +0000440include = open("libxml2-py.h", "w")
441include.write("/* Generated */\n\n")
442export = open("libxml2-export.c", "w")
443export.write("/* Generated */\n\n")
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000444wrapper = open("libxml2-py.c", "w")
445wrapper.write("/* Generated */\n\n")
446wrapper.write("#include <Python.h>\n")
447wrapper.write("#include <libxml/tree.h>\n")
448wrapper.write("#include \"libxml_wrap.h\"\n")
449wrapper.write("#include \"libxml2-py.h\"\n\n")
450for function in functions.keys():
Daniel Veillard96fe0952002-01-30 20:52:23 +0000451 ret = print_function_wrapper(function, wrapper, export, include)
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000452 if ret < 0:
453 failed = failed + 1
Daniel Veillard01a6d412002-02-11 18:42:20 +0000454 del functions[function]
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000455 if ret == 0:
456 skipped = skipped + 1
Daniel Veillard01a6d412002-02-11 18:42:20 +0000457 del functions[function]
Daniel Veillard36ed5292002-01-30 23:49:06 +0000458 if ret == 1:
459 nb_wrap = nb_wrap + 1
Daniel Veillard96fe0952002-01-30 20:52:23 +0000460include.close()
461export.close()
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000462wrapper.close()
463
464print "Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap,
Daniel Veillard01a6d412002-02-11 18:42:20 +0000465 failed, skipped);
Daniel Veillard7db38712002-02-07 16:39:11 +0000466print "Missing type converters: "
467for type in unknown_types.keys():
468 print "%s:%d " % (type, len(unknown_types[type])),
469print
Daniel Veillard36ed5292002-01-30 23:49:06 +0000470
Daniel Veillard1971ee22002-01-31 20:29:19 +0000471#######################################################################
472#
473# This part writes part of the Python front-end classes based on
474# mapping rules between types and classes and also based on function
475# renaming to get consistent function names at the Python level
476#
477#######################################################################
478
479#
480# The type automatically remapped to generated classes
481#
482classes_type = {
483 "xmlNodePtr": ("._o", "xmlNode(_obj=%s)", "xmlNode"),
484 "xmlNode *": ("._o", "xmlNode(_obj=%s)", "xmlNode"),
485 "xmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
486 "xmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
487 "htmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
488 "htmlxmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
489 "xmlAttrPtr": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"),
490 "xmlAttr *": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"),
491 "xmlNsPtr": ("._o", "xmlNs(_obj=%s)", "xmlNs"),
492 "xmlNs *": ("._o", "xmlNs(_obj=%s)", "xmlNs"),
493 "xmlDtdPtr": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"),
494 "xmlDtd *": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"),
495 "xmlEntityPtr": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"),
496 "xmlEntity *": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"),
497 "xmlElementPtr": ("._o", "xmlElement(_obj=%s)", "xmlElement"),
498 "xmlElement *": ("._o", "xmlElement(_obj=%s)", "xmlElement"),
499 "xmlAttributePtr": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"),
500 "xmlAttribute *": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"),
501 "xmlXPathContextPtr": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
Daniel Veillard7db38712002-02-07 16:39:11 +0000502 "xmlXPathContext *": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
503 "xmlXPathParserContext *": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"),
504 "xmlXPathParserContextPtr": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"),
Daniel Veillard3ce52572002-02-03 15:08:05 +0000505 "xmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
506 "xmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
Daniel Veillard7db38712002-02-07 16:39:11 +0000507 "xmlCatalogPtr": ("._o", "catalog(_obj=%s)", "catalog"),
Daniel Veillard1971ee22002-01-31 20:29:19 +0000508}
509
510converter_type = {
511 "xmlXPathObjectPtr": "xpathObjectRet(%s)",
512}
513
514primary_classes = ["xmlNode", "xmlDoc"]
515
516classes_ancestor = {
517 "xmlNode" : "xmlCore",
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000518 "xmlDtd" : "xmlNode",
519 "xmlDoc" : "xmlNode",
520 "xmlAttr" : "xmlNode",
521 "xmlNs" : "xmlNode",
522 "xmlEntity" : "xmlNode",
523 "xmlElement" : "xmlNode",
524 "xmlAttribute" : "xmlNode",
Daniel Veillard1971ee22002-01-31 20:29:19 +0000525}
526classes_destructors = {
Daniel Veillard3ce52572002-02-03 15:08:05 +0000527 "parserCtxt": "xmlFreeParserCtxt",
Daniel Veillard7db38712002-02-07 16:39:11 +0000528 "catalog": "xmlFreeCatalog",
Daniel Veillard1971ee22002-01-31 20:29:19 +0000529}
530
Daniel Veillard36ed5292002-01-30 23:49:06 +0000531function_classes = {}
Daniel Veillard1971ee22002-01-31 20:29:19 +0000532
533function_classes["None"] = []
534for type in classes_type.keys():
535 function_classes[classes_type[type][2]] = []
536
537#
538# Build the list of C types to look for ordered to start with primary classes
539#
540ctypes = []
Daniel Veillard9589d452002-02-02 10:28:17 +0000541classes_list = []
Daniel Veillard1971ee22002-01-31 20:29:19 +0000542ctypes_processed = {}
Daniel Veillard9589d452002-02-02 10:28:17 +0000543classes_processed = {}
Daniel Veillard1971ee22002-01-31 20:29:19 +0000544for classe in primary_classes:
Daniel Veillard9589d452002-02-02 10:28:17 +0000545 classes_list.append(classe)
546 classes_processed[classe] = ()
Daniel Veillard1971ee22002-01-31 20:29:19 +0000547 for type in classes_type.keys():
548 tinfo = classes_type[type]
Daniel Veillard01a6d412002-02-11 18:42:20 +0000549 if tinfo[2] == classe:
550 ctypes.append(type)
551 ctypes_processed[type] = ()
Daniel Veillard1971ee22002-01-31 20:29:19 +0000552for type in classes_type.keys():
553 if ctypes_processed.has_key(type):
554 continue
555 tinfo = classes_type[type]
Daniel Veillard9589d452002-02-02 10:28:17 +0000556 if not classes_processed.has_key(tinfo[2]):
557 classes_list.append(tinfo[2])
Daniel Veillard01a6d412002-02-11 18:42:20 +0000558 classes_processed[tinfo[2]] = ()
559
Daniel Veillard1971ee22002-01-31 20:29:19 +0000560 ctypes.append(type)
561 ctypes_processed[type] = ()
562
Daniel Veillard3ce52572002-02-03 15:08:05 +0000563def nameFixup(function, classe, type, file):
Daniel Veillard1971ee22002-01-31 20:29:19 +0000564 listname = classe + "List"
565 ll = len(listname)
566 l = len(classe)
567 if name[0:l] == listname:
Daniel Veillard01a6d412002-02-11 18:42:20 +0000568 func = name[l:]
569 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard3ce52572002-02-03 15:08:05 +0000570 elif name[0:12] == "xmlParserGet" and file == "python_accessor":
571 func = name[12:]
572 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard26f1dcc2002-02-03 16:53:19 +0000573 elif name[0:12] == "xmlParserSet" and file == "python_accessor":
574 func = name[12:]
575 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000576 elif name[0:10] == "xmlNodeGet" and file == "python_accessor":
577 func = name[10:]
578 func = string.lower(func[0:1]) + func[1:]
Daniel Veillardc575b992002-02-08 13:28:40 +0000579 elif name[0:17] == "xmlXPathParserGet" and file == "python_accessor":
580 func = name[17:]
581 func = string.lower(func[0:1]) + func[1:]
582 elif name[0:11] == "xmlXPathGet" and file == "python_accessor":
583 func = name[11:]
584 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard7db38712002-02-07 16:39:11 +0000585 elif name[0:11] == "xmlACatalog":
586 func = name[11:]
587 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard1971ee22002-01-31 20:29:19 +0000588 elif name[0:l] == classe:
Daniel Veillard01a6d412002-02-11 18:42:20 +0000589 func = name[l:]
590 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard9589d452002-02-02 10:28:17 +0000591 elif name[0:7] == "libxml_":
Daniel Veillard01a6d412002-02-11 18:42:20 +0000592 func = name[7:]
593 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard1971ee22002-01-31 20:29:19 +0000594 elif name[0:6] == "xmlGet":
Daniel Veillard01a6d412002-02-11 18:42:20 +0000595 func = name[6:]
596 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard1971ee22002-01-31 20:29:19 +0000597 elif name[0:3] == "xml":
Daniel Veillard01a6d412002-02-11 18:42:20 +0000598 func = name[3:]
599 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard36ed5292002-01-30 23:49:06 +0000600 else:
Daniel Veillard1971ee22002-01-31 20:29:19 +0000601 func = name
602 if func[0:5] == "xPath":
603 func = "xpath" + func[5:]
604 elif func[0:4] == "xPtr":
605 func = "xpointer" + func[4:]
606 elif func[0:8] == "xInclude":
607 func = "xinclude" + func[8:]
608 elif func[0:2] == "iD":
609 func = "ID" + func[2:]
610 elif func[0:3] == "uRI":
611 func = "URI" + func[3:]
612 elif func[0:4] == "uTF8":
613 func = "UTF8" + func[4:]
614 return func
Daniel Veillard36ed5292002-01-30 23:49:06 +0000615
Daniel Veillard1971ee22002-01-31 20:29:19 +0000616for name in functions.keys():
617 found = 0;
618 (desc, ret, args, file) = functions[name]
619 for type in ctypes:
620 classe = classes_type[type][2]
621
Daniel Veillard01a6d412002-02-11 18:42:20 +0000622 if name[0:3] == "xml" and len(args) >= 1 and args[0][1] == type:
623 found = 1
624 func = nameFixup(name, classe, type, file)
625 info = (0, func, name, ret, args, file)
626 function_classes[classe].append(info)
627 elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == type:
628 found = 1
629 func = nameFixup(name, classe, type, file)
630 info = (1, func, name, ret, args, file)
631 function_classes[classe].append(info)
632 elif name[0:4] == "html" and len(args) >= 1 and args[0][1] == type:
633 found = 1
634 func = nameFixup(name, classe, type, file)
635 info = (0, func, name, ret, args, file)
636 function_classes[classe].append(info)
637 elif name[0:4] == "html" and len(args) >= 2 and args[1][1] == type:
638 found = 1
639 func = nameFixup(name, classe, type, file)
640 info = (1, func, name, ret, args, file)
641 function_classes[classe].append(info)
642 if found == 1:
643 break
Daniel Veillard1971ee22002-01-31 20:29:19 +0000644 if found == 1:
645 continue
646 if name[0:8] == "xmlXPath":
647 continue
648 if name[0:6] == "xmlStr":
649 continue
650 if name[0:10] == "xmlCharStr":
651 continue
Daniel Veillard3ce52572002-02-03 15:08:05 +0000652 func = nameFixup(name, "None", file, file)
Daniel Veillard1971ee22002-01-31 20:29:19 +0000653 info = (0, func, name, ret, args, file)
654 function_classes['None'].append(info)
Daniel Veillard36ed5292002-01-30 23:49:06 +0000655
656classes = open("libxml2class.py", "w")
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000657txt = open("libxml2class.txt", "w")
658txt.write(" Generated Classes for libxml2-python\n\n")
Daniel Veillard36ed5292002-01-30 23:49:06 +0000659
Daniel Veillard1971ee22002-01-31 20:29:19 +0000660def functionCompare(info1, info2):
661 (index1, func1, name1, ret1, args1, file1) = info1
662 (index2, func2, name2, ret2, args2, file2) = info2
Daniel Veillard26f1dcc2002-02-03 16:53:19 +0000663 if file1 == file2:
Daniel Veillard01a6d412002-02-11 18:42:20 +0000664 if func1 < func2:
665 return -1
666 if func1 > func2:
667 return 1
Daniel Veillard3ce52572002-02-03 15:08:05 +0000668 if file1 == "python_accessor":
669 return -1
670 if file2 == "python_accessor":
671 return 1
Daniel Veillard1971ee22002-01-31 20:29:19 +0000672 if file1 < file2:
673 return -1
674 if file1 > file2:
675 return 1
Daniel Veillard1971ee22002-01-31 20:29:19 +0000676 return 0
677
678def writeDoc(name, args, indent, output):
679 if functions[name][0] == None or functions[name][0] == "":
680 return
681 val = functions[name][0]
682 val = string.replace(val, "NULL", "None");
683 output.write(indent)
684 output.write('"""')
685 while len(val) > 60:
686 str = val[0:60]
Daniel Veillard01a6d412002-02-11 18:42:20 +0000687 i = string.rfind(str, " ");
688 if i < 0:
689 i = 60
Daniel Veillard1971ee22002-01-31 20:29:19 +0000690 str = val[0:i]
Daniel Veillard01a6d412002-02-11 18:42:20 +0000691 val = val[i:]
692 output.write(str)
693 output.write('\n ');
694 output.write(indent)
Daniel Veillard1971ee22002-01-31 20:29:19 +0000695 output.write(val);
696 output.write('"""\n')
697
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000698txt.write("#\n# Global functions of the module\n#\n\n")
Daniel Veillard36ed5292002-01-30 23:49:06 +0000699if function_classes.has_key("None"):
Daniel Veillard1971ee22002-01-31 20:29:19 +0000700 flist = function_classes["None"]
701 flist.sort(functionCompare)
702 oldfile = ""
703 for info in flist:
Daniel Veillard01a6d412002-02-11 18:42:20 +0000704 (index, func, name, ret, args, file) = info
705 if file != oldfile:
706 classes.write("#\n# Functions from module %s\n#\n\n" % file)
707 txt.write("\n# functions from module %s\n" % file)
708 oldfile = file
709 classes.write("def %s(" % func)
710 txt.write("%s()\n" % func);
711 n = 0
712 for arg in args:
713 if n != 0:
714 classes.write(", ")
715 classes.write("%s" % arg[0])
716 n = n + 1
717 classes.write("):\n")
718 writeDoc(name, args, ' ', classes);
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000719
Daniel Veillard01a6d412002-02-11 18:42:20 +0000720 for arg in args:
721 if classes_type.has_key(arg[1]):
722 classes.write(" if %s == None: %s__o = None\n" %
723 (arg[0], arg[0]))
724 classes.write(" else: %s__o = %s%s\n" %
725 (arg[0], arg[0], classes_type[arg[1]][0]))
726 if ret[0] != "void":
727 classes.write(" ret = ");
728 else:
729 classes.write(" ");
730 classes.write("libxml2mod.%s(" % name)
731 n = 0
732 for arg in args:
733 if n != 0:
734 classes.write(", ");
735 classes.write("%s" % arg[0])
736 if classes_type.has_key(arg[1]):
737 classes.write("__o");
738 n = n + 1
739 classes.write(")\n");
740 if ret[0] != "void":
741 if classes_type.has_key(ret[0]):
742 classes.write(" if ret == None: return None\n");
743 classes.write(" return ");
744 classes.write(classes_type[ret[0]][1] % ("ret"));
745 classes.write("\n");
746 else:
747 classes.write(" return ret\n");
748 classes.write("\n");
Daniel Veillard36ed5292002-01-30 23:49:06 +0000749
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000750txt.write("\n\n#\n# Set of classes of the module\n#\n\n")
Daniel Veillard9589d452002-02-02 10:28:17 +0000751for classname in classes_list:
Daniel Veillard36ed5292002-01-30 23:49:06 +0000752 if classname == "None":
753 pass
754 else:
Daniel Veillard1971ee22002-01-31 20:29:19 +0000755 if classes_ancestor.has_key(classname):
Daniel Veillard01a6d412002-02-11 18:42:20 +0000756 txt.write("\n\nClass %s(%s)\n" % (classname,
757 classes_ancestor[classname]))
758 classes.write("class %s(%s):\n" % (classname,
759 classes_ancestor[classname]))
760 classes.write(" def __init__(self, _obj=None):\n")
761 classes.write(" self._o = None\n")
762 classes.write(" %s.__init__(self, _obj=_obj)\n\n" % (
763 classes_ancestor[classname]))
764 if classes_ancestor[classname] == "xmlCore" or \
765 classes_ancestor[classname] == "xmlNode":
766 classes.write(" def __repr__(self):\n")
767 format = "%s:%%s" % (classname)
768 classes.write(" return \"%s\" %% (self.name)\n\n" % (
769 format))
770 else:
771 txt.write("Class %s()\n" % (classname))
772 classes.write("class %s:\n" % (classname))
773 classes.write(" def __init__(self, _obj=None):\n")
774 classes.write(" if _obj != None:self._o = _obj;return\n")
775 classes.write(" self._o = None\n\n");
776 if classes_destructors.has_key(classname):
777 classes.write(" def __del__(self):\n")
778 classes.write(" if self._o != None:\n")
779 classes.write(" libxml2mod.%s(self._o)\n" %
780 classes_destructors[classname]);
781 classes.write(" self._o = None\n\n");
782 flist = function_classes[classname]
783 flist.sort(functionCompare)
784 oldfile = ""
785 for info in flist:
786 (index, func, name, ret, args, file) = info
787 if file != oldfile:
788 if file == "python_accessor":
789 classes.write(" # accessors for %s\n" % (classname))
790 txt.write(" # accessors\n")
791 else:
792 classes.write(" #\n")
793 classes.write(" # %s functions from module %s\n" % (
794 classname, file))
795 txt.write("\n # functions from module %s\n" % file)
796 classes.write(" #\n\n")
797 oldfile = file
798 classes.write(" def %s(self" % func)
799 txt.write(" %s()\n" % func);
800 n = 0
801 for arg in args:
802 if n != index:
803 classes.write(", %s" % arg[0])
804 n = n + 1
805 classes.write("):\n")
806 writeDoc(name, args, ' ', classes);
807 n = 0
808 for arg in args:
809 if classes_type.has_key(arg[1]):
810 if n != index:
811 classes.write(" if %s == None: %s__o = None\n" %
812 (arg[0], arg[0]))
813 classes.write(" else: %s__o = %s%s\n" %
814 (arg[0], arg[0], classes_type[arg[1]][0]))
815 n = n + 1
816 if ret[0] != "void":
817 classes.write(" ret = ");
818 else:
819 classes.write(" ");
820 classes.write("libxml2mod.%s(" % name)
821 n = 0
822 for arg in args:
823 if n != 0:
824 classes.write(", ");
825 if n != index:
826 classes.write("%s" % arg[0])
827 if classes_type.has_key(arg[1]):
828 classes.write("__o");
829 else:
830 classes.write("self");
831 if classes_type.has_key(arg[1]):
832 classes.write(classes_type[arg[1]][0])
833 n = n + 1
834 classes.write(")\n");
835 if ret[0] != "void":
836 if classes_type.has_key(ret[0]):
837 classes.write(" if ret == None: return None\n");
838 classes.write(" return ");
839 classes.write(classes_type[ret[0]][1] % ("ret"));
840 classes.write("\n");
841 elif converter_type.has_key(ret[0]):
842 classes.write(" if ret == None: return None\n");
843 classes.write(" return ");
844 classes.write(converter_type[ret[0]] % ("ret"));
845 classes.write("\n");
846 else:
847 classes.write(" return ret\n");
848 classes.write("\n");
Daniel Veillard36ed5292002-01-30 23:49:06 +0000849
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000850txt.close()
Daniel Veillard36ed5292002-01-30 23:49:06 +0000851classes.close()