1#!/usr/bin/python -u
2#
3# generate python wrappers from the XML API description
4#
5
6functions = {}
7enums = {} # { enumType: { enumConstant: enumValue } }
8
9import string
10
11#######################################################################
12#
13#  That part if purely the API acquisition phase from the
14#  XML API description
15#
16#######################################################################
17import os
18import xml.sax
19
20debug = 0
21srcdir = os.getenv("SRCDIR", ".")
22
23def getparser():
24    # Attach parser to an unmarshalling object. return both objects.
25    target = docParser()
26    parser = xml.sax.make_parser()
27    parser.setContentHandler(target)
28    return parser, target
29
30class docParser(xml.sax.handler.ContentHandler):
31    def __init__(self):
32        self._methodname = None
33        self._data = []
34        self.in_function = 0
35
36        self.startElement = self.start
37        self.endElement = self.end
38        self.characters = self.data
39
40    def close(self):
41        if debug:
42            print "close"
43
44    def getmethodname(self):
45        return self._methodname
46
47    def data(self, text):
48        if debug:
49            print "data %s" % text
50        self._data.append(text)
51
52    def start(self, tag, attrs):
53        if debug:
54            print "start %s, %s" % (tag, attrs)
55        if tag == 'function':
56            self._data = []
57            self.in_function = 1
58            self.function = None
59            self.function_args = []
60            self.function_descr = None
61            self.function_return = None
62            self.function_file = None
63            if attrs.has_key('name'):
64                self.function = attrs['name']
65            if attrs.has_key('file'):
66                self.function_file = attrs['file']
67        elif tag == 'info':
68            self._data = []
69        elif tag == 'arg':
70            if self.in_function == 1:
71                self.function_arg_name = None
72                self.function_arg_type = None
73                self.function_arg_info = None
74                if attrs.has_key('name'):
75                    self.function_arg_name = attrs['name']
76                if attrs.has_key('type'):
77                    self.function_arg_type = attrs['type']
78                if attrs.has_key('info'):
79                    self.function_arg_info = attrs['info']
80        elif tag == 'return':
81            if self.in_function == 1:
82                self.function_return_type = None
83                self.function_return_info = None
84                self.function_return_field = None
85                if attrs.has_key('type'):
86                    self.function_return_type = attrs['type']
87                if attrs.has_key('info'):
88                    self.function_return_info = attrs['info']
89                if attrs.has_key('field'):
90                    self.function_return_field = attrs['field']
91        elif tag == 'enum':
92            enum(attrs['type'],attrs['name'],attrs['value'])
93
94
95
96    def end(self, tag):
97        if debug:
98            print "end %s" % tag
99        if tag == 'function':
100            if self.function != None:
101                function(self.function, self.function_descr,
102                         self.function_return, self.function_args,
103                         self.function_file)
104                self.in_function = 0
105        elif tag == 'arg':
106            if self.in_function == 1:
107                self.function_args.append([self.function_arg_name,
108                                           self.function_arg_type,
109                                           self.function_arg_info])
110        elif tag == 'return':
111            if self.in_function == 1:
112                self.function_return = [self.function_return_type,
113                                        self.function_return_info,
114                                        self.function_return_field]
115        elif tag == 'info':
116            str = ''
117            for c in self._data:
118                str = str + c
119            if self.in_function == 1:
120                self.function_descr = str
121
122
123def function(name, desc, ret, args, file):
124    functions[name] = (desc, ret, args, file)
125
126def enum(type, name, value):
127    if not enums.has_key(type):
128        enums[type] = {}
129    enums[type][name] = value
130
131#######################################################################
132#
133#  Some filtering rukes to drop functions/types which should not
134#  be exposed as-is on the Python interface
135#
136#######################################################################
137
138skipped_modules = {
139    'xmlmemory': None,
140    'DOCBparser': None,
141    'SAX': None,
142    'hash': None,
143    'list': None,
144    'threads': None,
145    'xpointer': None,
146    'transform': None,
147}
148skipped_types = {
149    'int *': "usually a return type",
150    'xmlSAXHandlerPtr': "not the proper interface for SAX",
151    'htmlSAXHandlerPtr': "not the proper interface for SAX",
152    'xmlRMutexPtr': "thread specific, skipped",
153    'xmlMutexPtr': "thread specific, skipped",
154    'xmlGlobalStatePtr': "thread specific, skipped",
155    'xmlListPtr': "internal representation not suitable for python",
156    'xmlBufferPtr': "internal representation not suitable for python",
157    'FILE *': None,
158}
159
160#######################################################################
161#
162#  Table of remapping to/from the python type or class to the C
163#  counterpart.
164#
165#######################################################################
166
167py_types = {
168    'void': (None, None, None, None, None),
169    'int':  ('i', None, "int", "int", "libxml_"),
170    'long':  ('l', None, "long", "long", "libxml_"),
171    'double':  ('d', None, "double", "double", "libxml_"),
172    'unsigned int':  ('i', None, "int", "int", "libxml_"),
173    'xmlChar':  ('c', None, "int", "int", "libxml_"),
174    'unsigned char *':  ('z', None, "charPtr", "char *", "libxml_"),
175    'char *':  ('z', None, "charPtr", "char *", "libxml_"),
176    'const char *':  ('z', None, "charPtrConst", "const char *", "libxml_"),
177    'xmlChar *':  ('z', None, "xmlCharPtr", "xmlChar *", "libxml_"),
178    'const xmlChar *':  ('z', None, "xmlCharPtrConst", "const xmlChar *", "libxml_"),
179    'xmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
180    'const xmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
181    'xmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
182    'const xmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
183    'xmlDtdPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
184    'const xmlDtdPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
185    'xmlDtd *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
186    'const xmlDtd *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
187    'xmlAttrPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
188    'const xmlAttrPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
189    'xmlAttr *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
190    'const xmlAttr *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
191    'xmlEntityPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
192    'const xmlEntityPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
193    'xmlEntity *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
194    'const xmlEntity *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
195    'xmlElementPtr':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr", "libxml_"),
196    'const xmlElementPtr':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr", "libxml_"),
197    'xmlElement *':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr", "libxml_"),
198    'const xmlElement *':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr", "libxml_"),
199    'xmlAttributePtr':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr", "libxml_"),
200    'const xmlAttributePtr':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr", "libxml_"),
201    'xmlAttribute *':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr", "libxml_"),
202    'const xmlAttribute *':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr", "libxml_"),
203    'xmlNsPtr':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr", "libxml_"),
204    'const xmlNsPtr':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr", "libxml_"),
205    'xmlNs *':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr", "libxml_"),
206    'const xmlNs *':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr", "libxml_"),
207    'xmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"),
208    'const xmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"),
209    'xmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"),
210    'const xmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"),
211    'htmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"),
212    'const htmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"),
213    'htmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"),
214    'const htmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr", "libxml_"),
215    'htmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
216    'const htmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
217    'htmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
218    'const htmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr", "libxml_"),
219    'xmlXPathContextPtr':  ('O', "xmlXPathContext", "xmlXPathContextPtr", "xmlXPathContextPtr", "libxml_"),
220    'xmlXPathParserContextPtr':  ('O', "xmlXPathParserContext", "xmlXPathParserContextPtr", "xmlXPathParserContextPtr", "libxml_"),
221    'xmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr", "libxml_"),
222    'xmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr", "libxml_"),
223    'htmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr", "libxml_"),
224    'htmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr", "libxml_"),
225    'xmlCatalogPtr': ('O', "catalog", "xmlCatalogPtr", "xmlCatalogPtr"),
226    'FILE *': ('O', "File", "FILEPtr", "FILE *", "libxml_"),
227    'xsltTransformContextPtr':  ('O', "transformCtxt", "xsltTransformContextPtr", "xsltTransformContextPtr", "libxslt_"),
228    'xsltTransformContext *':  ('O', "transformCtxt", "xsltTransformContextPtr", "xsltTransformContextPtr", "libxslt_"),
229    'xsltStylePreCompPtr':  ('O', "compiledStyle", "xsltStylePreCompPtr", "xsltStylePreCompPtr", "libxslt_"),
230    'xsltStylePreComp *':  ('O', "compiledStyle", "xsltStylePreCompPtr", "xsltStylePreCompPtr", "libxslt_"),
231    'xsltStylesheetPtr':  ('O', "stylesheet", "xsltStylesheetPtr", "xsltStylesheetPtr", "libxslt_"),
232    'xsltStylesheet *':  ('O', "stylesheet", "xsltStylesheetPtr", "xsltStylesheetPtr", "libxslt_"),
233    'xmlXPathContext *':  ('O', "xpathContext", "xmlXPathContextPtr", "xmlXPathContextPtr", "libxslt_"),
234}
235
236py_return_types = {
237    'xmlXPathObjectPtr':  ('O', "foo", "xmlXPathObjectPtr", "xmlXPathObjectPtr", "libxml_"),
238}
239
240unknown_types = {}
241
242#######################################################################
243#
244#  This part writes the C <-> Python stubs libxslt-py.[ch] and
245#  the table libxslt-export.c to add when registrering the Python module
246#
247#######################################################################
248
249def skip_function(name):
250    if name[0:12] == "xmlXPathWrap":
251        return 1
252    if name == "xsltMatchPattern":
253        return 1
254#    if name[0:11] == "xmlXPathNew":
255#        return 1
256    return 0
257
258def print_function_wrapper(name, output, export, include):
259    global py_types
260    global unknown_types
261    global functions
262    global skipped_modules
263
264    try:
265        (desc, ret, args, file) = functions[name]
266    except:
267        print "failed to get function %s infos"
268        return
269
270    if skipped_modules.has_key(file):
271        return 0
272    if skip_function(name) == 1:
273        return 0
274
275    c_call = ""
276    format=""
277    format_args=""
278    c_args=""
279    c_return=""
280    c_convert=""
281    for arg in args:
282        # This should be correct
283        if arg[1][0:6] == "const ":
284            arg[1] = arg[1][6:]
285        c_args = c_args + "    %s %s;\n" % (arg[1], arg[0])
286        if py_types.has_key(arg[1]):
287            (f, t, n, c, p) = py_types[arg[1]]
288            if f != None:
289                format = format + f
290            if t != None:
291                format_args = format_args + ", &pyobj_%s" % (arg[0])
292                c_args = c_args + "    PyObject *pyobj_%s;\n" % (arg[0])
293                c_convert = c_convert + \
294                   "    %s = (%s) Py%s_Get(pyobj_%s);\n" % (arg[0],
295                   arg[1], t, arg[0])
296            else:
297                format_args = format_args + ", &%s" % (arg[0])
298            if c_call != "":
299                c_call = c_call + ", "
300            c_call = c_call + "%s" % (arg[0])
301        else:
302            if skipped_types.has_key(arg[1]):
303                return 0
304            if unknown_types.has_key(arg[1]):
305                lst = unknown_types[arg[1]]
306                lst.append(name)
307            else:
308                unknown_types[arg[1]] = [name]
309            return -1
310    if format != "":
311        format = format + ":%s" % (name)
312
313    if ret[0] == 'void':
314        if file == "python_accessor":
315            if args[1][1] == "char *" or args[1][1] == "xmlChar *":
316                c_call = "\n    if (%s->%s != NULL) xmlFree(%s->%s);\n" % (
317                                 args[0][0], args[1][0], args[0][0], args[1][0])
318                c_call = c_call + "    %s->%s = xmlStrdup((const xmlChar *)%s);\n" % (args[0][0],
319                                 args[1][0], args[1][0])
320            else:
321                c_call = "\n    %s->%s = %s;\n" % (args[0][0], args[1][0],
322                                                   args[1][0])
323        else:
324            c_call = "\n    %s(%s);\n" % (name, c_call)
325        ret_convert = "    Py_INCREF(Py_None);\n    return(Py_None);\n"
326    elif py_types.has_key(ret[0]):
327        (f, t, n, c, p) = py_types[ret[0]]
328        c_return = "    %s c_retval;\n" % (ret[0])
329        if file == "python_accessor" and ret[2] != None:
330            c_call = "\n    c_retval = %s->%s;\n" % (args[0][0], ret[2])
331        else:
332            c_call = "\n    c_retval = %s(%s);\n" % (name, c_call)
333        ret_convert = "    py_retval = %s%sWrap((%s) c_retval);\n" % (p,n,c)
334        ret_convert = ret_convert + "    return(py_retval);\n"
335    elif py_return_types.has_key(ret[0]):
336        (f, t, n, c, p) = py_return_types[ret[0]]
337        c_return = "    %s c_retval;\n" % (ret[0])
338        if file == "python_accessor" and ret[2] != None:
339            c_call = "\n    c_retval = %s->%s;\n" % (args[0][0], ret[2])
340        else:
341            c_call = "\n    c_retval = %s(%s);\n" % (name, c_call)
342        ret_convert = "    py_retval = %s%sWrap((%s) c_retval);\n" % (p,n,c)
343        ret_convert = ret_convert + "    return(py_retval);\n"
344    else:
345        if skipped_types.has_key(ret[0]):
346            return 0
347        if unknown_types.has_key(ret[0]):
348            lst = unknown_types[ret[0]]
349            lst.append(name)
350        else:
351            unknown_types[ret[0]] = [name]
352        return -1
353
354    include.write("PyObject * ")
355    include.write("libxslt_%s(PyObject *self, PyObject *args);\n" % (name))
356
357    export.write("    { (char *)\"%s\", libxslt_%s, METH_VARARGS, NULL },\n" % (name, name))
358
359    if file == "python":
360        # Those have been manually generated
361        return 1
362    if file == "python_accessor" and ret[0] != "void" and ret[2] == None:
363        # Those have been manually generated
364        return 1
365
366    output.write("PyObject *\n")
367    output.write("libxslt_%s(PyObject *self ATTRIBUTE_UNUSED," % (name))
368    output.write(" PyObject *args")
369    if format == "":
370        output.write(" ATTRIBUTE_UNUSED")
371    output.write(") {\n")
372    if ret[0] != 'void':
373        output.write("    PyObject *py_retval;\n")
374    if c_return != "":
375        output.write(c_return)
376    if c_args != "":
377        output.write(c_args)
378    if format != "":
379        output.write("\n    if (!PyArg_ParseTuple(args, (char *)\"%s\"%s))\n" %
380                     (format, format_args))
381        output.write("        return(NULL);\n")
382    if c_convert != "":
383        output.write(c_convert)
384
385    output.write(c_call)
386    output.write(ret_convert)
387    output.write("}\n\n")
388    return 1
389
390def buildStubs():
391    global py_types
392    global py_return_types
393    global unknown_types
394
395    try:
396        f = open("%s/libxslt-api.xml" % srcdir)
397        data = f.read()
398        (parser, target)  = getparser()
399        parser.feed(data)
400        parser.close()
401    except IOError, msg:
402        try:
403            f = open("%s/../doc/libxslt-api.xml" % srcdir)
404            data = f.read()
405            (parser, target)  = getparser()
406            parser.feed(data)
407            parser.close()
408        except IOError, msg:
409            print "../doc/libxslt-api.xml", ":", msg
410
411    n = len(functions.keys())
412    print "Found %d functions in libxslt-api.xml" % (n)
413
414    py_types['pythonObject'] = ('O', "pythonObject", "pythonObject",
415                                "pythonObject", "libxml_")
416    try:
417        f = open("%s/libxslt-python-api.xml" % srcdir)
418        data = f.read()
419        (parser, target)  = getparser()
420        parser.feed(data)
421        parser.close()
422    except IOError, msg:
423        print "libxslt-python-api.xml", ":", msg
424
425
426    print "Found %d functions in libxslt-python-api.xml" % (
427          len(functions.keys()) - n)
428    nb_wrap = 0
429    failed = 0
430    skipped = 0
431
432    include = open("libxslt-py.h", "w")
433    include.write("/* Generated */\n\n")
434    export = open("libxslt-export.c", "w")
435    export.write("/* Generated */\n\n")
436    wrapper = open("libxslt-py.c", "w")
437    wrapper.write("/* Generated */\n\n")
438#    wrapper.write("#include \"config.h\"\n")
439    wrapper.write("#include <libxslt/xsltconfig.h>\n")
440    wrapper.write("#include \"libxslt_wrap.h\"\n")
441    wrapper.write("#include \"libxslt-py.h\"\n\n")
442    for function in functions.keys():
443        ret = print_function_wrapper(function, wrapper, export, include)
444        if ret < 0:
445            failed = failed + 1
446            del functions[function]
447        if ret == 0:
448            skipped = skipped + 1
449            del functions[function]
450        if ret == 1:
451            nb_wrap = nb_wrap + 1
452    include.close()
453    export.close()
454    wrapper.close()
455
456    print "Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap,
457                                                              failed, skipped)
458    print "Missing type converters:"
459    for type in unknown_types.keys():
460        print "%s:%d " % (type, len(unknown_types[type])),
461    print
462
463#######################################################################
464#
465#  This part writes part of the Python front-end classes based on
466#  mapping rules between types and classes and also based on function
467#  renaming to get consistent function names at the Python level
468#
469#######################################################################
470
471#
472# The type automatically remapped to generated classes
473#
474libxml2_classes_type = {
475    "xmlNodePtr": ("._o", "xmlNode(_obj=%s)", "xmlNode"),
476    "xmlNode *": ("._o", "xmlNode(_obj=%s)", "xmlNode"),
477    "xmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
478    "xmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
479    "htmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
480    "htmlxmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
481    "xmlAttrPtr": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"),
482    "xmlAttr *": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"),
483    "xmlNsPtr": ("._o", "xmlNs(_obj=%s)", "xmlNs"),
484    "xmlNs *": ("._o", "xmlNs(_obj=%s)", "xmlNs"),
485    "xmlDtdPtr": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"),
486    "xmlDtd *": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"),
487    "xmlEntityPtr": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"),
488    "xmlEntity *": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"),
489    "xmlElementPtr": ("._o", "xmlElement(_obj=%s)", "xmlElement"),
490    "xmlElement *": ("._o", "xmlElement(_obj=%s)", "xmlElement"),
491    "xmlAttributePtr": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"),
492    "xmlAttribute *": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"),
493    "xmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
494    "xmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
495    "xmlCatalogPtr": ("._o", "catalog(_obj=%s)", "catalog"),
496}
497
498classes_type = {
499    "xsltTransformContextPtr": ("._o", "transformCtxt(_obj=%s)", "transformCtxt"),
500    "xsltTransformContext *": ("._o", "transformCtxt(_obj=%s)", "transformCtxt"),
501    "xsltStylesheetPtr": ("._o", "stylesheet(_obj=%s)", "stylesheet"),
502    "xsltStylesheet *": ("._o", "stylesheet(_obj=%s)", "stylesheet"),
503    "xmlXPathContextPtr": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
504    "xmlXPathContext *": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
505    "xmlXPathParserContextPtr": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"),
506    "xmlXPathParserContext *": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"),
507}
508
509converter_type = {
510    "xmlXPathObjectPtr": "libxml2.xpathObjectRet(%s)",
511}
512
513primary_classes = ["xpathParserContext", "xpathContext", "transformCtxt", "stylesheet"]
514
515classes_ancestor = {
516    "xpathContext" : "libxml2.xpathContext",
517    "xpathParserContext" : "libxml2.xpathParserContext",
518    "transformCtxt": "transformCtxtBase",
519    "stylesheet": "stylesheetBase",
520}
521classes_destructors = {
522    "xpathContext" : "pass"
523}
524
525function_classes = {}
526ctypes = []
527classes_list = []
528
529
530def nameFixup(name, classe, type, file):
531    listname = classe + "List"
532    ll = len(listname)
533    l = len(classe)
534    if name[0:l] == listname:
535        func = name[l:]
536        func = string.lower(func[0:1]) + func[1:]
537    elif name[0:12] == "xmlParserGet" and file == "python_accessor":
538        func = name[12:]
539        func = string.lower(func[0:1]) + func[1:]
540    elif name[0:12] == "xmlParserSet" and file == "python_accessor":
541        func = name[12:]
542        func = string.lower(func[0:1]) + func[1:]
543    elif name[0:10] == "xmlNodeGet" and file == "python_accessor":
544        func = name[10:]
545        func = string.lower(func[0:1]) + func[1:]
546    elif name[0:18] == "xsltXPathParserGet" and file == "python_accessor":
547        func = name[18:]
548        func = string.lower(func[0:1]) + func[1:]
549    elif name[0:12] == "xsltXPathGet" and file == "python_accessor":
550        func = name[12:]
551        func = string.lower(func[0:1]) + func[1:]
552    elif name[0:16] == "xsltTransformGet" and file == "python_accessor":
553        func = name[16:]
554        func = string.lower(func[0:1]) + func[1:]
555    elif name[0:16] == "xsltTransformSet" and file == "python_accessor":
556        func = name[13:]
557        func = string.lower(func[0:1]) + func[1:]
558    elif name[0:17] == "xsltStylesheetGet" and file == "python_accessor":
559        func = name[17:]
560        func = string.lower(func[0:1]) + func[1:]
561    elif name[0:17] == "xsltStylesheetSet" and file == "python_accessor":
562        func = name[14:]
563        func = string.lower(func[0:1]) + func[1:]
564    elif name[0:l] == classe:
565        func = name[l:]
566        func = string.lower(func[0:1]) + func[1:]
567    elif name[0:7] == "libxml_":
568        func = name[7:]
569        func = string.lower(func[0:1]) + func[1:]
570    elif name[0:8] == "libxslt_":
571        func = name[8:]
572        func = string.lower(func[0:1]) + func[1:]
573    elif name[0:6] == "xmlGet":
574        func = name[6:]
575        func = string.lower(func[0:1]) + func[1:]
576    elif name[0:3] == "xml":
577        func = name[3:]
578        func = string.lower(func[0:1]) + func[1:]
579    elif name[0:7] == "xsltGet":
580        func = name[7:]
581        func = string.lower(func[0:1]) + func[1:]
582    elif name[0:4] == "xslt":
583        func = name[4:]
584        func = string.lower(func[0:1]) + func[1:]
585    else:
586        func = name
587    if func[0:5] == "xPath":
588        func = "xpath" + func[5:]
589    elif func[0:4] == "xPtr":
590        func = "xpointer" + func[4:]
591    elif func[0:8] == "xInclude":
592        func = "xinclude" + func[8:]
593    elif func[0:2] == "iD":
594        func = "ID" + func[2:]
595    elif func[0:3] == "uRI":
596        func = "URI" + func[3:]
597    elif func[0:4] == "uTF8":
598        func = "UTF8" + func[4:]
599    return func
600
601def functionCompare(info1, info2):
602    (index1, func1, name1, ret1, args1, file1) = info1
603    (index2, func2, name2, ret2, args2, file2) = info2
604    if file1 == file2:
605        if func1 < func2:
606            return -1
607        if func1 > func2:
608            return 1
609    if file1 == "python_accessor":
610        return -1
611    if file2 == "python_accessor":
612        return 1
613    if file1 < file2:
614        return -1
615    if file1 > file2:
616        return 1
617    return 0
618
619def writeDoc(name, args, indent, output):
620     if functions[name][0] == None or functions[name][0] == "":
621         return
622     val = functions[name][0]
623     val = string.replace(val, "NULL", "None")
624     output.write(indent)
625     output.write('"""')
626     while len(val) > 60:
627         if val[0] == " ":
628             val = val[1:]
629             continue
630         str = val[0:60]
631         i = string.rfind(str, " ")
632         if i < 0:
633             i = 60
634         str = val[0:i]
635         val = val[i:]
636         output.write(str)
637         output.write('\n  ')
638         output.write(indent)
639     output.write(val)
640     output.write('"""\n')
641
642def buildWrappers():
643    global ctypes
644    global py_types
645    global py_return_types
646    global unknown_types
647    global functions
648    global function_classes
649    global libxml2_classes_type
650    global classes_type
651    global classes_list
652    global converter_type
653    global primary_classes
654    global converter_type
655    global classes_ancestor
656    global converter_type
657    global primary_classes
658    global classes_ancestor
659    global classes_destructors
660
661    function_classes["None"] = []
662    for type in classes_type.keys():
663        function_classes[classes_type[type][2]] = []
664
665    #
666    # Build the list of C types to look for ordered to start with
667    # primary classes
668    #
669    ctypes_processed = {}
670    classes_processed = {}
671    for classe in primary_classes:
672        classes_list.append(classe)
673        classes_processed[classe] = ()
674        for type in classes_type.keys():
675            tinfo = classes_type[type]
676            if tinfo[2] == classe:
677                ctypes.append(type)
678                ctypes_processed[type] = ()
679    for type in classes_type.keys():
680        if ctypes_processed.has_key(type):
681            continue
682        tinfo = classes_type[type]
683        if not classes_processed.has_key(tinfo[2]):
684            classes_list.append(tinfo[2])
685            classes_processed[tinfo[2]] = ()
686
687        ctypes.append(type)
688        ctypes_processed[type] = ()
689
690    for name in functions.keys():
691        found = 0
692        (desc, ret, args, file) = functions[name]
693        for type in ctypes:
694            classe = classes_type[type][2]
695
696            if name[0:4] == "xslt" and len(args) >= 1 and args[0][1] == type:
697                found = 1
698                func = nameFixup(name, classe, type, file)
699                info = (0, func, name, ret, args, file)
700                function_classes[classe].append(info)
701            elif name[0:4] == "xslt" and len(args) >= 2 and args[1][1] == type:
702                found = 1
703                func = nameFixup(name, classe, type, file)
704                info = (1, func, name, ret, args, file)
705                function_classes[classe].append(info)
706            elif name[0:4] == "xslt" and len(args) >= 3 and args[2][1] == type:
707                found = 1
708                func = nameFixup(name, classe, type, file)
709                info = (2, func, name, ret, args, file)
710                function_classes[classe].append(info)
711        if found == 1:
712            continue
713        if name[0:8] == "xmlXPath":
714            continue
715        if name[0:6] == "xmlStr":
716            continue
717        if name[0:10] == "xmlCharStr":
718            continue
719        func = nameFixup(name, "None", file, file)
720        info = (0, func, name, ret, args, file)
721        function_classes['None'].append(info)
722
723    classes = open("libxsltclass.py", "w")
724    txt = open("libxsltclass.txt", "w")
725    txt.write("          Generated Classes for libxslt-python\n\n")
726
727    txt.write("#\n# Global functions of the module\n#\n\n")
728    if function_classes.has_key("None"):
729        flist = function_classes["None"]
730        flist.sort(functionCompare)
731        oldfile = ""
732        for info in flist:
733            (index, func, name, ret, args, file) = info
734            if file != oldfile:
735                classes.write("#\n# Functions from module %s\n#\n\n" % file)
736                txt.write("\n# functions from module %s\n" % file)
737                oldfile = file
738            classes.write("def %s(" % func)
739            txt.write("%s()\n" % func)
740            n = 0
741            for arg in args:
742                if n != 0:
743                    classes.write(", ")
744                classes.write("%s" % arg[0])
745                n = n + 1
746            classes.write("):\n")
747            writeDoc(name, args, '    ', classes)
748
749            for arg in args:
750                if classes_type.has_key(arg[1]):
751                    classes.write("    if %s == None: %s__o = None\n" %
752                                  (arg[0], arg[0]))
753                    classes.write("    else: %s__o = %s%s\n" %
754                                  (arg[0], arg[0], classes_type[arg[1]][0]))
755                elif libxml2_classes_type.has_key(arg[1]):
756                    classes.write("    if %s == None: %s__o = None\n" %
757                                  (arg[0], arg[0]))
758                    classes.write("    else: %s__o = %s%s\n" %
759                                  (arg[0], arg[0], libxml2_classes_type[arg[1]][0]))
760            if ret[0] != "void":
761                classes.write("    ret = ")
762            else:
763                classes.write("    ")
764            classes.write("libxsltmod.%s(" % name)
765            n = 0
766            for arg in args:
767                if n != 0:
768                    classes.write(", ")
769                classes.write("%s" % arg[0])
770                if classes_type.has_key(arg[1]):
771                    classes.write("__o")
772                if libxml2_classes_type.has_key(arg[1]):
773                    classes.write("__o")
774                n = n + 1
775            classes.write(")\n")
776            if ret[0] != "void":
777                if classes_type.has_key(ret[0]):
778                    classes.write("    if ret == None: return None\n")
779                    classes.write("    return ")
780                    classes.write(classes_type[ret[0]][1] % ("ret"))
781                    classes.write("\n")
782                elif libxml2_classes_type.has_key(ret[0]):
783                    classes.write("    if ret == None: return None\n")
784                    classes.write("    return libxml2.")
785                    classes.write(libxml2_classes_type[ret[0]][1] % ("ret"))
786                    classes.write("\n")
787                else:
788                    classes.write("    return ret\n")
789            classes.write("\n")
790
791    txt.write("\n\n#\n# Set of classes of the module\n#\n\n")
792    for classname in classes_list:
793        if classname == "None":
794            pass
795        else:
796            if classes_ancestor.has_key(classname):
797                txt.write("\n\nClass %s(%s)\n" % (classname,
798                          classes_ancestor[classname]))
799                classes.write("class %s(%s):\n" % (classname,
800                              classes_ancestor[classname]))
801                classes.write("    def __init__(self, _obj=None):\n")
802                classes.write("        self._o = None\n")
803                classes.write("        %s.__init__(self, _obj=_obj)\n\n" % (
804                              classes_ancestor[classname]))
805                if classes_ancestor[classname] == "xmlCore" or \
806                   classes_ancestor[classname] == "xmlNode":
807                    classes.write("    def __repr__(self):\n")
808                    format = "%s:%%s" % (classname)
809                    classes.write("        return \"%s\" %% (self.name)\n\n" % (
810                                  format))
811            else:
812                txt.write("Class %s()\n" % (classname))
813                classes.write("class %s:\n" % (classname))
814                classes.write("    def __init__(self, _obj=None):\n")
815                classes.write("        if _obj != None:self._o = _obj;return\n")
816                classes.write("        self._o = None\n\n")
817            if classes_destructors.has_key(classname):
818                classes.write("    def __del__(self):\n")
819                if classes_destructors[classname] == "pass":
820                    classes.write("        pass\n")
821                else:
822                    classes.write("        if self._o != None:\n")
823                    classes.write("            libxsltmod.%s(self._o)\n" %
824                                  classes_destructors[classname])
825                    classes.write("        self._o = None\n\n")
826            flist = function_classes[classname]
827            flist.sort(functionCompare)
828            oldfile = ""
829            for info in flist:
830                (index, func, name, ret, args, file) = info
831                if file != oldfile:
832                    if file == "python_accessor":
833                        classes.write("    # accessors for %s\n" % (classname))
834                        txt.write("    # accessors\n")
835                    else:
836                        classes.write("    #\n")
837                        classes.write("    # %s functions from module %s\n" % (
838                                      classname, file))
839                        txt.write("\n    # functions from module %s\n" % file)
840                        classes.write("    #\n\n")
841                oldfile = file
842                classes.write("    def %s(self" % func)
843                txt.write("    %s()\n" % func)
844                n = 0
845                for arg in args:
846                    if n != index:
847                        classes.write(", %s" % arg[0])
848                    n = n + 1
849                classes.write("):\n")
850                writeDoc(name, args, '        ', classes)
851                n = 0
852                for arg in args:
853                    if classes_type.has_key(arg[1]):
854                        if n != index:
855                            classes.write("        if %s == None: %s__o = None\n" %
856                                          (arg[0], arg[0]))
857                            classes.write("        else: %s__o = %s%s\n" %
858                                          (arg[0], arg[0], classes_type[arg[1]][0]))
859                    elif libxml2_classes_type.has_key(arg[1]):
860                        classes.write("        if %s == None: %s__o = None\n" %
861                                      (arg[0], arg[0]))
862                        classes.write("        else: %s__o = %s%s\n" %
863                                      (arg[0], arg[0],
864                                       libxml2_classes_type[arg[1]][0]))
865                    n = n + 1
866                if ret[0] != "void":
867                    classes.write("        ret = ")
868                else:
869                    classes.write("        ")
870                classes.write("libxsltmod.%s(" % name)
871                n = 0
872                for arg in args:
873                    if n != 0:
874                        classes.write(", ")
875                    if n != index:
876                        classes.write("%s" % arg[0])
877                        if classes_type.has_key(arg[1]):
878                            classes.write("__o")
879                        elif libxml2_classes_type.has_key(arg[1]):
880                            classes.write("__o")
881                    else:
882                        classes.write("self")
883                        if classes_type.has_key(arg[1]):
884                            classes.write(classes_type[arg[1]][0])
885                        elif libxml2_classes_type.has_key(arg[1]):
886                            classes.write(libxml2_classes_type[arg[1]][0])
887                    n = n + 1
888                classes.write(")\n")
889                if ret[0] != "void":
890                    if classes_type.has_key(ret[0]):
891                        classes.write("        if ret == None: return None\n")
892                        classes.write("        return ")
893                        classes.write(classes_type[ret[0]][1] % ("ret"))
894                        classes.write("\n")
895                    elif libxml2_classes_type.has_key(ret[0]):
896                        classes.write("        if ret == None: return None\n")
897                        classes.write("        return libxml2.")
898                        classes.write(libxml2_classes_type[ret[0]][1] % ("ret"))
899                        classes.write("\n")
900                    elif converter_type.has_key(ret[0]):
901                        classes.write("        if ret == None: return None\n")
902                        classes.write("        return ")
903                        classes.write(converter_type[ret[0]] % ("ret"))
904                        classes.write("\n")
905                    else:
906                        classes.write("        return ret\n")
907                classes.write("\n")
908
909    #
910    # Generate enum constants
911    #
912    for type,enum in enums.items():
913        classes.write("# %s\n" % type)
914        items = enum.items()
915        items.sort(lambda i1,i2: cmp(long(i1[1]),long(i2[1])))
916        for name,value in items:
917            classes.write("%s = %s\n" % (name,value))
918        classes.write("\n");
919
920    txt.close()
921    classes.close()
922
923buildStubs()
924buildWrappers()
925