xref: /aosp_15_r20/external/libxml2/python/generator.py (revision 7c5688314b92172186c154356a6374bf7684c3ca)
1#!/usr/bin/env python3
2#
3# generate python wrappers from the XML API description
4#
5
6functions = {}
7enums = {} # { enumType: { enumConstant: enumValue } }
8
9import os
10import sys
11import string
12
13if __name__ == "__main__":
14    # launched as a script
15    srcPref = os.path.dirname(sys.argv[0])
16else:
17    # imported
18    srcPref = os.path.dirname(__file__)
19
20#######################################################################
21#
22#  That part if purely the API acquisition phase from the
23#  XML API description
24#
25#######################################################################
26import os
27import xml.sax
28
29debug = 0
30
31def getparser():
32    # Attach parser to an unmarshalling object. return both objects.
33    target = docParser()
34    parser = xml.sax.make_parser()
35    parser.setContentHandler(target)
36    return parser, target
37
38class docParser(xml.sax.handler.ContentHandler):
39    def __init__(self):
40        self._methodname = None
41        self._data = []
42        self.in_function = 0
43
44        self.startElement = self.start
45        self.endElement = self.end
46        self.characters = self.data
47
48    def close(self):
49        if debug:
50            print("close")
51
52    def getmethodname(self):
53        return self._methodname
54
55    def data(self, text):
56        if debug:
57            print("data %s" % text)
58        self._data.append(text)
59
60    def start(self, tag, attrs):
61        if debug:
62            print("start %s, %s" % (tag, attrs))
63        if tag == 'function':
64            self._data = []
65            self.in_function = 1
66            self.function = None
67            self.function_cond = None
68            self.function_args = []
69            self.function_descr = None
70            self.function_return = None
71            self.function_file = None
72            if 'name' in attrs.keys():
73                self.function = attrs['name']
74            if 'file' in attrs.keys():
75                self.function_file = attrs['file']
76        elif tag == 'cond':
77            self._data = []
78        elif tag == 'info':
79            self._data = []
80        elif tag == 'arg':
81            if self.in_function == 1:
82                self.function_arg_name = None
83                self.function_arg_type = None
84                self.function_arg_info = None
85                if 'name' in attrs.keys():
86                    self.function_arg_name = attrs['name']
87                if 'type' in attrs.keys():
88                    self.function_arg_type = attrs['type']
89                if 'info' in attrs.keys():
90                    self.function_arg_info = attrs['info']
91        elif tag == 'return':
92            if self.in_function == 1:
93                self.function_return_type = None
94                self.function_return_info = None
95                self.function_return_field = None
96                if 'type' in attrs.keys():
97                    self.function_return_type = attrs['type']
98                if 'info' in attrs.keys():
99                    self.function_return_info = attrs['info']
100                if 'field' in attrs.keys():
101                    self.function_return_field = attrs['field']
102        elif tag == 'enum':
103            enum(attrs['type'],attrs['name'],attrs['value'])
104
105    def end(self, tag):
106        if debug:
107            print("end %s" % tag)
108        if tag == 'function':
109            if self.function != None:
110                function(self.function, self.function_descr,
111                         self.function_return, self.function_args,
112                         self.function_file, self.function_cond)
113                self.in_function = 0
114        elif tag == 'arg':
115            if self.in_function == 1:
116                self.function_args.append([self.function_arg_name,
117                                           self.function_arg_type,
118                                           self.function_arg_info])
119        elif tag == 'return':
120            if self.in_function == 1:
121                self.function_return = [self.function_return_type,
122                                        self.function_return_info,
123                                        self.function_return_field]
124        elif tag == 'info':
125            str = ''
126            for c in self._data:
127                str = str + c
128            if self.in_function == 1:
129                self.function_descr = str
130        elif tag == 'cond':
131            str = ''
132            for c in self._data:
133                str = str + c
134            if self.in_function == 1:
135                self.function_cond = str
136
137
138def function(name, desc, ret, args, file, cond):
139    functions[name] = (desc, ret, args, file, cond)
140
141def enum(type, name, value):
142    if type not in enums:
143        enums[type] = {}
144    enums[type][name] = value
145
146#######################################################################
147#
148#  Some filtering rukes to drop functions/types which should not
149#  be exposed as-is on the Python interface
150#
151#######################################################################
152
153skipped_modules = {
154    'xmlmemory': None,
155    'SAX': None,
156    'hash': None,
157    'list': None,
158    'threads': None,
159#    'xpointer': None,
160}
161skipped_types = {
162    'int *': "usually a return type",
163    'xmlSAXHandlerPtr': "not the proper interface for SAX",
164    'htmlSAXHandlerPtr': "not the proper interface for SAX",
165    'xmlRMutexPtr': "thread specific, skipped",
166    'xmlMutexPtr': "thread specific, skipped",
167    'xmlGlobalStatePtr': "thread specific, skipped",
168    'xmlListPtr': "internal representation not suitable for python",
169    'xmlBufferPtr': "internal representation not suitable for python",
170    'FILE *': None,
171}
172
173#######################################################################
174#
175#  Table of remapping to/from the python type or class to the C
176#  counterpart.
177#
178#######################################################################
179
180py_types = {
181    'void': (None, None, None, None),
182    'int':  ('i', None, "int", "int"),
183    'long':  ('l', None, "long", "long"),
184    'double':  ('d', None, "double", "double"),
185    'unsigned int':  ('i', None, "int", "int"),
186    'xmlChar':  ('c', None, "int", "int"),
187    'unsigned char *':  ('z', None, "charPtr", "char *"),
188    'char *':  ('z', None, "charPtr", "char *"),
189    'const char *':  ('z', None, "charPtrConst", "const char *"),
190    'xmlChar *':  ('z', None, "xmlCharPtr", "xmlChar *"),
191    'const xmlChar *':  ('z', None, "xmlCharPtrConst", "const xmlChar *"),
192    'xmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
193    'const xmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
194    'xmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
195    'const xmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
196    'xmlDtdPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
197    'const xmlDtdPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
198    'xmlDtd *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
199    'const xmlDtd *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
200    'xmlAttrPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
201    'const xmlAttrPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
202    'xmlAttr *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
203    'const xmlAttr *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
204    'xmlEntityPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
205    'const xmlEntityPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
206    'xmlEntity *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
207    'const xmlEntity *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
208    'xmlElementPtr':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
209    'const xmlElementPtr':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
210    'xmlElement *':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
211    'const xmlElement *':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
212    'xmlAttributePtr':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
213    'const xmlAttributePtr':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
214    'xmlAttribute *':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
215    'const xmlAttribute *':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
216    'xmlNsPtr':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
217    'const xmlNsPtr':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
218    'xmlNs *':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
219    'const xmlNs *':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
220    'xmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
221    'const xmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
222    'xmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
223    'const xmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
224    'htmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
225    'const htmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
226    'htmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
227    'const htmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
228    'htmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
229    'const htmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
230    'htmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
231    'const htmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
232    'xmlXPathContextPtr':  ('O', "xmlXPathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"),
233    'xmlXPathContext *':  ('O', "xpathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"),
234    'xmlXPathParserContextPtr':  ('O', "xmlXPathParserContext", "xmlXPathParserContextPtr", "xmlXPathParserContextPtr"),
235    'xmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
236    'xmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
237    'htmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
238    'htmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
239    'xmlValidCtxtPtr': ('O', "ValidCtxt", "xmlValidCtxtPtr", "xmlValidCtxtPtr"),
240    'xmlCatalogPtr': ('O', "catalog", "xmlCatalogPtr", "xmlCatalogPtr"),
241    'FILE *': ('O', "File", "FILEPtr", "FILE *"),
242    'xmlURIPtr': ('O', "URI", "xmlURIPtr", "xmlURIPtr"),
243    'const xmlError *': ('O', "Error", "xmlErrorPtr", "const xmlError *"),
244    'xmlErrorPtr': ('O', "Error", "xmlErrorPtr", "xmlErrorPtr"),
245    'xmlOutputBufferPtr': ('O', "outputBuffer", "xmlOutputBufferPtr", "xmlOutputBufferPtr"),
246    'xmlParserInputBufferPtr': ('O', "inputBuffer", "xmlParserInputBufferPtr", "xmlParserInputBufferPtr"),
247    'xmlRegexpPtr': ('O', "xmlReg", "xmlRegexpPtr", "xmlRegexpPtr"),
248    'xmlTextReaderLocatorPtr': ('O', "xmlTextReaderLocator", "xmlTextReaderLocatorPtr", "xmlTextReaderLocatorPtr"),
249    'xmlTextReaderPtr': ('O', "xmlTextReader", "xmlTextReaderPtr", "xmlTextReaderPtr"),
250    'xmlRelaxNGPtr': ('O', "relaxNgSchema", "xmlRelaxNGPtr", "xmlRelaxNGPtr"),
251    'xmlRelaxNGParserCtxtPtr': ('O', "relaxNgParserCtxt", "xmlRelaxNGParserCtxtPtr", "xmlRelaxNGParserCtxtPtr"),
252    'xmlRelaxNGValidCtxtPtr': ('O', "relaxNgValidCtxt", "xmlRelaxNGValidCtxtPtr", "xmlRelaxNGValidCtxtPtr"),
253    'xmlSchemaPtr': ('O', "Schema", "xmlSchemaPtr", "xmlSchemaPtr"),
254    'xmlSchemaParserCtxtPtr': ('O', "SchemaParserCtxt", "xmlSchemaParserCtxtPtr", "xmlSchemaParserCtxtPtr"),
255    'xmlSchemaValidCtxtPtr': ('O', "SchemaValidCtxt", "xmlSchemaValidCtxtPtr", "xmlSchemaValidCtxtPtr"),
256}
257
258py_return_types = {
259    'xmlXPathObjectPtr':  ('O', "foo", "xmlXPathObjectPtr", "xmlXPathObjectPtr"),
260}
261
262unknown_types = {}
263
264foreign_encoding_args = (
265    'htmlCreateMemoryParserCtxt',
266    'htmlCtxtReadMemory',
267    'htmlParseChunk',
268    'htmlReadMemory',
269    'xmlCreateMemoryParserCtxt',
270    'xmlCtxtReadMemory',
271    'xmlCtxtResetPush',
272    'xmlParseChunk',
273    'xmlParseMemory',
274    'xmlReadMemory',
275    'xmlRecoverMemory',
276)
277
278#######################################################################
279#
280#  This part writes the C <-> Python stubs libxml2-py.[ch] and
281#  the table libxml2-export.c to add when registrering the Python module
282#
283#######################################################################
284
285# Class methods which are written by hand in libxml.c but the Python-level
286# code is still automatically generated (so they are not in skip_function()).
287skip_impl = (
288    'xmlSaveFileTo',
289    'xmlSaveFormatFileTo',
290)
291
292deprecated_funcs = {
293    'htmlAutoCloseTag': True,
294    'htmlDefaultSAXHandlerInit': True,
295    'htmlHandleOmittedElem': True,
296    'htmlInitAutoClose': True,
297    'htmlIsAutoClosed': True,
298    'htmlIsBooleanAttr': True,
299    'htmlParseCharRef': True,
300    'htmlParseElement': True,
301    'namePop': True,
302    'namePush': True,
303    'nodePop': True,
304    'nodePush': True,
305    'xmlByteConsumed': True,
306    'xmlCheckFilename': True,
307    'xmlCheckLanguageID': True,
308    'xmlCleanupCharEncodingHandlers': True,
309    'xmlCleanupGlobals': True,
310    'xmlCopyChar': True,
311    'xmlDefaultSAXHandlerInit': True,
312    'xmlDictCleanup': True,
313    'xmlFileMatch': True,
314    'xmlGetCompressMode': True,
315    'xmlInitCharEncodingHandlers': True,
316    'xmlInitGlobals': True,
317    'xmlInitializeDict': True,
318    'xmlIOFTPMatch': True,
319    'xmlIOHTTPMatch': True,
320    'xmlIsLetter': True,
321    'xmlIsRef': True,
322    'xmlKeepBlanksDefault': True,
323    'xmlLineNumbersDefault': True,
324    'xmlNanoHTTPCleanup': True,
325    'xmlNanoHTTPInit': True,
326    'xmlNanoHTTPScanProxy': True,
327    'xmlNextChar': True,
328    'xmlNormalizeWindowsPath': True,
329    'xmlParseAttValue': True,
330    'xmlParseAttributeListDecl': True,
331    'xmlParseCDSect': True,
332    'xmlParseCharData': True,
333    'xmlParseCharRef': True,
334    'xmlParseComment': True,
335    'xmlParseDocTypeDecl': True,
336    'xmlParseElement': True,
337    'xmlParseElementDecl': True,
338    'xmlParseEncName': True,
339    'xmlParseEncodingDecl': True,
340    'xmlParseEndTag': True,
341    'xmlParseEntity': True,
342    'xmlParseEntityDecl': True,
343    'xmlParseEntityRef': True,
344    'xmlParseMarkupDecl': True,
345    'xmlParseMisc': True,
346    'xmlParseName': True,
347    'xmlParseNmtoken': True,
348    'xmlParseNotationDecl': True,
349    'xmlParsePEReference': True,
350    'xmlParsePI': True,
351    'xmlParsePITarget': True,
352    'xmlParsePubidLiteral': True,
353    'xmlParseReference': True,
354    'xmlParseSDDecl': True,
355    'xmlParseStartTag': True,
356    'xmlParseSystemLiteral': True,
357    'xmlParseTextDecl': True,
358    'xmlParseVersionInfo': True,
359    'xmlParseVersionNum': True,
360    'xmlParseXMLDecl': True,
361    'xmlParserHandlePEReference': True,
362    'xmlParserInputBufferGrow': True,
363    'xmlParserInputBufferPush': True,
364    'xmlParserInputBufferRead': True,
365    'xmlParserSetLineNumbers': True,
366    'xmlParserSetLoadSubset': True,
367    'xmlParserSetPedantic': True,
368    'xmlParserSetReplaceEntities': True,
369    'xmlParserSetValidate': True,
370    'xmlPedanticParserDefault': True,
371    'xmlRecoverDoc': True,
372    'xmlRecoverFile': True,
373    'xmlRecoverMemory': True,
374    'xmlRegisterHTTPPostCallbacks': True,
375    'xmlRelaxNGCleanupTypes': True,
376    'xmlRelaxNGInitTypes': True,
377    'xmlRemoveRef': True,
378    'xmlSAXDefaultVersion': True,
379    'xmlSchemaCleanupTypes': True,
380    'xmlSchemaInitTypes': True,
381    'xmlSetCompressMode': True,
382    'xmlSetupParserForBuffer': True,
383    'xmlSkipBlankChars': True,
384    'xmlStringDecodeEntities': True,
385    'xmlStringLenDecodeEntities': True,
386    'xmlSubstituteEntitiesDefault': True,
387    'xmlThrDefDefaultBufferSize': True,
388    'xmlThrDefDoValidityCheckingDefaultValue': True,
389    'xmlThrDefGetWarningsDefaultValue': True,
390    'xmlThrDefIndentTreeOutput': True,
391    'xmlThrDefKeepBlanksDefaultValue': True,
392    'xmlThrDefLineNumbersDefaultValue': True,
393    'xmlThrDefLoadExtDtdDefaultValue': True,
394    'xmlThrDefParserDebugEntities': True,
395    'xmlThrDefPedanticParserDefaultValue': True,
396    'xmlThrDefSaveNoEmptyTags': True,
397    'xmlThrDefSubstituteEntitiesDefaultValue': True,
398    'xmlThrDefTreeIndentString': True,
399    'xmlValidCtxtNormalizeAttributeValue': True,
400    'xmlValidNormalizeAttributeValue': True,
401    'xmlValidateAttributeValue': True,
402    'xmlValidateDocumentFinal': True,
403    'xmlValidateDtdFinal': True,
404    'xmlValidateNotationUse': True,
405    'xmlValidateOneAttribute': True,
406    'xmlValidateOneElement': True,
407    'xmlValidateOneNamespace': True,
408    'xmlValidatePopElement': True,
409    'xmlValidatePushCData': True,
410    'xmlValidatePushElement': True,
411    'xmlValidateRoot': True,
412    'xmlValidate': True,
413    'xmlXPathEvalExpr': True,
414    'xmlXPathInit': True,
415    'xmlXPtrEvalRangePredicate': True,
416    'xmlXPtrNewCollapsedRange': True,
417    'xmlXPtrNewContext': True,
418    'xmlXPtrNewLocationSetNodes': True,
419    'xmlXPtrNewRange': True,
420    'xmlXPtrNewRangeNodes': True,
421    'xmlXPtrRangeToFunction': True,
422}
423
424def skip_function(name):
425    if name[0:12] == "xmlXPathWrap":
426        return 1
427    if name == "xmlFreeParserCtxt":
428        return 1
429    if name == "xmlCleanupParser":
430        return 1
431    if name == "xmlFreeTextReader":
432        return 1
433#    if name[0:11] == "xmlXPathNew":
434#        return 1
435    # the next function is defined in libxml.c
436    if name == "xmlRelaxNGFreeValidCtxt":
437        return 1
438    if name == "xmlFreeValidCtxt":
439        return 1
440    if name == "xmlSchemaFreeValidCtxt":
441        return 1
442
443#
444# Those are skipped because the Const version is used of the bindings
445# instead.
446#
447    if name == "xmlTextReaderBaseUri":
448        return 1
449    if name == "xmlTextReaderLocalName":
450        return 1
451    if name == "xmlTextReaderName":
452        return 1
453    if name == "xmlTextReaderNamespaceUri":
454        return 1
455    if name == "xmlTextReaderPrefix":
456        return 1
457    if name == "xmlTextReaderXmlLang":
458        return 1
459    if name == "xmlTextReaderValue":
460        return 1
461    if name == "xmlOutputBufferClose": # handled by by the superclass
462        return 1
463    if name == "xmlOutputBufferFlush": # handled by by the superclass
464        return 1
465    if name == "xmlErrMemory":
466        return 1
467
468    if name == "xmlValidBuildContentModel":
469        return 1
470    if name == "xmlValidateElementDecl":
471        return 1
472    if name == "xmlValidateAttributeDecl":
473        return 1
474    if name == "xmlPopInputCallbacks":
475        return 1
476
477    return 0
478
479def print_function_wrapper(name, output, export, include):
480    global py_types
481    global unknown_types
482    global functions
483    global skipped_modules
484
485    try:
486        (desc, ret, args, file, cond) = functions[name]
487    except:
488        print("failed to get function %s infos")
489        return
490
491    if file in skipped_modules:
492        return 0
493    if skip_function(name) == 1:
494        return 0
495    if name in skip_impl:
496        # Don't delete the function entry in the caller.
497        return 1
498
499    if name.startswith('xmlUCSIs'):
500        is_deprecated = name != 'xmlUCSIsBlock' and name != 'xmlUCSIsCat'
501    else:
502        is_deprecated = name in deprecated_funcs
503
504    c_call = ""
505    format=""
506    format_args=""
507    c_args=""
508    c_return=""
509    c_convert=""
510    c_release=""
511    num_bufs=0
512    for arg in args:
513        # This should be correct
514        if arg[1][0:6] == "const ":
515            arg[1] = arg[1][6:]
516        c_args = c_args + "    %s %s;\n" % (arg[1], arg[0])
517        if arg[1] in py_types:
518            (f, t, n, c) = py_types[arg[1]]
519            if (f == 'z') and (name in foreign_encoding_args) and (num_bufs == 0):
520                f = 's#'
521            if f != None:
522                format = format + f
523            if t != None:
524                format_args = format_args + ", &pyobj_%s" % (arg[0])
525                c_args = c_args + "    PyObject *pyobj_%s;\n" % (arg[0])
526                c_convert = c_convert + \
527                   "    %s = (%s) Py%s_Get(pyobj_%s);\n" % (arg[0],
528                   arg[1], t, arg[0])
529            else:
530                format_args = format_args + ", &%s" % (arg[0])
531            if f == 's#':
532                format_args = format_args + ", &py_buffsize%d" % num_bufs
533                c_args = c_args + "    Py_ssize_t  py_buffsize%d;\n" % num_bufs
534                num_bufs = num_bufs + 1
535            if c_call != "":
536                c_call = c_call + ", "
537            c_call = c_call + "%s" % (arg[0])
538            if t == "File":
539                c_release = c_release + \
540		            "    PyFile_Release(%s);\n" % (arg[0])
541        else:
542            if arg[1] in skipped_types:
543                return 0
544            if arg[1] in unknown_types:
545                lst = unknown_types[arg[1]]
546                lst.append(name)
547            else:
548                unknown_types[arg[1]] = [name]
549            return -1
550    if format != "":
551        format = format + ":%s" % (name)
552
553    if ret[0] == 'void':
554        if file == "python_accessor":
555            if args[1][1] == "char *" or args[1][1] == "xmlChar *":
556                c_call = "\n    if (%s->%s != NULL) xmlFree(%s->%s);\n" % (
557                                 args[0][0], args[1][0], args[0][0], args[1][0])
558                c_call = c_call + "    %s->%s = (%s)xmlStrdup((const xmlChar *)%s);\n" % (args[0][0],
559                                 args[1][0], args[1][1], args[1][0])
560            else:
561                c_call = "\n    %s->%s = %s;\n" % (args[0][0], args[1][0],
562                                                   args[1][0])
563        else:
564            c_call = "\n    %s(%s);\n" % (name, c_call)
565        ret_convert = "    Py_INCREF(Py_None);\n    return(Py_None);\n"
566    elif ret[0] in py_types:
567        (f, t, n, c) = py_types[ret[0]]
568        c_return = c_return + "    %s c_retval;\n" % (ret[0])
569        if file == "python_accessor" and ret[2] != None:
570            c_call = "\n    c_retval = %s->%s;\n" % (args[0][0], ret[2])
571        else:
572            c_call = "\n    c_retval = %s(%s);\n" % (name, c_call)
573        ret_convert = "    py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c)
574        ret_convert = ret_convert + "    return(py_retval);\n"
575    elif ret[0] in py_return_types:
576        (f, t, n, c) = py_return_types[ret[0]]
577        c_return = c_return + "    %s c_retval;\n" % (ret[0])
578        c_call = "\n    c_retval = %s(%s);\n" % (name, c_call)
579        ret_convert = "    py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c)
580        ret_convert = ret_convert + "    return(py_retval);\n"
581    else:
582        if ret[0] in skipped_types:
583            return 0
584        if ret[0] in unknown_types:
585            lst = unknown_types[ret[0]]
586            lst.append(name)
587        else:
588            unknown_types[ret[0]] = [name]
589        return -1
590
591    if cond != None and cond != "":
592        include.write("#if %s\n" % cond)
593        export.write("#if %s\n" % cond)
594        output.write("#if %s\n" % cond)
595
596    include.write("PyObject * ")
597    include.write("libxml_%s(PyObject *self, PyObject *args);\n" % (name))
598
599    export.write("    { (char *)\"%s\", libxml_%s, METH_VARARGS, NULL },\n" %
600                 (name, name))
601
602    if file == "python":
603        # Those have been manually generated
604        if cond != None and cond != "":
605            include.write("#endif\n")
606            export.write("#endif\n")
607            output.write("#endif\n")
608        return 1
609    if file == "python_accessor" and ret[0] != "void" and ret[2] is None:
610        # Those have been manually generated
611        if cond != None and cond != "":
612            include.write("#endif\n")
613            export.write("#endif\n")
614            output.write("#endif\n")
615        return 1
616
617    if is_deprecated:
618        output.write("XML_IGNORE_DEPRECATION_WARNINGS\n")
619    output.write("PyObject *\n")
620    output.write("libxml_%s(PyObject *self ATTRIBUTE_UNUSED," % (name))
621    output.write(" PyObject *args")
622    if format == "":
623        output.write(" ATTRIBUTE_UNUSED")
624    output.write(") {\n")
625    if ret[0] != 'void':
626        output.write("    PyObject *py_retval;\n")
627    if c_return != "":
628        output.write(c_return)
629    if c_args != "":
630        output.write(c_args)
631    if is_deprecated:
632        output.write("\n    if (libxml_deprecationWarning(\"%s\") == -1)\n" %
633                     name)
634        output.write("        return(NULL);\n")
635    if format != "":
636        output.write("\n    if (!PyArg_ParseTuple(args, (char *)\"%s\"%s))\n" %
637                     (format, format_args))
638        output.write("        return(NULL);\n")
639    if c_convert != "":
640        output.write(c_convert)
641
642    output.write(c_call)
643    if c_release != "":
644        output.write(c_release)
645    output.write(ret_convert)
646    output.write("}\n")
647    if is_deprecated:
648        output.write("XML_POP_WARNINGS\n")
649    output.write("\n")
650
651    if cond != None and cond != "":
652        include.write("#endif /* %s */\n" % cond)
653        export.write("#endif /* %s */\n" % cond)
654        output.write("#endif /* %s */\n" % cond)
655    return 1
656
657def buildStubs():
658    global py_types
659    global py_return_types
660    global unknown_types
661
662    try:
663        f = open(os.path.join(srcPref,"libxml2-api.xml"))
664        data = f.read()
665        (parser, target)  = getparser()
666        parser.feed(data)
667        parser.close()
668    except IOError as msg:
669        try:
670            f = open(os.path.join(srcPref,"..","doc","libxml2-api.xml"))
671            data = f.read()
672            (parser, target)  = getparser()
673            parser.feed(data)
674            parser.close()
675        except IOError as msg:
676            print(file, ":", msg)
677            sys.exit(1)
678
679    n = len(list(functions.keys()))
680    print("Found %d functions in libxml2-api.xml" % (n))
681
682    py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject")
683    try:
684        f = open(os.path.join(srcPref,"libxml2-python-api.xml"))
685        data = f.read()
686        (parser, target)  = getparser()
687        parser.feed(data)
688        parser.close()
689    except IOError as msg:
690        print(file, ":", msg)
691
692
693    print("Found %d functions in libxml2-python-api.xml" % (
694          len(list(functions.keys())) - n))
695    nb_wrap = 0
696    failed = 0
697    skipped = 0
698
699    include = open("libxml2-py.h", "w")
700    include.write("/* Generated */\n\n")
701    export = open("libxml2-export.c", "w")
702    export.write("/* Generated */\n\n")
703    wrapper = open("libxml2-py.c", "w")
704    wrapper.write("/* Generated */\n\n")
705    wrapper.write("#define PY_SSIZE_T_CLEAN\n")
706    wrapper.write("#include <Python.h>\n")
707    wrapper.write("#include <libxml/xmlversion.h>\n")
708    wrapper.write("#include <libxml/tree.h>\n")
709    wrapper.write("#include <libxml/xmlschemastypes.h>\n")
710    wrapper.write("#include \"libxml_wrap.h\"\n")
711    wrapper.write("#include \"libxml2-py.h\"\n\n")
712    for function in sorted(functions.keys()):
713        ret = print_function_wrapper(function, wrapper, export, include)
714        if ret < 0:
715            failed = failed + 1
716            del functions[function]
717        if ret == 0:
718            skipped = skipped + 1
719            del functions[function]
720        if ret == 1:
721            nb_wrap = nb_wrap + 1
722    include.close()
723    export.close()
724    wrapper.close()
725
726    print("Generated %d wrapper functions, %d failed, %d skipped" % (nb_wrap,
727                                                              failed, skipped))
728#    print("Missing type converters: ")
729#    for type in list(unknown_types.keys()):
730#        print("%s:%d " % (type, len(unknown_types[type])))
731#    print()
732
733#######################################################################
734#
735#  This part writes part of the Python front-end classes based on
736#  mapping rules between types and classes and also based on function
737#  renaming to get consistent function names at the Python level
738#
739#######################################################################
740
741#
742# The type automatically remapped to generated classes
743#
744classes_type = {
745    "xmlNodePtr": ("._o", "xmlNode(_obj=%s)", "xmlNode"),
746    "xmlNode *": ("._o", "xmlNode(_obj=%s)", "xmlNode"),
747    "xmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
748    "xmlDoc *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
749    "htmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
750    "htmlxmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
751    "xmlAttrPtr": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"),
752    "xmlAttr *": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"),
753    "xmlNsPtr": ("._o", "xmlNs(_obj=%s)", "xmlNs"),
754    "xmlNs *": ("._o", "xmlNs(_obj=%s)", "xmlNs"),
755    "xmlDtdPtr": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"),
756    "xmlDtd *": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"),
757    "xmlEntityPtr": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"),
758    "xmlEntity *": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"),
759    "xmlElementPtr": ("._o", "xmlElement(_obj=%s)", "xmlElement"),
760    "xmlElement *": ("._o", "xmlElement(_obj=%s)", "xmlElement"),
761    "xmlAttributePtr": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"),
762    "xmlAttribute *": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"),
763    "xmlXPathContextPtr": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
764    "xmlXPathContext *": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
765    "xmlXPathParserContext *": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"),
766    "xmlXPathParserContextPtr": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"),
767    "xmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
768    "xmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
769    "htmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
770    "htmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
771    "xmlValidCtxtPtr": ("._o", "ValidCtxt(_obj=%s)", "ValidCtxt"),
772    "xmlCatalogPtr": ("._o", "catalog(_obj=%s)", "catalog"),
773    "xmlURIPtr": ("._o", "URI(_obj=%s)", "URI"),
774    "const xmlError *": ("._o", "Error(_obj=%s)", "Error"),
775    "xmlErrorPtr": ("._o", "Error(_obj=%s)", "Error"),
776    "xmlOutputBufferPtr": ("._o", "outputBuffer(_obj=%s)", "outputBuffer"),
777    "xmlParserInputBufferPtr": ("._o", "inputBuffer(_obj=%s)", "inputBuffer"),
778    "xmlRegexpPtr": ("._o", "xmlReg(_obj=%s)", "xmlReg"),
779    "xmlTextReaderLocatorPtr": ("._o", "xmlTextReaderLocator(_obj=%s)", "xmlTextReaderLocator"),
780    "xmlTextReaderPtr": ("._o", "xmlTextReader(_obj=%s)", "xmlTextReader"),
781    'xmlRelaxNGPtr': ('._o', "relaxNgSchema(_obj=%s)", "relaxNgSchema"),
782    'xmlRelaxNGParserCtxtPtr': ('._o', "relaxNgParserCtxt(_obj=%s)", "relaxNgParserCtxt"),
783    'xmlRelaxNGValidCtxtPtr': ('._o', "relaxNgValidCtxt(_obj=%s)", "relaxNgValidCtxt"),
784    'xmlSchemaPtr': ("._o", "Schema(_obj=%s)", "Schema"),
785    'xmlSchemaParserCtxtPtr': ("._o", "SchemaParserCtxt(_obj=%s)", "SchemaParserCtxt"),
786    'xmlSchemaValidCtxtPtr': ("._o", "SchemaValidCtxt(_obj=%s)", "SchemaValidCtxt"),
787}
788
789converter_type = {
790    "xmlXPathObjectPtr": "xpathObjectRet(%s)",
791}
792
793primary_classes = ["xmlNode", "xmlDoc"]
794
795classes_ancestor = {
796    "xmlNode" : "xmlCore",
797    "xmlDtd" : "xmlNode",
798    "xmlDoc" : "xmlNode",
799    "xmlAttr" : "xmlNode",
800    "xmlNs" : "xmlNode",
801    "xmlEntity" : "xmlNode",
802    "xmlElement" : "xmlNode",
803    "xmlAttribute" : "xmlNode",
804    "outputBuffer": "ioWriteWrapper",
805    "inputBuffer": "ioReadWrapper",
806    "parserCtxt": "parserCtxtCore",
807    "xmlTextReader": "xmlTextReaderCore",
808    "ValidCtxt": "ValidCtxtCore",
809    "SchemaValidCtxt": "SchemaValidCtxtCore",
810    "relaxNgValidCtxt": "relaxNgValidCtxtCore",
811}
812classes_destructors = {
813    "parserCtxt": "xmlFreeParserCtxt",
814    "catalog": "xmlFreeCatalog",
815    "URI": "xmlFreeURI",
816#    "outputBuffer": "xmlOutputBufferClose",
817    "inputBuffer": "xmlFreeParserInputBuffer",
818    "xmlReg": "xmlRegFreeRegexp",
819    "xmlTextReader": "xmlFreeTextReader",
820    "relaxNgSchema": "xmlRelaxNGFree",
821    "relaxNgParserCtxt": "xmlRelaxNGFreeParserCtxt",
822    "relaxNgValidCtxt": "xmlRelaxNGFreeValidCtxt",
823        "Schema": "xmlSchemaFree",
824        "SchemaParserCtxt": "xmlSchemaFreeParserCtxt",
825        "SchemaValidCtxt": "xmlSchemaFreeValidCtxt",
826        "ValidCtxt": "xmlFreeValidCtxt",
827}
828
829functions_noexcept = {
830    "xmlHasProp": 1,
831    "xmlHasNsProp": 1,
832    "xmlDocSetRootElement": 1,
833    "xmlNodeGetNs": 1,
834    "xmlNodeGetNsDefs": 1,
835    "xmlNextElementSibling": 1,
836    "xmlPreviousElementSibling": 1,
837    "xmlFirstElementChild": 1,
838    "xmlLastElementChild": 1,
839}
840
841reference_keepers = {
842    "xmlTextReader": [('inputBuffer', 'input')],
843    "relaxNgValidCtxt": [('relaxNgSchema', 'schema')],
844        "SchemaValidCtxt": [('Schema', 'schema')],
845}
846
847function_classes = {}
848
849function_classes["None"] = []
850
851def nameFixup(name, classe, type, file):
852    listname = classe + "List"
853    ll = len(listname)
854    l = len(classe)
855    if name[0:l] == listname:
856        func = name[l:]
857        func = func[0:1].lower() + func[1:]
858    elif name[0:12] == "xmlParserGet" and file == "python_accessor":
859        func = name[12:]
860        func = func[0:1].lower() + func[1:]
861    elif name[0:12] == "xmlParserSet" and file == "python_accessor":
862        func = name[12:]
863        func = func[0:1].lower() + func[1:]
864    elif name[0:10] == "xmlNodeGet" and file == "python_accessor":
865        func = name[10:]
866        func = func[0:1].lower() + func[1:]
867    elif name[0:9] == "xmlURIGet" and file == "python_accessor":
868        func = name[9:]
869        func = func[0:1].lower() + func[1:]
870    elif name[0:9] == "xmlURISet" and file == "python_accessor":
871        func = name[6:]
872        func = func[0:1].lower() + func[1:]
873    elif name[0:11] == "xmlErrorGet" and file == "python_accessor":
874        func = name[11:]
875        func = func[0:1].lower() + func[1:]
876    elif name[0:17] == "xmlXPathParserGet" and file == "python_accessor":
877        func = name[17:]
878        func = func[0:1].lower() + func[1:]
879    elif name[0:11] == "xmlXPathGet" and file == "python_accessor":
880        func = name[11:]
881        func = func[0:1].lower() + func[1:]
882    elif name[0:11] == "xmlXPathSet" and file == "python_accessor":
883        func = name[8:]
884        func = func[0:1].lower() + func[1:]
885    elif name[0:15] == "xmlOutputBuffer" and file != "python":
886        func = name[15:]
887        func = func[0:1].lower() + func[1:]
888    elif name[0:20] == "xmlParserInputBuffer" and file != "python":
889        func = name[20:]
890        func = func[0:1].lower() + func[1:]
891    elif name[0:9] == "xmlRegexp" and file == "xmlregexp":
892        func = "regexp" + name[9:]
893    elif name[0:6] == "xmlReg" and file == "xmlregexp":
894        func = "regexp" + name[6:]
895    elif name[0:20] == "xmlTextReaderLocator" and file == "xmlreader":
896        func = name[20:]
897    elif name[0:18] == "xmlTextReaderConst" and file == "xmlreader":
898        func = name[18:]
899    elif name[0:13] == "xmlTextReader" and file == "xmlreader":
900        func = name[13:]
901    elif name[0:12] == "xmlReaderNew" and file == "xmlreader":
902        func = name[9:]
903    elif name[0:11] == "xmlACatalog":
904        func = name[11:]
905        func = func[0:1].lower() + func[1:]
906    elif name[0:l] == classe:
907        func = name[l:]
908        func = func[0:1].lower() + func[1:]
909    elif name[0:7] == "libxml_":
910        func = name[7:]
911        func = func[0:1].lower() + func[1:]
912    elif name[0:6] == "xmlGet":
913        func = name[6:]
914        func = func[0:1].lower() + func[1:]
915    elif name[0:3] == "xml":
916        func = name[3:]
917        func = func[0:1].lower() + func[1:]
918    else:
919        func = name
920    if func[0:5] == "xPath":
921        func = "xpath" + func[5:]
922    elif func[0:4] == "xPtr":
923        func = "xpointer" + func[4:]
924    elif func[0:8] == "xInclude":
925        func = "xinclude" + func[8:]
926    elif func[0:2] == "iD":
927        func = "ID" + func[2:]
928    elif func[0:3] == "uRI":
929        func = "URI" + func[3:]
930    elif func[0:4] == "uTF8":
931        func = "UTF8" + func[4:]
932    elif func[0:3] == 'sAX':
933        func = "SAX" + func[3:]
934    return func
935
936
937def functionCompare(info1, info2):
938    (index1, func1, name1, ret1, args1, file1) = info1
939    (index2, func2, name2, ret2, args2, file2) = info2
940    if file1 == file2:
941        if func1 < func2:
942            return -1
943        if func1 > func2:
944            return 1
945    if file1 == "python_accessor":
946        return -1
947    if file2 == "python_accessor":
948        return 1
949    if file1 < file2:
950        return -1
951    if file1 > file2:
952        return 1
953    return 0
954
955def cmp_to_key(mycmp):
956    'Convert a cmp= function into a key= function'
957    class K(object):
958        def __init__(self, obj, *args):
959            self.obj = obj
960        def __lt__(self, other):
961            return mycmp(self.obj, other.obj) < 0
962        def __gt__(self, other):
963            return mycmp(self.obj, other.obj) > 0
964        def __eq__(self, other):
965            return mycmp(self.obj, other.obj) == 0
966        def __le__(self, other):
967            return mycmp(self.obj, other.obj) <= 0
968        def __ge__(self, other):
969            return mycmp(self.obj, other.obj) >= 0
970        def __ne__(self, other):
971            return mycmp(self.obj, other.obj) != 0
972    return K
973def writeDoc(name, args, indent, output):
974     if functions[name][0] is None or functions[name][0] == "":
975         return
976     val = functions[name][0]
977     val = val.replace("NULL", "None")
978     output.write(indent)
979     output.write('"""')
980     while len(val) > 60:
981         if val[0] == " ":
982             val = val[1:]
983             continue
984         str = val[0:60]
985         i = str.rfind(" ")
986         if i < 0:
987             i = 60
988         str = val[0:i]
989         val = val[i:]
990         output.write(str)
991         output.write('\n  ')
992         output.write(indent)
993     output.write(val)
994     output.write(' """\n')
995
996def buildWrappers():
997    global ctypes
998    global py_types
999    global py_return_types
1000    global unknown_types
1001    global functions
1002    global function_classes
1003    global classes_type
1004    global classes_list
1005    global converter_type
1006    global primary_classes
1007    global converter_type
1008    global classes_ancestor
1009    global converter_type
1010    global primary_classes
1011    global classes_ancestor
1012    global classes_destructors
1013    global functions_noexcept
1014
1015    for type in classes_type.keys():
1016        function_classes[classes_type[type][2]] = []
1017
1018    #
1019    # Build the list of C types to look for ordered to start
1020    # with primary classes
1021    #
1022    ctypes = []
1023    classes_list = []
1024    ctypes_processed = {}
1025    classes_processed = {}
1026    for classe in primary_classes:
1027        classes_list.append(classe)
1028        classes_processed[classe] = ()
1029        for type in classes_type.keys():
1030            tinfo = classes_type[type]
1031            if tinfo[2] == classe:
1032                ctypes.append(type)
1033                ctypes_processed[type] = ()
1034    for type in sorted(classes_type.keys()):
1035        if type in ctypes_processed:
1036            continue
1037        tinfo = classes_type[type]
1038        if tinfo[2] not in classes_processed:
1039            classes_list.append(tinfo[2])
1040            classes_processed[tinfo[2]] = ()
1041
1042        ctypes.append(type)
1043        ctypes_processed[type] = ()
1044
1045    for name in functions.keys():
1046        found = 0
1047        (desc, ret, args, file, cond) = functions[name]
1048        for type in ctypes:
1049            classe = classes_type[type][2]
1050
1051            if name[0:3] == "xml" and len(args) >= 1 and args[0][1] == type:
1052                found = 1
1053                func = nameFixup(name, classe, type, file)
1054                info = (0, func, name, ret, args, file)
1055                function_classes[classe].append(info)
1056            elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == type \
1057                and file != "python_accessor":
1058                found = 1
1059                func = nameFixup(name, classe, type, file)
1060                info = (1, func, name, ret, args, file)
1061                function_classes[classe].append(info)
1062            elif name[0:4] == "html" and len(args) >= 1 and args[0][1] == type:
1063                found = 1
1064                func = nameFixup(name, classe, type, file)
1065                info = (0, func, name, ret, args, file)
1066                function_classes[classe].append(info)
1067            elif name[0:4] == "html" and len(args) >= 2 and args[1][1] == type \
1068                and file != "python_accessor":
1069                found = 1
1070                func = nameFixup(name, classe, type, file)
1071                info = (1, func, name, ret, args, file)
1072                function_classes[classe].append(info)
1073        if found == 1:
1074            continue
1075        if name[0:8] == "xmlXPath":
1076            continue
1077        if name[0:6] == "xmlStr":
1078            continue
1079        if name[0:10] == "xmlCharStr":
1080            continue
1081        func = nameFixup(name, "None", file, file)
1082        info = (0, func, name, ret, args, file)
1083        function_classes['None'].append(info)
1084
1085    classes = open("libxml2class.py", "w")
1086    txt = open("libxml2class.txt", "w")
1087    txt.write("          Generated Classes for libxml2-python\n\n")
1088
1089    txt.write("#\n# Global functions of the module\n#\n\n")
1090    if "None" in function_classes:
1091        flist = function_classes["None"]
1092        flist = sorted(flist, key=cmp_to_key(functionCompare))
1093        oldfile = ""
1094        for info in flist:
1095            (index, func, name, ret, args, file) = info
1096            if file != oldfile:
1097                classes.write("#\n# Functions from module %s\n#\n\n" % file)
1098                txt.write("\n# functions from module %s\n" % file)
1099                oldfile = file
1100            classes.write("def %s(" % func)
1101            txt.write("%s()\n" % func)
1102            n = 0
1103            for arg in args:
1104                if n != 0:
1105                    classes.write(", ")
1106                classes.write("%s" % arg[0])
1107                n = n + 1
1108            classes.write("):\n")
1109            writeDoc(name, args, '    ', classes)
1110
1111            for arg in args:
1112                if arg[1] in classes_type:
1113                    classes.write("    if %s is None: %s__o = None\n" %
1114                                  (arg[0], arg[0]))
1115                    classes.write("    else: %s__o = %s%s\n" %
1116                                  (arg[0], arg[0], classes_type[arg[1]][0]))
1117                if arg[1] in py_types:
1118                    (f, t, n, c) = py_types[arg[1]]
1119                    if t == "File":
1120                        classes.write("    if %s is not None: %s.flush()\n" % (
1121                                      arg[0], arg[0]))
1122
1123            if ret[0] != "void":
1124                classes.write("    ret = ")
1125            else:
1126                classes.write("    ")
1127            classes.write("libxml2mod.%s(" % name)
1128            n = 0
1129            for arg in args:
1130                if n != 0:
1131                    classes.write(", ")
1132                classes.write("%s" % arg[0])
1133                if arg[1] in classes_type:
1134                    classes.write("__o")
1135                n = n + 1
1136            classes.write(")\n")
1137
1138# This may be needed to reposition the I/O, but likely to cause more harm
1139# than good. Those changes in Python3 really break the model.
1140#           for arg in args:
1141#               if arg[1] in py_types:
1142#                   (f, t, n, c) = py_types[arg[1]]
1143#                   if t == "File":
1144#                       classes.write("    if %s is not None: %s.seek(0,0)\n"%(
1145#                                     arg[0], arg[0]))
1146
1147            if ret[0] != "void":
1148                if ret[0] in classes_type:
1149                    #
1150                    # Raise an exception
1151                    #
1152                    if name in functions_noexcept:
1153                        classes.write("    if ret is None:return None\n")
1154                    elif name.find("URI") >= 0:
1155                        classes.write(
1156                        "    if ret is None:raise uriError('%s() failed')\n"
1157                                      % (name))
1158                    elif name.find("XPath") >= 0:
1159                        classes.write(
1160                        "    if ret is None:raise xpathError('%s() failed')\n"
1161                                      % (name))
1162                    elif name.find("Parse") >= 0:
1163                        classes.write(
1164                        "    if ret is None:raise parserError('%s() failed')\n"
1165                                      % (name))
1166                    else:
1167                        classes.write(
1168                        "    if ret is None:raise treeError('%s() failed')\n"
1169                                      % (name))
1170                    classes.write("    return ")
1171                    classes.write(classes_type[ret[0]][1] % ("ret"))
1172                    classes.write("\n")
1173                else:
1174                    classes.write("    return ret\n")
1175            classes.write("\n")
1176
1177    txt.write("\n\n#\n# Set of classes of the module\n#\n\n")
1178    for classname in classes_list:
1179        if classname == "None":
1180            pass
1181        else:
1182            if classname in classes_ancestor:
1183                txt.write("\n\nClass %s(%s)\n" % (classname,
1184                          classes_ancestor[classname]))
1185                classes.write("class %s(%s):\n" % (classname,
1186                              classes_ancestor[classname]))
1187                classes.write("    def __init__(self, _obj=None):\n")
1188                if classes_ancestor[classname] == "xmlCore" or \
1189                   classes_ancestor[classname] == "xmlNode":
1190                    classes.write("        if checkWrapper(_obj) != 0:")
1191                    classes.write("            raise TypeError")
1192                    classes.write("('%s got a wrong wrapper object type')\n" % \
1193                                classname)
1194                if classname in reference_keepers:
1195                    rlist = reference_keepers[classname]
1196                    for ref in rlist:
1197                        classes.write("        self.%s = None\n" % ref[1])
1198                classes.write("        self._o = _obj\n")
1199                classes.write("        %s.__init__(self, _obj=_obj)\n\n" % (
1200                              classes_ancestor[classname]))
1201                if classes_ancestor[classname] == "xmlCore" or \
1202                   classes_ancestor[classname] == "xmlNode":
1203                    classes.write("    def __repr__(self):\n")
1204                    format = "<%s (%%s) object at 0x%%x>" % (classname)
1205                    classes.write("        return \"%s\" %% (self.name, int(pos_id (self)))\n\n" % (
1206                                  format))
1207            else:
1208                txt.write("Class %s()\n" % (classname))
1209                classes.write("class %s:\n" % (classname))
1210                classes.write("    def __init__(self, _obj=None):\n")
1211                if classname in reference_keepers:
1212                    list = reference_keepers[classname]
1213                    for ref in list:
1214                        classes.write("        self.%s = None\n" % ref[1])
1215                classes.write("        if _obj != None:self._o = _obj;return\n")
1216                classes.write("        self._o = None\n\n")
1217            destruct=None
1218            if classname in classes_destructors:
1219                classes.write("    def __del__(self):\n")
1220                classes.write("        if self._o != None:\n")
1221                classes.write("            libxml2mod.%s(self._o)\n" %
1222                              classes_destructors[classname])
1223                classes.write("        self._o = None\n\n")
1224                destruct=classes_destructors[classname]
1225            flist = function_classes[classname]
1226            flist = sorted(flist, key=cmp_to_key(functionCompare))
1227            oldfile = ""
1228            for info in flist:
1229                (index, func, name, ret, args, file) = info
1230                #
1231                # Do not provide as method the destructors for the class
1232                # to avoid double free
1233                #
1234                if name == destruct:
1235                    continue
1236                if file != oldfile:
1237                    if file == "python_accessor":
1238                        classes.write("    # accessors for %s\n" % (classname))
1239                        txt.write("    # accessors\n")
1240                    else:
1241                        classes.write("    #\n")
1242                        classes.write("    # %s functions from module %s\n" % (
1243                                      classname, file))
1244                        txt.write("\n    # functions from module %s\n" % file)
1245                        classes.write("    #\n\n")
1246                oldfile = file
1247                classes.write("    def %s(self" % func)
1248                txt.write("    %s()\n" % func)
1249                n = 0
1250                for arg in args:
1251                    if n != index:
1252                        classes.write(", %s" % arg[0])
1253                    n = n + 1
1254                classes.write("):\n")
1255                writeDoc(name, args, '        ', classes)
1256                n = 0
1257                for arg in args:
1258                    if arg[1] in classes_type:
1259                        if n != index:
1260                            classes.write("        if %s is None: %s__o = None\n" %
1261                                          (arg[0], arg[0]))
1262                            classes.write("        else: %s__o = %s%s\n" %
1263                                          (arg[0], arg[0], classes_type[arg[1]][0]))
1264                    n = n + 1
1265                if ret[0] != "void":
1266                    classes.write("        ret = ")
1267                else:
1268                    classes.write("        ")
1269                classes.write("libxml2mod.%s(" % name)
1270                n = 0
1271                for arg in args:
1272                    if n != 0:
1273                        classes.write(", ")
1274                    if n != index:
1275                        classes.write("%s" % arg[0])
1276                        if arg[1] in classes_type:
1277                            classes.write("__o")
1278                    else:
1279                        classes.write("self")
1280                        if arg[1] in classes_type:
1281                            classes.write(classes_type[arg[1]][0])
1282                    n = n + 1
1283                classes.write(")\n")
1284                if ret[0] != "void":
1285                    if ret[0] in classes_type:
1286                        #
1287                        # Raise an exception
1288                        #
1289                        if name in functions_noexcept:
1290                            classes.write(
1291                                "        if ret is None:return None\n")
1292                        elif name.find("URI") >= 0:
1293                            classes.write(
1294                    "        if ret is None:raise uriError('%s() failed')\n"
1295                                          % (name))
1296                        elif name.find("XPath") >= 0:
1297                            classes.write(
1298                    "        if ret is None:raise xpathError('%s() failed')\n"
1299                                          % (name))
1300                        elif name.find("Parse") >= 0:
1301                            classes.write(
1302                    "        if ret is None:raise parserError('%s() failed')\n"
1303                                          % (name))
1304                        else:
1305                            classes.write(
1306                    "        if ret is None:raise treeError('%s() failed')\n"
1307                                          % (name))
1308
1309                        #
1310                        # generate the returned class wrapper for the object
1311                        #
1312                        classes.write("        __tmp = ")
1313                        classes.write(classes_type[ret[0]][1] % ("ret"))
1314                        classes.write("\n")
1315
1316                        #
1317                        # Sometime one need to keep references of the source
1318                        # class in the returned class object.
1319                        # See reference_keepers for the list
1320                        #
1321                        tclass = classes_type[ret[0]][2]
1322                        if tclass in reference_keepers:
1323                            list = reference_keepers[tclass]
1324                            for pref in list:
1325                                if pref[0] == classname:
1326                                    classes.write("        __tmp.%s = self\n" %
1327                                                  pref[1])
1328                        #
1329                        # return the class
1330                        #
1331                        classes.write("        return __tmp\n")
1332                    elif ret[0] in converter_type:
1333                        #
1334                        # Raise an exception
1335                        #
1336                        if name in functions_noexcept:
1337                            classes.write(
1338                                "        if ret is None:return None")
1339                        elif name.find("URI") >= 0:
1340                            classes.write(
1341                    "        if ret is None:raise uriError('%s() failed')\n"
1342                                          % (name))
1343                        elif name.find("XPath") >= 0:
1344                            classes.write(
1345                    "        if ret is None:raise xpathError('%s() failed')\n"
1346                                          % (name))
1347                        elif name.find("Parse") >= 0:
1348                            classes.write(
1349                    "        if ret is None:raise parserError('%s() failed')\n"
1350                                          % (name))
1351                        else:
1352                            classes.write(
1353                    "        if ret is None:raise treeError('%s() failed')\n"
1354                                          % (name))
1355                        classes.write("        return ")
1356                        classes.write(converter_type[ret[0]] % ("ret"))
1357                        classes.write("\n")
1358                    else:
1359                        classes.write("        return ret\n")
1360                classes.write("\n")
1361
1362    #
1363    # Generate enum constants
1364    #
1365    for type,enum in enums.items():
1366        classes.write("# %s\n" % type)
1367        items = enum.items()
1368        items = sorted(items, key=(lambda i: int(i[1])))
1369        for name,value in items:
1370            classes.write("%s = %s\n" % (name,value))
1371        classes.write("\n")
1372
1373    txt.close()
1374    classes.close()
1375
1376buildStubs()
1377buildWrappers()
1378