blob: 13a101139db5c2e36c54f122740d907c1c788e86 [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:
27 """sgmlop based XML parser. this is typically 15x faster
28 than SlowParser..."""
29
30 def __init__(self, target):
31
32 # setup callbacks
33 self.finish_starttag = target.start
34 self.finish_endtag = target.end
35 self.handle_data = target.data
36
37 # 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 }
45
46 def close(self):
47 try:
48 self.parser.close()
49 finally:
50 self.parser = self.feed = None # nuke circular reference
51
52 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)
58
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):
68 self.unknown_starttag = target.start
69 self.handle_data = target.data
70 self.unknown_endtag = target.end
71 xmllib.XMLParser.__init__(self)
72
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:
77 target = docParser()
78 if FastParser:
79 return FastParser(target), target
80 return SlowParser(target), target
81
82class docParser:
83 def __init__(self):
84 self._methodname = None
85 self._data = []
86 self.in_function = 0
87
88 def close(self):
89 if debug:
90 print "close"
91
92 def getmethodname(self):
93 return self._methodname
94
95 def data(self, text):
96 if debug:
97 print "data %s" % text
98 self._data.append(text)
99
100 def start(self, tag, attrs):
101 if debug:
102 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
Daniel Veillard3ce52572002-02-03 15:08:05 +0000132 self.function_return_field = None
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000133 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']
Daniel Veillard3ce52572002-02-03 15:08:05 +0000137 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:
143 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,
Daniel Veillard3ce52572002-02-03 15:08:05 +0000158 self.function_return_info,
159 self.function_return_field]
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000160 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
168def 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:
298 (desc, ret, args, file) = functions[name]
299 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 Veillard96fe0952002-01-30 20:52:23 +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])
319 if py_types.has_key(arg[1]):
Daniel Veillard96fe0952002-01-30 20:52:23 +0000320 (f, t, n, c) = py_types[arg[1]]
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000321 if f != None:
322 format = format + f
323 if t != None:
Daniel Veillard96fe0952002-01-30 20:52:23 +0000324 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])
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000331 if c_call != "":
332 c_call = c_call + ", ";
333 c_call = c_call + "%s" % (arg[0])
334 else:
Daniel Veillard96fe0952002-01-30 20:52:23 +0000335 if skipped_types.has_key(arg[1]):
336 return 0
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000337 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
343 if format != "":
344 format = format + ":%s" % (name)
345
346 if ret[0] == 'void':
Daniel Veillard26f1dcc2002-02-03 16:53:19 +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);
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000352 ret_convert = " Py_INCREF(Py_None);\n return(Py_None);\n"
353 elif py_types.has_key(ret[0]):
Daniel Veillard96fe0952002-01-30 20:52:23 +0000354 (f, t, n, c) = py_types[ret[0]]
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000355 c_return = " %s c_retval;\n" % (ret[0])
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000356 if file == "python_accessor" and ret[2] != None:
Daniel Veillard3ce52572002-02-03 15:08:05 +0000357 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);
Daniel Veillard96fe0952002-01-30 20:52:23 +0000360 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]):
363 (f, t, n, c) = py_return_types[ret[0]]
364 c_return = " %s c_retval;\n" % (ret[0])
365 c_call = "\n c_retval = %s(%s);\n" % (name, c_call);
366 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 Veillard96fe0952002-01-30 20:52:23 +0000369 if skipped_types.has_key(ret[0]):
370 return 0
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000371 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
377
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 Veillard96fe0952002-01-30 20:52:23 +0000381 export.write(" { \"%s\", libxml_%s, METH_VARARGS },\n" % (name, name))
Daniel Veillard9589d452002-02-02 10:28:17 +0000382
383 if file == "python":
384 # Those have been manually generated
385 return 1
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000386 if file == "python_accessor" and ret[0] != "void" and ret[2] == None:
387 # Those have been manually generated
388 return 1
Daniel Veillard9589d452002-02-02 10:28:17 +0000389
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000390 output.write("PyObject *\n")
391 output.write("libxml_%s(PyObject *self, PyObject *args) {\n" % (name))
392 if ret[0] != 'void':
393 output.write(" PyObject *py_retval;\n")
394 if c_return != "":
395 output.write(c_return)
396 if c_args != "":
397 output.write(c_args)
398 if format != "":
399 output.write("\n if (!PyArg_ParseTuple(args, \"%s\"%s))\n" %
400 (format, format_args))
401 output.write(" return(NULL);\n")
Daniel Veillard96fe0952002-01-30 20:52:23 +0000402 if c_convert != "":
403 output.write(c_convert)
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000404
405 output.write(c_call)
406 output.write(ret_convert)
407 output.write("}\n\n")
408 return 1
409
410try:
Daniel Veillard63276972002-01-31 23:49:05 +0000411 f = open("../doc/libxml2-api.xml")
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000412 data = f.read()
413 (parser, target) = getparser()
414 parser.feed(data)
415 parser.close()
416except IOError, msg:
417 print file, ":", msg
418
Daniel Veillard9589d452002-02-02 10:28:17 +0000419n = len(functions.keys())
420print "Found %d functions in libxml2-api.xml" % (n)
421
422py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject")
423try:
424 f = open("libxml2-python-api.xml")
425 data = f.read()
426 (parser, target) = getparser()
427 parser.feed(data)
428 parser.close()
429except IOError, msg:
430 print file, ":", msg
431
432
433print "Found %d functions in libxml2-python-api.xml" % (
434 len(functions.keys()) - n)
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000435nb_wrap = 0
436failed = 0
437skipped = 0
438
Daniel Veillard96fe0952002-01-30 20:52:23 +0000439include = open("libxml2-py.h", "w")
440include.write("/* Generated */\n\n")
441export = open("libxml2-export.c", "w")
442export.write("/* Generated */\n\n")
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000443wrapper = open("libxml2-py.c", "w")
444wrapper.write("/* Generated */\n\n")
445wrapper.write("#include <Python.h>\n")
446wrapper.write("#include <libxml/tree.h>\n")
447wrapper.write("#include \"libxml_wrap.h\"\n")
448wrapper.write("#include \"libxml2-py.h\"\n\n")
449for function in functions.keys():
Daniel Veillard96fe0952002-01-30 20:52:23 +0000450 ret = print_function_wrapper(function, wrapper, export, include)
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000451 if ret < 0:
452 failed = failed + 1
Daniel Veillard36ed5292002-01-30 23:49:06 +0000453 del functions[function]
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000454 if ret == 0:
455 skipped = skipped + 1
Daniel Veillard36ed5292002-01-30 23:49:06 +0000456 del functions[function]
457 if ret == 1:
458 nb_wrap = nb_wrap + 1
Daniel Veillard96fe0952002-01-30 20:52:23 +0000459include.close()
460export.close()
Daniel Veillardd2897fd2002-01-30 16:37:32 +0000461wrapper.close()
462
463print "Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap,
464 failed, skipped);
Daniel Veillard7db38712002-02-07 16:39:11 +0000465print "Missing type converters: "
466for type in unknown_types.keys():
467 print "%s:%d " % (type, len(unknown_types[type])),
468print
Daniel Veillard36ed5292002-01-30 23:49:06 +0000469
Daniel Veillard1971ee22002-01-31 20:29:19 +0000470#######################################################################
471#
472# This part writes part of the Python front-end classes based on
473# mapping rules between types and classes and also based on function
474# renaming to get consistent function names at the Python level
475#
476#######################################################################
477
478#
479# The type automatically remapped to generated classes
480#
481classes_type = {
482 "xmlNodePtr": ("._o", "xmlNode(_obj=%s)", "xmlNode"),
483 "xmlNode *": ("._o", "xmlNode(_obj=%s)", "xmlNode"),
484 "xmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
485 "xmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
486 "htmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
487 "htmlxmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
488 "xmlAttrPtr": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"),
489 "xmlAttr *": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"),
490 "xmlNsPtr": ("._o", "xmlNs(_obj=%s)", "xmlNs"),
491 "xmlNs *": ("._o", "xmlNs(_obj=%s)", "xmlNs"),
492 "xmlDtdPtr": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"),
493 "xmlDtd *": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"),
494 "xmlEntityPtr": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"),
495 "xmlEntity *": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"),
496 "xmlElementPtr": ("._o", "xmlElement(_obj=%s)", "xmlElement"),
497 "xmlElement *": ("._o", "xmlElement(_obj=%s)", "xmlElement"),
498 "xmlAttributePtr": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"),
499 "xmlAttribute *": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"),
500 "xmlXPathContextPtr": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
Daniel Veillard7db38712002-02-07 16:39:11 +0000501 "xmlXPathContext *": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
502 "xmlXPathParserContext *": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"),
503 "xmlXPathParserContextPtr": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"),
Daniel Veillard3ce52572002-02-03 15:08:05 +0000504 "xmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
505 "xmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
Daniel Veillard7db38712002-02-07 16:39:11 +0000506 "xmlCatalogPtr": ("._o", "catalog(_obj=%s)", "catalog"),
Daniel Veillard1971ee22002-01-31 20:29:19 +0000507}
508
509converter_type = {
510 "xmlXPathObjectPtr": "xpathObjectRet(%s)",
511}
512
513primary_classes = ["xmlNode", "xmlDoc"]
514
515classes_ancestor = {
516 "xmlNode" : "xmlCore",
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000517 "xmlDtd" : "xmlNode",
518 "xmlDoc" : "xmlNode",
519 "xmlAttr" : "xmlNode",
520 "xmlNs" : "xmlNode",
521 "xmlEntity" : "xmlNode",
522 "xmlElement" : "xmlNode",
523 "xmlAttribute" : "xmlNode",
Daniel Veillard1971ee22002-01-31 20:29:19 +0000524}
525classes_destructors = {
Daniel Veillard3ce52572002-02-03 15:08:05 +0000526 "parserCtxt": "xmlFreeParserCtxt",
Daniel Veillard7db38712002-02-07 16:39:11 +0000527 "catalog": "xmlFreeCatalog",
Daniel Veillard1971ee22002-01-31 20:29:19 +0000528}
529
Daniel Veillard36ed5292002-01-30 23:49:06 +0000530function_classes = {}
Daniel Veillard1971ee22002-01-31 20:29:19 +0000531
532function_classes["None"] = []
533for type in classes_type.keys():
534 function_classes[classes_type[type][2]] = []
535
536#
537# Build the list of C types to look for ordered to start with primary classes
538#
539ctypes = []
Daniel Veillard9589d452002-02-02 10:28:17 +0000540classes_list = []
Daniel Veillard1971ee22002-01-31 20:29:19 +0000541ctypes_processed = {}
Daniel Veillard9589d452002-02-02 10:28:17 +0000542classes_processed = {}
Daniel Veillard1971ee22002-01-31 20:29:19 +0000543for classe in primary_classes:
Daniel Veillard9589d452002-02-02 10:28:17 +0000544 classes_list.append(classe)
545 classes_processed[classe] = ()
Daniel Veillard1971ee22002-01-31 20:29:19 +0000546 for type in classes_type.keys():
547 tinfo = classes_type[type]
548 if tinfo[2] == classe:
549 ctypes.append(type)
550 ctypes_processed[type] = ()
551for type in classes_type.keys():
552 if ctypes_processed.has_key(type):
553 continue
554 tinfo = classes_type[type]
Daniel Veillard9589d452002-02-02 10:28:17 +0000555 if not classes_processed.has_key(tinfo[2]):
556 classes_list.append(tinfo[2])
557 classes_processed[tinfo[2]] = ()
558
Daniel Veillard1971ee22002-01-31 20:29:19 +0000559 ctypes.append(type)
560 ctypes_processed[type] = ()
561
Daniel Veillard3ce52572002-02-03 15:08:05 +0000562def nameFixup(function, classe, type, file):
Daniel Veillard1971ee22002-01-31 20:29:19 +0000563 listname = classe + "List"
564 ll = len(listname)
565 l = len(classe)
566 if name[0:l] == listname:
567 func = name[l:]
568 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard3ce52572002-02-03 15:08:05 +0000569 elif name[0:12] == "xmlParserGet" and file == "python_accessor":
570 func = name[12:]
571 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard26f1dcc2002-02-03 16:53:19 +0000572 elif name[0:12] == "xmlParserSet" and file == "python_accessor":
573 func = name[12:]
574 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000575 elif name[0:10] == "xmlNodeGet" and file == "python_accessor":
576 func = name[10:]
577 func = string.lower(func[0:1]) + func[1:]
Daniel Veillardc575b992002-02-08 13:28:40 +0000578 elif name[0:17] == "xmlXPathParserGet" and file == "python_accessor":
579 func = name[17:]
580 func = string.lower(func[0:1]) + func[1:]
581 elif name[0:11] == "xmlXPathGet" and file == "python_accessor":
582 func = name[11:]
583 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard7db38712002-02-07 16:39:11 +0000584 elif name[0:11] == "xmlACatalog":
585 func = name[11:]
586 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard1971ee22002-01-31 20:29:19 +0000587 elif name[0:l] == classe:
588 func = name[l:]
589 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard9589d452002-02-02 10:28:17 +0000590 elif name[0:7] == "libxml_":
591 func = name[7:]
592 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard1971ee22002-01-31 20:29:19 +0000593 elif name[0:6] == "xmlGet":
594 func = name[6:]
595 func = string.lower(func[0:1]) + func[1:]
596 elif name[0:3] == "xml":
Daniel Veillard36ed5292002-01-30 23:49:06 +0000597 func = name[3:]
598 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard36ed5292002-01-30 23:49:06 +0000599 else:
Daniel Veillard1971ee22002-01-31 20:29:19 +0000600 func = name
601 if func[0:5] == "xPath":
602 func = "xpath" + func[5:]
603 elif func[0:4] == "xPtr":
604 func = "xpointer" + func[4:]
605 elif func[0:8] == "xInclude":
606 func = "xinclude" + func[8:]
607 elif func[0:2] == "iD":
608 func = "ID" + func[2:]
609 elif func[0:3] == "uRI":
610 func = "URI" + func[3:]
611 elif func[0:4] == "uTF8":
612 func = "UTF8" + func[4:]
613 return func
Daniel Veillard36ed5292002-01-30 23:49:06 +0000614
Daniel Veillard1971ee22002-01-31 20:29:19 +0000615for name in functions.keys():
616 found = 0;
617 (desc, ret, args, file) = functions[name]
618 for type in ctypes:
619 classe = classes_type[type][2]
620
621 if name[0:3] == "xml" and len(args) >= 1 and args[0][1] == type:
622 found = 1
Daniel Veillard3ce52572002-02-03 15:08:05 +0000623 func = nameFixup(name, classe, type, file)
Daniel Veillard1971ee22002-01-31 20:29:19 +0000624 info = (0, func, name, ret, args, file)
625 function_classes[classe].append(info)
626 elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == type:
627 found = 1
Daniel Veillard3ce52572002-02-03 15:08:05 +0000628 func = nameFixup(name, classe, type, file)
Daniel Veillard1971ee22002-01-31 20:29:19 +0000629 info = (1, func, name, ret, args, file)
630 function_classes[classe].append(info)
631 elif name[0:4] == "html" and len(args) >= 1 and args[0][1] == type:
632 found = 1
Daniel Veillard3ce52572002-02-03 15:08:05 +0000633 func = nameFixup(name, classe, type, file)
Daniel Veillard1971ee22002-01-31 20:29:19 +0000634 info = (0, func, name, ret, args, file)
635 function_classes[classe].append(info)
636 elif name[0:4] == "html" and len(args) >= 2 and args[1][1] == type:
637 found = 1
Daniel Veillard3ce52572002-02-03 15:08:05 +0000638 func = nameFixup(name, classe, type, file)
Daniel Veillard1971ee22002-01-31 20:29:19 +0000639 info = (1, func, name, ret, args, file)
640 function_classes[classe].append(info)
641 if found == 1:
642 break
643 if found == 1:
644 continue
645 if name[0:8] == "xmlXPath":
646 continue
647 if name[0:6] == "xmlStr":
648 continue
649 if name[0:10] == "xmlCharStr":
650 continue
Daniel Veillard3ce52572002-02-03 15:08:05 +0000651 func = nameFixup(name, "None", file, file)
Daniel Veillard1971ee22002-01-31 20:29:19 +0000652 info = (0, func, name, ret, args, file)
653 function_classes['None'].append(info)
Daniel Veillard36ed5292002-01-30 23:49:06 +0000654
655classes = open("libxml2class.py", "w")
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000656txt = open("libxml2class.txt", "w")
657txt.write(" Generated Classes for libxml2-python\n\n")
Daniel Veillard36ed5292002-01-30 23:49:06 +0000658
Daniel Veillard1971ee22002-01-31 20:29:19 +0000659def functionCompare(info1, info2):
660 (index1, func1, name1, ret1, args1, file1) = info1
661 (index2, func2, name2, ret2, args2, file2) = info2
Daniel Veillard26f1dcc2002-02-03 16:53:19 +0000662 if file1 == file2:
663 if func1 < func2:
664 return -1
665 if func1 > func2:
666 return 1
Daniel Veillard3ce52572002-02-03 15:08:05 +0000667 if file1 == "python_accessor":
668 return -1
669 if file2 == "python_accessor":
670 return 1
Daniel Veillard1971ee22002-01-31 20:29:19 +0000671 if file1 < file2:
672 return -1
673 if file1 > file2:
674 return 1
Daniel Veillard1971ee22002-01-31 20:29:19 +0000675 return 0
676
677def writeDoc(name, args, indent, output):
678 if functions[name][0] == None or functions[name][0] == "":
679 return
680 val = functions[name][0]
681 val = string.replace(val, "NULL", "None");
682 output.write(indent)
683 output.write('"""')
684 while len(val) > 60:
685 str = val[0:60]
686 i = string.rfind(str, " ");
687 if i < 0:
688 i = 60
689 str = val[0:i]
690 val = val[i:]
691 output.write(str)
692 output.write('\n ');
693 output.write(indent)
694 output.write(val);
695 output.write('"""\n')
696
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000697txt.write("#\n# Global functions of the module\n#\n\n")
Daniel Veillard36ed5292002-01-30 23:49:06 +0000698if function_classes.has_key("None"):
Daniel Veillard1971ee22002-01-31 20:29:19 +0000699 flist = function_classes["None"]
700 flist.sort(functionCompare)
701 oldfile = ""
702 for info in flist:
Daniel Veillard36ed5292002-01-30 23:49:06 +0000703 (index, func, name, ret, args, file) = info
Daniel Veillard1971ee22002-01-31 20:29:19 +0000704 if file != oldfile:
705 classes.write("#\n# Functions from module %s\n#\n\n" % file)
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000706 txt.write("\n# functions from module %s\n" % file)
Daniel Veillard1971ee22002-01-31 20:29:19 +0000707 oldfile = file
Daniel Veillard36ed5292002-01-30 23:49:06 +0000708 classes.write("def %s(" % func)
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000709 txt.write("%s()\n" % func);
Daniel Veillard36ed5292002-01-30 23:49:06 +0000710 n = 0
711 for arg in args:
712 if n != 0:
713 classes.write(", ")
714 classes.write("%s" % arg[0])
715 n = n + 1
716 classes.write("):\n")
Daniel Veillard1971ee22002-01-31 20:29:19 +0000717 writeDoc(name, args, ' ', classes);
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000718
719 for arg in args:
720 if classes_type.has_key(arg[1]):
721 classes.write(" if %s == None: %s__o = None\n" %
722 (arg[0], arg[0]))
723 classes.write(" else: %s__o = %s%s\n" %
724 (arg[0], arg[0], classes_type[arg[1]][0]))
Daniel Veillard36ed5292002-01-30 23:49:06 +0000725 if ret[0] != "void":
726 classes.write(" ret = ");
727 else:
728 classes.write(" ");
729 classes.write("_libxml.%s(" % name)
730 n = 0
731 for arg in args:
732 if n != 0:
733 classes.write(", ");
734 classes.write("%s" % arg[0])
735 if classes_type.has_key(arg[1]):
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000736 classes.write("__o");
Daniel Veillard36ed5292002-01-30 23:49:06 +0000737 n = n + 1
738 classes.write(")\n");
739 if ret[0] != "void":
740 if classes_type.has_key(ret[0]):
741 classes.write(" if ret == None: return None\n");
742 classes.write(" return ");
743 classes.write(classes_type[ret[0]][1] % ("ret"));
744 classes.write("\n");
745 else:
746 classes.write(" return ret\n");
747 classes.write("\n");
748
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000749txt.write("\n\n#\n# Set of classes of the module\n#\n\n")
Daniel Veillard9589d452002-02-02 10:28:17 +0000750for classname in classes_list:
Daniel Veillard36ed5292002-01-30 23:49:06 +0000751 if classname == "None":
752 pass
753 else:
Daniel Veillard1971ee22002-01-31 20:29:19 +0000754 if classes_ancestor.has_key(classname):
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000755 txt.write("\n\nClass %s(%s)\n" % (classname,
756 classes_ancestor[classname]))
Daniel Veillard1971ee22002-01-31 20:29:19 +0000757 classes.write("class %s(%s):\n" % (classname,
758 classes_ancestor[classname]))
Daniel Veillard36ed5292002-01-30 23:49:06 +0000759 classes.write(" def __init__(self, _obj=None):\n")
760 classes.write(" self._o = None\n")
Daniel Veillard1971ee22002-01-31 20:29:19 +0000761 classes.write(" %s.__init__(self, _obj=_obj)\n\n" % (
762 classes_ancestor[classname]))
Daniel Veillard3ce52572002-02-03 15:08:05 +0000763 if classes_ancestor[classname] == "xmlCore" or \
764 classes_ancestor[classname] == "xmlNode":
765 classes.write(" def __repr__(self):\n")
766 format = "%s:%%s" % (classname)
767 classes.write(" return \"%s\" %% (self.name)\n\n" % (
768 format))
Daniel Veillard36ed5292002-01-30 23:49:06 +0000769 else:
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000770 txt.write("Class %s()\n" % (classname))
Daniel Veillard1971ee22002-01-31 20:29:19 +0000771 classes.write("class %s:\n" % (classname))
Daniel Veillard36ed5292002-01-30 23:49:06 +0000772 classes.write(" def __init__(self, _obj=None):\n")
773 classes.write(" if _obj != None:self._o = _obj;return\n")
774 classes.write(" self._o = None\n\n");
Daniel Veillard1971ee22002-01-31 20:29:19 +0000775 if classes_destructors.has_key(classname):
776 classes.write(" def __del__(self):\n")
777 classes.write(" if self._o != None:\n")
778 classes.write(" _libxml.%s(self._o)\n" %
779 classes_destructors[classname]);
780 classes.write(" self._o = None\n\n");
781 flist = function_classes[classname]
782 flist.sort(functionCompare)
783 oldfile = ""
784 for info in flist:
Daniel Veillard36ed5292002-01-30 23:49:06 +0000785 (index, func, name, ret, args, file) = info
Daniel Veillard1971ee22002-01-31 20:29:19 +0000786 if file != oldfile:
Daniel Veillard3ce52572002-02-03 15:08:05 +0000787 if file == "python_accessor":
788 classes.write(" # accessors for %s\n" % (classname))
789 txt.write(" # accessors\n")
790 else:
791 classes.write(" #\n")
792 classes.write(" # %s functions from module %s\n" % (
793 classname, file))
794 txt.write("\n # functions from module %s\n" % file)
795 classes.write(" #\n\n")
Daniel Veillard1971ee22002-01-31 20:29:19 +0000796 oldfile = file
Daniel Veillard36ed5292002-01-30 23:49:06 +0000797 classes.write(" def %s(self" % func)
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000798 txt.write(" %s()\n" % func);
Daniel Veillard36ed5292002-01-30 23:49:06 +0000799 n = 0
800 for arg in args:
801 if n != index:
802 classes.write(", %s" % arg[0])
803 n = n + 1
804 classes.write("):\n")
Daniel Veillard1971ee22002-01-31 20:29:19 +0000805 writeDoc(name, args, ' ', classes);
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000806 n = 0
807 for arg in args:
808 if classes_type.has_key(arg[1]):
809 if n != index:
810 classes.write(" if %s == None: %s__o = None\n" %
811 (arg[0], arg[0]))
812 classes.write(" else: %s__o = %s%s\n" %
813 (arg[0], arg[0], classes_type[arg[1]][0]))
814 n = n + 1
Daniel Veillard36ed5292002-01-30 23:49:06 +0000815 if ret[0] != "void":
816 classes.write(" ret = ");
817 else:
818 classes.write(" ");
819 classes.write("_libxml.%s(" % name)
820 n = 0
821 for arg in args:
822 if n != 0:
823 classes.write(", ");
824 if n != index:
825 classes.write("%s" % arg[0])
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000826 if classes_type.has_key(arg[1]):
827 classes.write("__o");
Daniel Veillard36ed5292002-01-30 23:49:06 +0000828 else:
829 classes.write("self");
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000830 if classes_type.has_key(arg[1]):
831 classes.write(classes_type[arg[1]][0])
Daniel Veillard36ed5292002-01-30 23:49:06 +0000832 n = n + 1
833 classes.write(")\n");
834 if ret[0] != "void":
835 if classes_type.has_key(ret[0]):
836 classes.write(" if ret == None: return None\n");
837 classes.write(" return ");
838 classes.write(classes_type[ret[0]][1] % ("ret"));
839 classes.write("\n");
Daniel Veillard1971ee22002-01-31 20:29:19 +0000840 elif converter_type.has_key(ret[0]):
841 classes.write(" if ret == None: return None\n");
842 classes.write(" return ");
843 classes.write(converter_type[ret[0]] % ("ret"));
844 classes.write("\n");
Daniel Veillard36ed5292002-01-30 23:49:06 +0000845 else:
846 classes.write(" return ret\n");
847 classes.write("\n");
848
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000849txt.close()
Daniel Veillard36ed5292002-01-30 23:49:06 +0000850classes.close()