blob: 0b13c41a181591ea73a8b4711aa901dc0f23a1eb [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 *"),
217 'const char *': ('z', None, "charPtr", "char *"),
218 'xmlChar *': ('z', None, "xmlCharPtr", "xmlChar *"),
219 'const xmlChar *': ('z', None, "xmlCharPtr", "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 = {
526 "xpathContext": "xmlXPathFreeContext",
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]
549 if tinfo[2] == classe:
550 ctypes.append(type)
551 ctypes_processed[type] = ()
552for 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])
558 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:
568 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 Veillard7db38712002-02-07 16:39:11 +0000579 elif name[0:11] == "xmlACatalog":
580 func = name[11:]
581 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard1971ee22002-01-31 20:29:19 +0000582 elif name[0:l] == classe:
583 func = name[l:]
584 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard9589d452002-02-02 10:28:17 +0000585 elif name[0:7] == "libxml_":
586 func = name[7:]
587 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard1971ee22002-01-31 20:29:19 +0000588 elif name[0:6] == "xmlGet":
589 func = name[6:]
590 func = string.lower(func[0:1]) + func[1:]
591 elif name[0:3] == "xml":
Daniel Veillard36ed5292002-01-30 23:49:06 +0000592 func = name[3:]
593 func = string.lower(func[0:1]) + func[1:]
Daniel Veillard36ed5292002-01-30 23:49:06 +0000594 else:
Daniel Veillard1971ee22002-01-31 20:29:19 +0000595 func = name
596 if func[0:5] == "xPath":
597 func = "xpath" + func[5:]
598 elif func[0:4] == "xPtr":
599 func = "xpointer" + func[4:]
600 elif func[0:8] == "xInclude":
601 func = "xinclude" + func[8:]
602 elif func[0:2] == "iD":
603 func = "ID" + func[2:]
604 elif func[0:3] == "uRI":
605 func = "URI" + func[3:]
606 elif func[0:4] == "uTF8":
607 func = "UTF8" + func[4:]
608 return func
Daniel Veillard36ed5292002-01-30 23:49:06 +0000609
Daniel Veillard1971ee22002-01-31 20:29:19 +0000610for name in functions.keys():
611 found = 0;
612 (desc, ret, args, file) = functions[name]
613 for type in ctypes:
614 classe = classes_type[type][2]
615
616 if name[0:3] == "xml" and len(args) >= 1 and args[0][1] == type:
617 found = 1
Daniel Veillard3ce52572002-02-03 15:08:05 +0000618 func = nameFixup(name, classe, type, file)
Daniel Veillard1971ee22002-01-31 20:29:19 +0000619 info = (0, func, name, ret, args, file)
620 function_classes[classe].append(info)
621 elif name[0:3] == "xml" and len(args) >= 2 and args[1][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 = (1, func, name, ret, args, file)
625 function_classes[classe].append(info)
626 elif name[0:4] == "html" and len(args) >= 1 and args[0][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 = (0, func, name, ret, args, file)
630 function_classes[classe].append(info)
631 elif name[0:4] == "html" and len(args) >= 2 and args[1][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 = (1, func, name, ret, args, file)
635 function_classes[classe].append(info)
636 if found == 1:
637 break
638 if found == 1:
639 continue
640 if name[0:8] == "xmlXPath":
641 continue
642 if name[0:6] == "xmlStr":
643 continue
644 if name[0:10] == "xmlCharStr":
645 continue
Daniel Veillard3ce52572002-02-03 15:08:05 +0000646 func = nameFixup(name, "None", file, file)
Daniel Veillard1971ee22002-01-31 20:29:19 +0000647 info = (0, func, name, ret, args, file)
648 function_classes['None'].append(info)
Daniel Veillard36ed5292002-01-30 23:49:06 +0000649
650classes = open("libxml2class.py", "w")
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000651txt = open("libxml2class.txt", "w")
652txt.write(" Generated Classes for libxml2-python\n\n")
Daniel Veillard36ed5292002-01-30 23:49:06 +0000653
Daniel Veillard1971ee22002-01-31 20:29:19 +0000654def functionCompare(info1, info2):
655 (index1, func1, name1, ret1, args1, file1) = info1
656 (index2, func2, name2, ret2, args2, file2) = info2
Daniel Veillard26f1dcc2002-02-03 16:53:19 +0000657 if file1 == file2:
658 if func1 < func2:
659 return -1
660 if func1 > func2:
661 return 1
Daniel Veillard3ce52572002-02-03 15:08:05 +0000662 if file1 == "python_accessor":
663 return -1
664 if file2 == "python_accessor":
665 return 1
Daniel Veillard1971ee22002-01-31 20:29:19 +0000666 if file1 < file2:
667 return -1
668 if file1 > file2:
669 return 1
Daniel Veillard1971ee22002-01-31 20:29:19 +0000670 return 0
671
672def writeDoc(name, args, indent, output):
673 if functions[name][0] == None or functions[name][0] == "":
674 return
675 val = functions[name][0]
676 val = string.replace(val, "NULL", "None");
677 output.write(indent)
678 output.write('"""')
679 while len(val) > 60:
680 str = val[0:60]
681 i = string.rfind(str, " ");
682 if i < 0:
683 i = 60
684 str = val[0:i]
685 val = val[i:]
686 output.write(str)
687 output.write('\n ');
688 output.write(indent)
689 output.write(val);
690 output.write('"""\n')
691
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000692txt.write("#\n# Global functions of the module\n#\n\n")
Daniel Veillard36ed5292002-01-30 23:49:06 +0000693if function_classes.has_key("None"):
Daniel Veillard1971ee22002-01-31 20:29:19 +0000694 flist = function_classes["None"]
695 flist.sort(functionCompare)
696 oldfile = ""
697 for info in flist:
Daniel Veillard36ed5292002-01-30 23:49:06 +0000698 (index, func, name, ret, args, file) = info
Daniel Veillard1971ee22002-01-31 20:29:19 +0000699 if file != oldfile:
700 classes.write("#\n# Functions from module %s\n#\n\n" % file)
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000701 txt.write("\n# functions from module %s\n" % file)
Daniel Veillard1971ee22002-01-31 20:29:19 +0000702 oldfile = file
Daniel Veillard36ed5292002-01-30 23:49:06 +0000703 classes.write("def %s(" % func)
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000704 txt.write("%s()\n" % func);
Daniel Veillard36ed5292002-01-30 23:49:06 +0000705 n = 0
706 for arg in args:
707 if n != 0:
708 classes.write(", ")
709 classes.write("%s" % arg[0])
710 n = n + 1
711 classes.write("):\n")
Daniel Veillard1971ee22002-01-31 20:29:19 +0000712 writeDoc(name, args, ' ', classes);
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000713
714 for arg in args:
715 if classes_type.has_key(arg[1]):
716 classes.write(" if %s == None: %s__o = None\n" %
717 (arg[0], arg[0]))
718 classes.write(" else: %s__o = %s%s\n" %
719 (arg[0], arg[0], classes_type[arg[1]][0]))
Daniel Veillard36ed5292002-01-30 23:49:06 +0000720 if ret[0] != "void":
721 classes.write(" ret = ");
722 else:
723 classes.write(" ");
724 classes.write("_libxml.%s(" % name)
725 n = 0
726 for arg in args:
727 if n != 0:
728 classes.write(", ");
729 classes.write("%s" % arg[0])
730 if classes_type.has_key(arg[1]):
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000731 classes.write("__o");
Daniel Veillard36ed5292002-01-30 23:49:06 +0000732 n = n + 1
733 classes.write(")\n");
734 if ret[0] != "void":
735 if classes_type.has_key(ret[0]):
736 classes.write(" if ret == None: return None\n");
737 classes.write(" return ");
738 classes.write(classes_type[ret[0]][1] % ("ret"));
739 classes.write("\n");
740 else:
741 classes.write(" return ret\n");
742 classes.write("\n");
743
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000744txt.write("\n\n#\n# Set of classes of the module\n#\n\n")
Daniel Veillard9589d452002-02-02 10:28:17 +0000745for classname in classes_list:
Daniel Veillard36ed5292002-01-30 23:49:06 +0000746 if classname == "None":
747 pass
748 else:
Daniel Veillard1971ee22002-01-31 20:29:19 +0000749 if classes_ancestor.has_key(classname):
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000750 txt.write("\n\nClass %s(%s)\n" % (classname,
751 classes_ancestor[classname]))
Daniel Veillard1971ee22002-01-31 20:29:19 +0000752 classes.write("class %s(%s):\n" % (classname,
753 classes_ancestor[classname]))
Daniel Veillard36ed5292002-01-30 23:49:06 +0000754 classes.write(" def __init__(self, _obj=None):\n")
755 classes.write(" self._o = None\n")
Daniel Veillard1971ee22002-01-31 20:29:19 +0000756 classes.write(" %s.__init__(self, _obj=_obj)\n\n" % (
757 classes_ancestor[classname]))
Daniel Veillard3ce52572002-02-03 15:08:05 +0000758 if classes_ancestor[classname] == "xmlCore" or \
759 classes_ancestor[classname] == "xmlNode":
760 classes.write(" def __repr__(self):\n")
761 format = "%s:%%s" % (classname)
762 classes.write(" return \"%s\" %% (self.name)\n\n" % (
763 format))
Daniel Veillard36ed5292002-01-30 23:49:06 +0000764 else:
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000765 txt.write("Class %s()\n" % (classname))
Daniel Veillard1971ee22002-01-31 20:29:19 +0000766 classes.write("class %s:\n" % (classname))
Daniel Veillard36ed5292002-01-30 23:49:06 +0000767 classes.write(" def __init__(self, _obj=None):\n")
768 classes.write(" if _obj != None:self._o = _obj;return\n")
769 classes.write(" self._o = None\n\n");
Daniel Veillard1971ee22002-01-31 20:29:19 +0000770 if classes_destructors.has_key(classname):
771 classes.write(" def __del__(self):\n")
772 classes.write(" if self._o != None:\n")
773 classes.write(" _libxml.%s(self._o)\n" %
774 classes_destructors[classname]);
775 classes.write(" self._o = None\n\n");
776 flist = function_classes[classname]
777 flist.sort(functionCompare)
778 oldfile = ""
779 for info in flist:
Daniel Veillard36ed5292002-01-30 23:49:06 +0000780 (index, func, name, ret, args, file) = info
Daniel Veillard1971ee22002-01-31 20:29:19 +0000781 if file != oldfile:
Daniel Veillard3ce52572002-02-03 15:08:05 +0000782 if file == "python_accessor":
783 classes.write(" # accessors for %s\n" % (classname))
784 txt.write(" # accessors\n")
785 else:
786 classes.write(" #\n")
787 classes.write(" # %s functions from module %s\n" % (
788 classname, file))
789 txt.write("\n # functions from module %s\n" % file)
790 classes.write(" #\n\n")
Daniel Veillard1971ee22002-01-31 20:29:19 +0000791 oldfile = file
Daniel Veillard36ed5292002-01-30 23:49:06 +0000792 classes.write(" def %s(self" % func)
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000793 txt.write(" %s()\n" % func);
Daniel Veillard36ed5292002-01-30 23:49:06 +0000794 n = 0
795 for arg in args:
796 if n != index:
797 classes.write(", %s" % arg[0])
798 n = n + 1
799 classes.write("):\n")
Daniel Veillard1971ee22002-01-31 20:29:19 +0000800 writeDoc(name, args, ' ', classes);
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000801 n = 0
802 for arg in args:
803 if classes_type.has_key(arg[1]):
804 if n != index:
805 classes.write(" if %s == None: %s__o = None\n" %
806 (arg[0], arg[0]))
807 classes.write(" else: %s__o = %s%s\n" %
808 (arg[0], arg[0], classes_type[arg[1]][0]))
809 n = n + 1
Daniel Veillard36ed5292002-01-30 23:49:06 +0000810 if ret[0] != "void":
811 classes.write(" ret = ");
812 else:
813 classes.write(" ");
814 classes.write("_libxml.%s(" % name)
815 n = 0
816 for arg in args:
817 if n != 0:
818 classes.write(", ");
819 if n != index:
820 classes.write("%s" % arg[0])
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000821 if classes_type.has_key(arg[1]):
822 classes.write("__o");
Daniel Veillard36ed5292002-01-30 23:49:06 +0000823 else:
824 classes.write("self");
Daniel Veillard36eea2d2002-02-04 00:17:01 +0000825 if classes_type.has_key(arg[1]):
826 classes.write(classes_type[arg[1]][0])
Daniel Veillard36ed5292002-01-30 23:49:06 +0000827 n = n + 1
828 classes.write(")\n");
829 if ret[0] != "void":
830 if classes_type.has_key(ret[0]):
831 classes.write(" if ret == None: return None\n");
832 classes.write(" return ");
833 classes.write(classes_type[ret[0]][1] % ("ret"));
834 classes.write("\n");
Daniel Veillard1971ee22002-01-31 20:29:19 +0000835 elif converter_type.has_key(ret[0]):
836 classes.write(" if ret == None: return None\n");
837 classes.write(" return ");
838 classes.write(converter_type[ret[0]] % ("ret"));
839 classes.write("\n");
Daniel Veillard36ed5292002-01-30 23:49:06 +0000840 else:
841 classes.write(" return ret\n");
842 classes.write("\n");
843
Daniel Veillard253aa2c2002-02-02 09:17:16 +0000844txt.close()
Daniel Veillard36ed5292002-01-30 23:49:06 +0000845classes.close()