File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / python / generator.py
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:33 2014 UTC (10 years, 1 month ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

    1: #!/usr/bin/python -u
    2: #
    3: # generate python wrappers from the XML API description
    4: #
    5: 
    6: functions = {}
    7: enums = {} # { enumType: { enumConstant: enumValue } }
    8: 
    9: import os
   10: import sys
   11: import string
   12: 
   13: if __name__ == "__main__":
   14:     # launched as a script
   15:     srcPref = os.path.dirname(sys.argv[0])
   16: else:
   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: #######################################################################
   26: import os
   27: import xml.sax
   28: 
   29: debug = 0
   30: 
   31: def 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: 
   38: class 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: 
  138: def function(name, desc, ret, args, file, cond):
  139:     functions[name] = (desc, ret, args, file, cond)
  140: 
  141: def 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: 
  153: skipped_modules = {
  154:     'xmlmemory': None,
  155:     'DOCBparser': None,
  156:     'SAX': None,
  157:     'hash': None,
  158:     'list': None,
  159:     'threads': None,
  160: #    'xpointer': None,
  161: }
  162: skipped_types = {
  163:     'int *': "usually a return type",
  164:     'xmlSAXHandlerPtr': "not the proper interface for SAX",
  165:     'htmlSAXHandlerPtr': "not the proper interface for SAX",
  166:     'xmlRMutexPtr': "thread specific, skipped",
  167:     'xmlMutexPtr': "thread specific, skipped",
  168:     'xmlGlobalStatePtr': "thread specific, skipped",
  169:     'xmlListPtr': "internal representation not suitable for python",
  170:     'xmlBufferPtr': "internal representation not suitable for python",
  171:     'FILE *': None,
  172: }
  173: 
  174: #######################################################################
  175: #
  176: #  Table of remapping to/from the python type or class to the C
  177: #  counterpart.
  178: #
  179: #######################################################################
  180: 
  181: py_types = {
  182:     'void': (None, None, None, None),
  183:     'int':  ('i', None, "int", "int"),
  184:     'long':  ('l', None, "long", "long"),
  185:     'double':  ('d', None, "double", "double"),
  186:     'unsigned int':  ('i', None, "int", "int"),
  187:     'xmlChar':  ('c', None, "int", "int"),
  188:     'unsigned char *':  ('z', None, "charPtr", "char *"),
  189:     'char *':  ('z', None, "charPtr", "char *"),
  190:     'const char *':  ('z', None, "charPtrConst", "const char *"),
  191:     'xmlChar *':  ('z', None, "xmlCharPtr", "xmlChar *"),
  192:     'const xmlChar *':  ('z', None, "xmlCharPtrConst", "const xmlChar *"),
  193:     'xmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  194:     'const xmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  195:     'xmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  196:     'const xmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  197:     'xmlDtdPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  198:     'const xmlDtdPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  199:     'xmlDtd *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  200:     'const xmlDtd *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  201:     'xmlAttrPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  202:     'const xmlAttrPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  203:     'xmlAttr *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  204:     'const xmlAttr *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  205:     'xmlEntityPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  206:     'const xmlEntityPtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  207:     'xmlEntity *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  208:     'const xmlEntity *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  209:     'xmlElementPtr':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
  210:     'const xmlElementPtr':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
  211:     'xmlElement *':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
  212:     'const xmlElement *':  ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
  213:     'xmlAttributePtr':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
  214:     'const xmlAttributePtr':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
  215:     'xmlAttribute *':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
  216:     'const xmlAttribute *':  ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
  217:     'xmlNsPtr':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
  218:     'const xmlNsPtr':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
  219:     'xmlNs *':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
  220:     'const xmlNs *':  ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
  221:     'xmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
  222:     'const xmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
  223:     'xmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
  224:     'const xmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
  225:     'htmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
  226:     'const htmlDocPtr':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
  227:     'htmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
  228:     'const htmlDoc *':  ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
  229:     'htmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  230:     'const htmlNodePtr':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  231:     'htmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  232:     'const htmlNode *':  ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
  233:     'xmlXPathContextPtr':  ('O', "xmlXPathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"),
  234:     'xmlXPathContext *':  ('O', "xpathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"),
  235:     'xmlXPathParserContextPtr':  ('O', "xmlXPathParserContext", "xmlXPathParserContextPtr", "xmlXPathParserContextPtr"),
  236:     'xmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
  237:     'xmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
  238:     'htmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
  239:     'htmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
  240:     'xmlValidCtxtPtr': ('O', "ValidCtxt", "xmlValidCtxtPtr", "xmlValidCtxtPtr"),
  241:     'xmlCatalogPtr': ('O', "catalog", "xmlCatalogPtr", "xmlCatalogPtr"),
  242:     'FILE *': ('O', "File", "FILEPtr", "FILE *"),
  243:     'xmlURIPtr': ('O', "URI", "xmlURIPtr", "xmlURIPtr"),
  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: 
  258: py_return_types = {
  259:     'xmlXPathObjectPtr':  ('O', "foo", "xmlXPathObjectPtr", "xmlXPathObjectPtr"),
  260: }
  261: 
  262: unknown_types = {}
  263: 
  264: foreign_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()).
  287: skip_impl = (
  288:     'xmlSaveFileTo',
  289:     'xmlSaveFormatFileTo',
  290: )
  291: 
  292: def skip_function(name):
  293:     if name[0:12] == "xmlXPathWrap":
  294:         return 1
  295:     if name == "xmlFreeParserCtxt":
  296:         return 1
  297:     if name == "xmlCleanupParser":
  298:         return 1
  299:     if name == "xmlFreeTextReader":
  300:         return 1
  301: #    if name[0:11] == "xmlXPathNew":
  302: #        return 1
  303:     # the next function is defined in libxml.c
  304:     if name == "xmlRelaxNGFreeValidCtxt":
  305:         return 1
  306:     if name == "xmlFreeValidCtxt":
  307:         return 1
  308:     if name == "xmlSchemaFreeValidCtxt":
  309:         return 1
  310: 
  311: #
  312: # Those are skipped because the Const version is used of the bindings
  313: # instead.
  314: #
  315:     if name == "xmlTextReaderBaseUri":
  316:         return 1
  317:     if name == "xmlTextReaderLocalName":
  318:         return 1
  319:     if name == "xmlTextReaderName":
  320:         return 1
  321:     if name == "xmlTextReaderNamespaceUri":
  322:         return 1
  323:     if name == "xmlTextReaderPrefix":
  324:         return 1
  325:     if name == "xmlTextReaderXmlLang":
  326:         return 1
  327:     if name == "xmlTextReaderValue":
  328:         return 1
  329:     if name == "xmlOutputBufferClose": # handled by by the superclass
  330:         return 1
  331:     if name == "xmlOutputBufferFlush": # handled by by the superclass
  332:         return 1
  333:     if name == "xmlErrMemory":
  334:         return 1
  335: 
  336:     if name == "xmlValidBuildContentModel":
  337:         return 1
  338:     if name == "xmlValidateElementDecl":
  339:         return 1
  340:     if name == "xmlValidateAttributeDecl":
  341:         return 1
  342:     if name == "xmlPopInputCallbacks":
  343:         return 1
  344: 
  345:     return 0
  346: 
  347: def print_function_wrapper(name, output, export, include):
  348:     global py_types
  349:     global unknown_types
  350:     global functions
  351:     global skipped_modules
  352: 
  353:     try:
  354:         (desc, ret, args, file, cond) = functions[name]
  355:     except:
  356:         print("failed to get function %s infos")
  357:         return
  358: 
  359:     if file in skipped_modules:
  360:         return 0
  361:     if skip_function(name) == 1:
  362:         return 0
  363:     if name in skip_impl:
  364:         # Don't delete the function entry in the caller.
  365:         return 1
  366: 
  367:     c_call = ""
  368:     format=""
  369:     format_args=""
  370:     c_args=""
  371:     c_return=""
  372:     c_convert=""
  373:     c_release=""
  374:     num_bufs=0
  375:     for arg in args:
  376:         # This should be correct
  377:         if arg[1][0:6] == "const ":
  378:             arg[1] = arg[1][6:]
  379:         c_args = c_args + "    %s %s;\n" % (arg[1], arg[0])
  380:         if arg[1] in py_types:
  381:             (f, t, n, c) = py_types[arg[1]]
  382:             if (f == 'z') and (name in foreign_encoding_args) and (num_bufs == 0):
  383:                 f = 's#'
  384:             if f != None:
  385:                 format = format + f
  386:             if t != None:
  387:                 format_args = format_args + ", &pyobj_%s" % (arg[0])
  388:                 c_args = c_args + "    PyObject *pyobj_%s;\n" % (arg[0])
  389:                 c_convert = c_convert + \
  390:                    "    %s = (%s) Py%s_Get(pyobj_%s);\n" % (arg[0],
  391:                    arg[1], t, arg[0])
  392:             else:
  393:                 format_args = format_args + ", &%s" % (arg[0])
  394:             if f == 's#':
  395:                 format_args = format_args + ", &py_buffsize%d" % num_bufs
  396:                 c_args = c_args + "    int py_buffsize%d;\n" % num_bufs
  397:                 num_bufs = num_bufs + 1
  398:             if c_call != "":
  399:                 c_call = c_call + ", "
  400:             c_call = c_call + "%s" % (arg[0])
  401:             if t == "File":
  402:                 c_release = c_release + \
  403: 		            "    PyFile_Release(%s);\n" % (arg[0])
  404:         else:
  405:             if arg[1] in skipped_types:
  406:                 return 0
  407:             if arg[1] in unknown_types:
  408:                 lst = unknown_types[arg[1]]
  409:                 lst.append(name)
  410:             else:
  411:                 unknown_types[arg[1]] = [name]
  412:             return -1
  413:     if format != "":
  414:         format = format + ":%s" % (name)
  415: 
  416:     if ret[0] == 'void':
  417:         if file == "python_accessor":
  418:             if args[1][1] == "char *" or args[1][1] == "xmlChar *":
  419:                 c_call = "\n    if (%s->%s != NULL) xmlFree(%s->%s);\n" % (
  420:                                  args[0][0], args[1][0], args[0][0], args[1][0])
  421:                 c_call = c_call + "    %s->%s = (%s)xmlStrdup((const xmlChar *)%s);\n" % (args[0][0],
  422:                                  args[1][0], args[1][1], args[1][0])
  423:             else:
  424:                 c_call = "\n    %s->%s = %s;\n" % (args[0][0], args[1][0],
  425:                                                    args[1][0])
  426:         else:
  427:             c_call = "\n    %s(%s);\n" % (name, c_call)
  428:         ret_convert = "    Py_INCREF(Py_None);\n    return(Py_None);\n"
  429:     elif ret[0] in py_types:
  430:         (f, t, n, c) = py_types[ret[0]]
  431:         c_return = c_return + "    %s c_retval;\n" % (ret[0])
  432:         if file == "python_accessor" and ret[2] != None:
  433:             c_call = "\n    c_retval = %s->%s;\n" % (args[0][0], ret[2])
  434:         else:
  435:             c_call = "\n    c_retval = %s(%s);\n" % (name, c_call)
  436:         ret_convert = "    py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c)
  437:         ret_convert = ret_convert + "    return(py_retval);\n"
  438:     elif ret[0] in py_return_types:
  439:         (f, t, n, c) = py_return_types[ret[0]]
  440:         c_return = c_return + "    %s c_retval;\n" % (ret[0])
  441:         c_call = "\n    c_retval = %s(%s);\n" % (name, c_call)
  442:         ret_convert = "    py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c)
  443:         ret_convert = ret_convert + "    return(py_retval);\n"
  444:     else:
  445:         if ret[0] in skipped_types:
  446:             return 0
  447:         if ret[0] in unknown_types:
  448:             lst = unknown_types[ret[0]]
  449:             lst.append(name)
  450:         else:
  451:             unknown_types[ret[0]] = [name]
  452:         return -1
  453: 
  454:     if cond != None and cond != "":
  455:         include.write("#if %s\n" % cond)
  456:         export.write("#if %s\n" % cond)
  457:         output.write("#if %s\n" % cond)
  458: 
  459:     include.write("PyObject * ")
  460:     include.write("libxml_%s(PyObject *self, PyObject *args);\n" % (name))
  461: 
  462:     export.write("    { (char *)\"%s\", libxml_%s, METH_VARARGS, NULL },\n" %
  463:                  (name, name))
  464: 
  465:     if file == "python":
  466:         # Those have been manually generated
  467:         if cond != None and cond != "":
  468:             include.write("#endif\n")
  469:             export.write("#endif\n")
  470:             output.write("#endif\n")
  471:         return 1
  472:     if file == "python_accessor" and ret[0] != "void" and ret[2] is None:
  473:         # Those have been manually generated
  474:         if cond != None and cond != "":
  475:             include.write("#endif\n")
  476:             export.write("#endif\n")
  477:             output.write("#endif\n")
  478:         return 1
  479: 
  480:     output.write("PyObject *\n")
  481:     output.write("libxml_%s(PyObject *self ATTRIBUTE_UNUSED," % (name))
  482:     output.write(" PyObject *args")
  483:     if format == "":
  484:         output.write(" ATTRIBUTE_UNUSED")
  485:     output.write(") {\n")
  486:     if ret[0] != 'void':
  487:         output.write("    PyObject *py_retval;\n")
  488:     if c_return != "":
  489:         output.write(c_return)
  490:     if c_args != "":
  491:         output.write(c_args)
  492:     if format != "":
  493:         output.write("\n    if (!PyArg_ParseTuple(args, (char *)\"%s\"%s))\n" %
  494:                      (format, format_args))
  495:         output.write("        return(NULL);\n")
  496:     if c_convert != "":
  497:         output.write(c_convert)
  498: 
  499:     output.write(c_call)
  500:     if c_release != "":
  501:         output.write(c_release)
  502:     output.write(ret_convert)
  503:     output.write("}\n\n")
  504:     if cond != None and cond != "":
  505:         include.write("#endif /* %s */\n" % cond)
  506:         export.write("#endif /* %s */\n" % cond)
  507:         output.write("#endif /* %s */\n" % cond)
  508:     return 1
  509: 
  510: def buildStubs():
  511:     global py_types
  512:     global py_return_types
  513:     global unknown_types
  514: 
  515:     try:
  516:         f = open(os.path.join(srcPref,"libxml2-api.xml"))
  517:         data = f.read()
  518:         (parser, target)  = getparser()
  519:         parser.feed(data)
  520:         parser.close()
  521:     except IOError as msg:
  522:         try:
  523:             f = open(os.path.join(srcPref,"..","doc","libxml2-api.xml"))
  524:             data = f.read()
  525:             (parser, target)  = getparser()
  526:             parser.feed(data)
  527:             parser.close()
  528:         except IOError as msg:
  529:             print(file, ":", msg)
  530:             sys.exit(1)
  531: 
  532:     n = len(list(functions.keys()))
  533:     print("Found %d functions in libxml2-api.xml" % (n))
  534: 
  535:     py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject")
  536:     try:
  537:         f = open(os.path.join(srcPref,"libxml2-python-api.xml"))
  538:         data = f.read()
  539:         (parser, target)  = getparser()
  540:         parser.feed(data)
  541:         parser.close()
  542:     except IOError as msg:
  543:         print(file, ":", msg)
  544: 
  545: 
  546:     print("Found %d functions in libxml2-python-api.xml" % (
  547:           len(list(functions.keys())) - n))
  548:     nb_wrap = 0
  549:     failed = 0
  550:     skipped = 0
  551: 
  552:     include = open("libxml2-py.h", "w")
  553:     include.write("/* Generated */\n\n")
  554:     export = open("libxml2-export.c", "w")
  555:     export.write("/* Generated */\n\n")
  556:     wrapper = open("libxml2-py.c", "w")
  557:     wrapper.write("/* Generated */\n\n")
  558:     wrapper.write("#include <Python.h>\n")
  559:     wrapper.write("#include <libxml/xmlversion.h>\n")
  560:     wrapper.write("#include <libxml/tree.h>\n")
  561:     wrapper.write("#include <libxml/xmlschemastypes.h>\n")
  562:     wrapper.write("#include \"libxml_wrap.h\"\n")
  563:     wrapper.write("#include \"libxml2-py.h\"\n\n")
  564:     for function in sorted(functions.keys()):
  565:         ret = print_function_wrapper(function, wrapper, export, include)
  566:         if ret < 0:
  567:             failed = failed + 1
  568:             del functions[function]
  569:         if ret == 0:
  570:             skipped = skipped + 1
  571:             del functions[function]
  572:         if ret == 1:
  573:             nb_wrap = nb_wrap + 1
  574:     include.close()
  575:     export.close()
  576:     wrapper.close()
  577: 
  578:     print("Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap,
  579:                                                               failed, skipped))
  580:     print("Missing type converters: ")
  581:     for type in list(unknown_types.keys()):
  582:         print("%s:%d " % (type, len(unknown_types[type])))
  583:     print()
  584: 
  585: #######################################################################
  586: #
  587: #  This part writes part of the Python front-end classes based on
  588: #  mapping rules between types and classes and also based on function
  589: #  renaming to get consistent function names at the Python level
  590: #
  591: #######################################################################
  592: 
  593: #
  594: # The type automatically remapped to generated classes
  595: #
  596: classes_type = {
  597:     "xmlNodePtr": ("._o", "xmlNode(_obj=%s)", "xmlNode"),
  598:     "xmlNode *": ("._o", "xmlNode(_obj=%s)", "xmlNode"),
  599:     "xmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
  600:     "xmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
  601:     "htmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
  602:     "htmlxmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
  603:     "xmlAttrPtr": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"),
  604:     "xmlAttr *": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"),
  605:     "xmlNsPtr": ("._o", "xmlNs(_obj=%s)", "xmlNs"),
  606:     "xmlNs *": ("._o", "xmlNs(_obj=%s)", "xmlNs"),
  607:     "xmlDtdPtr": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"),
  608:     "xmlDtd *": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"),
  609:     "xmlEntityPtr": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"),
  610:     "xmlEntity *": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"),
  611:     "xmlElementPtr": ("._o", "xmlElement(_obj=%s)", "xmlElement"),
  612:     "xmlElement *": ("._o", "xmlElement(_obj=%s)", "xmlElement"),
  613:     "xmlAttributePtr": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"),
  614:     "xmlAttribute *": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"),
  615:     "xmlXPathContextPtr": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
  616:     "xmlXPathContext *": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
  617:     "xmlXPathParserContext *": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"),
  618:     "xmlXPathParserContextPtr": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"),
  619:     "xmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
  620:     "xmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
  621:     "htmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
  622:     "htmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
  623:     "xmlValidCtxtPtr": ("._o", "ValidCtxt(_obj=%s)", "ValidCtxt"),
  624:     "xmlCatalogPtr": ("._o", "catalog(_obj=%s)", "catalog"),
  625:     "xmlURIPtr": ("._o", "URI(_obj=%s)", "URI"),
  626:     "xmlErrorPtr": ("._o", "Error(_obj=%s)", "Error"),
  627:     "xmlOutputBufferPtr": ("._o", "outputBuffer(_obj=%s)", "outputBuffer"),
  628:     "xmlParserInputBufferPtr": ("._o", "inputBuffer(_obj=%s)", "inputBuffer"),
  629:     "xmlRegexpPtr": ("._o", "xmlReg(_obj=%s)", "xmlReg"),
  630:     "xmlTextReaderLocatorPtr": ("._o", "xmlTextReaderLocator(_obj=%s)", "xmlTextReaderLocator"),
  631:     "xmlTextReaderPtr": ("._o", "xmlTextReader(_obj=%s)", "xmlTextReader"),
  632:     'xmlRelaxNGPtr': ('._o', "relaxNgSchema(_obj=%s)", "relaxNgSchema"),
  633:     'xmlRelaxNGParserCtxtPtr': ('._o', "relaxNgParserCtxt(_obj=%s)", "relaxNgParserCtxt"),
  634:     'xmlRelaxNGValidCtxtPtr': ('._o', "relaxNgValidCtxt(_obj=%s)", "relaxNgValidCtxt"),
  635:     'xmlSchemaPtr': ("._o", "Schema(_obj=%s)", "Schema"),
  636:     'xmlSchemaParserCtxtPtr': ("._o", "SchemaParserCtxt(_obj=%s)", "SchemaParserCtxt"),
  637:     'xmlSchemaValidCtxtPtr': ("._o", "SchemaValidCtxt(_obj=%s)", "SchemaValidCtxt"),
  638: }
  639: 
  640: converter_type = {
  641:     "xmlXPathObjectPtr": "xpathObjectRet(%s)",
  642: }
  643: 
  644: primary_classes = ["xmlNode", "xmlDoc"]
  645: 
  646: classes_ancestor = {
  647:     "xmlNode" : "xmlCore",
  648:     "xmlDtd" : "xmlNode",
  649:     "xmlDoc" : "xmlNode",
  650:     "xmlAttr" : "xmlNode",
  651:     "xmlNs" : "xmlNode",
  652:     "xmlEntity" : "xmlNode",
  653:     "xmlElement" : "xmlNode",
  654:     "xmlAttribute" : "xmlNode",
  655:     "outputBuffer": "ioWriteWrapper",
  656:     "inputBuffer": "ioReadWrapper",
  657:     "parserCtxt": "parserCtxtCore",
  658:     "xmlTextReader": "xmlTextReaderCore",
  659:     "ValidCtxt": "ValidCtxtCore",
  660:     "SchemaValidCtxt": "SchemaValidCtxtCore",
  661:     "relaxNgValidCtxt": "relaxNgValidCtxtCore",
  662: }
  663: classes_destructors = {
  664:     "parserCtxt": "xmlFreeParserCtxt",
  665:     "catalog": "xmlFreeCatalog",
  666:     "URI": "xmlFreeURI",
  667: #    "outputBuffer": "xmlOutputBufferClose",
  668:     "inputBuffer": "xmlFreeParserInputBuffer",
  669:     "xmlReg": "xmlRegFreeRegexp",
  670:     "xmlTextReader": "xmlFreeTextReader",
  671:     "relaxNgSchema": "xmlRelaxNGFree",
  672:     "relaxNgParserCtxt": "xmlRelaxNGFreeParserCtxt",
  673:     "relaxNgValidCtxt": "xmlRelaxNGFreeValidCtxt",
  674:         "Schema": "xmlSchemaFree",
  675:         "SchemaParserCtxt": "xmlSchemaFreeParserCtxt",
  676:         "SchemaValidCtxt": "xmlSchemaFreeValidCtxt",
  677:         "ValidCtxt": "xmlFreeValidCtxt",
  678: }
  679: 
  680: functions_noexcept = {
  681:     "xmlHasProp": 1,
  682:     "xmlHasNsProp": 1,
  683:     "xmlDocSetRootElement": 1,
  684:     "xmlNodeGetNs": 1,
  685:     "xmlNodeGetNsDefs": 1,
  686:     "xmlNextElementSibling": 1,
  687:     "xmlPreviousElementSibling": 1,
  688:     "xmlFirstElementChild": 1,
  689:     "xmlLastElementChild": 1,
  690: }
  691: 
  692: reference_keepers = {
  693:     "xmlTextReader": [('inputBuffer', 'input')],
  694:     "relaxNgValidCtxt": [('relaxNgSchema', 'schema')],
  695:         "SchemaValidCtxt": [('Schema', 'schema')],
  696: }
  697: 
  698: function_classes = {}
  699: 
  700: function_classes["None"] = []
  701: 
  702: def nameFixup(name, classe, type, file):
  703:     listname = classe + "List"
  704:     ll = len(listname)
  705:     l = len(classe)
  706:     if name[0:l] == listname:
  707:         func = name[l:]
  708:         func = func[0:1].lower() + func[1:]
  709:     elif name[0:12] == "xmlParserGet" and file == "python_accessor":
  710:         func = name[12:]
  711:         func = func[0:1].lower() + func[1:]
  712:     elif name[0:12] == "xmlParserSet" and file == "python_accessor":
  713:         func = name[12:]
  714:         func = func[0:1].lower() + func[1:]
  715:     elif name[0:10] == "xmlNodeGet" and file == "python_accessor":
  716:         func = name[10:]
  717:         func = func[0:1].lower() + func[1:]
  718:     elif name[0:9] == "xmlURIGet" and file == "python_accessor":
  719:         func = name[9:]
  720:         func = func[0:1].lower() + func[1:]
  721:     elif name[0:9] == "xmlURISet" and file == "python_accessor":
  722:         func = name[6:]
  723:         func = func[0:1].lower() + func[1:]
  724:     elif name[0:11] == "xmlErrorGet" and file == "python_accessor":
  725:         func = name[11:]
  726:         func = func[0:1].lower() + func[1:]
  727:     elif name[0:17] == "xmlXPathParserGet" and file == "python_accessor":
  728:         func = name[17:]
  729:         func = func[0:1].lower() + func[1:]
  730:     elif name[0:11] == "xmlXPathGet" and file == "python_accessor":
  731:         func = name[11:]
  732:         func = func[0:1].lower() + func[1:]
  733:     elif name[0:11] == "xmlXPathSet" and file == "python_accessor":
  734:         func = name[8:]
  735:         func = func[0:1].lower() + func[1:]
  736:     elif name[0:15] == "xmlOutputBuffer" and file != "python":
  737:         func = name[15:]
  738:         func = func[0:1].lower() + func[1:]
  739:     elif name[0:20] == "xmlParserInputBuffer" and file != "python":
  740:         func = name[20:]
  741:         func = func[0:1].lower() + func[1:]
  742:     elif name[0:9] == "xmlRegexp" and file == "xmlregexp":
  743:         func = "regexp" + name[9:]
  744:     elif name[0:6] == "xmlReg" and file == "xmlregexp":
  745:         func = "regexp" + name[6:]
  746:     elif name[0:20] == "xmlTextReaderLocator" and file == "xmlreader":
  747:         func = name[20:]
  748:     elif name[0:18] == "xmlTextReaderConst" and file == "xmlreader":
  749:         func = name[18:]
  750:     elif name[0:13] == "xmlTextReader" and file == "xmlreader":
  751:         func = name[13:]
  752:     elif name[0:12] == "xmlReaderNew" and file == "xmlreader":
  753:         func = name[9:]
  754:     elif name[0:11] == "xmlACatalog":
  755:         func = name[11:]
  756:         func = func[0:1].lower() + func[1:]
  757:     elif name[0:l] == classe:
  758:         func = name[l:]
  759:         func = func[0:1].lower() + func[1:]
  760:     elif name[0:7] == "libxml_":
  761:         func = name[7:]
  762:         func = func[0:1].lower() + func[1:]
  763:     elif name[0:6] == "xmlGet":
  764:         func = name[6:]
  765:         func = func[0:1].lower() + func[1:]
  766:     elif name[0:3] == "xml":
  767:         func = name[3:]
  768:         func = func[0:1].lower() + func[1:]
  769:     else:
  770:         func = name
  771:     if func[0:5] == "xPath":
  772:         func = "xpath" + func[5:]
  773:     elif func[0:4] == "xPtr":
  774:         func = "xpointer" + func[4:]
  775:     elif func[0:8] == "xInclude":
  776:         func = "xinclude" + func[8:]
  777:     elif func[0:2] == "iD":
  778:         func = "ID" + func[2:]
  779:     elif func[0:3] == "uRI":
  780:         func = "URI" + func[3:]
  781:     elif func[0:4] == "uTF8":
  782:         func = "UTF8" + func[4:]
  783:     elif func[0:3] == 'sAX':
  784:         func = "SAX" + func[3:]
  785:     return func
  786: 
  787: 
  788: def functionCompare(info1, info2):
  789:     (index1, func1, name1, ret1, args1, file1) = info1
  790:     (index2, func2, name2, ret2, args2, file2) = info2
  791:     if file1 == file2:
  792:         if func1 < func2:
  793:             return -1
  794:         if func1 > func2:
  795:             return 1
  796:     if file1 == "python_accessor":
  797:         return -1
  798:     if file2 == "python_accessor":
  799:         return 1
  800:     if file1 < file2:
  801:         return -1
  802:     if file1 > file2:
  803:         return 1
  804:     return 0
  805: 
  806: def cmp_to_key(mycmp):
  807:     'Convert a cmp= function into a key= function'
  808:     class K(object):
  809:         def __init__(self, obj, *args):
  810:             self.obj = obj
  811:         def __lt__(self, other):
  812:             return mycmp(self.obj, other.obj) < 0
  813:         def __gt__(self, other):
  814:             return mycmp(self.obj, other.obj) > 0
  815:         def __eq__(self, other):
  816:             return mycmp(self.obj, other.obj) == 0
  817:         def __le__(self, other):
  818:             return mycmp(self.obj, other.obj) <= 0
  819:         def __ge__(self, other):
  820:             return mycmp(self.obj, other.obj) >= 0
  821:         def __ne__(self, other):
  822:             return mycmp(self.obj, other.obj) != 0
  823:     return K
  824: def writeDoc(name, args, indent, output):
  825:      if functions[name][0] is None or functions[name][0] == "":
  826:          return
  827:      val = functions[name][0]
  828:      val = val.replace("NULL", "None")
  829:      output.write(indent)
  830:      output.write('"""')
  831:      while len(val) > 60:
  832:          if val[0] == " ":
  833:              val = val[1:]
  834:              continue
  835:          str = val[0:60]
  836:          i = str.rfind(" ")
  837:          if i < 0:
  838:              i = 60
  839:          str = val[0:i]
  840:          val = val[i:]
  841:          output.write(str)
  842:          output.write('\n  ')
  843:          output.write(indent)
  844:      output.write(val)
  845:      output.write(' """\n')
  846: 
  847: def buildWrappers():
  848:     global ctypes
  849:     global py_types
  850:     global py_return_types
  851:     global unknown_types
  852:     global functions
  853:     global function_classes
  854:     global classes_type
  855:     global classes_list
  856:     global converter_type
  857:     global primary_classes
  858:     global converter_type
  859:     global classes_ancestor
  860:     global converter_type
  861:     global primary_classes
  862:     global classes_ancestor
  863:     global classes_destructors
  864:     global functions_noexcept
  865: 
  866:     for type in classes_type.keys():
  867:         function_classes[classes_type[type][2]] = []
  868: 
  869:     #
  870:     # Build the list of C types to look for ordered to start
  871:     # with primary classes
  872:     #
  873:     ctypes = []
  874:     classes_list = []
  875:     ctypes_processed = {}
  876:     classes_processed = {}
  877:     for classe in primary_classes:
  878:         classes_list.append(classe)
  879:         classes_processed[classe] = ()
  880:         for type in classes_type.keys():
  881:             tinfo = classes_type[type]
  882:             if tinfo[2] == classe:
  883:                 ctypes.append(type)
  884:                 ctypes_processed[type] = ()
  885:     for type in sorted(classes_type.keys()):
  886:         if type in ctypes_processed:
  887:             continue
  888:         tinfo = classes_type[type]
  889:         if tinfo[2] not in classes_processed:
  890:             classes_list.append(tinfo[2])
  891:             classes_processed[tinfo[2]] = ()
  892: 
  893:         ctypes.append(type)
  894:         ctypes_processed[type] = ()
  895: 
  896:     for name in functions.keys():
  897:         found = 0
  898:         (desc, ret, args, file, cond) = functions[name]
  899:         for type in ctypes:
  900:             classe = classes_type[type][2]
  901: 
  902:             if name[0:3] == "xml" and len(args) >= 1 and args[0][1] == type:
  903:                 found = 1
  904:                 func = nameFixup(name, classe, type, file)
  905:                 info = (0, func, name, ret, args, file)
  906:                 function_classes[classe].append(info)
  907:             elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == type \
  908:                 and file != "python_accessor":
  909:                 found = 1
  910:                 func = nameFixup(name, classe, type, file)
  911:                 info = (1, func, name, ret, args, file)
  912:                 function_classes[classe].append(info)
  913:             elif name[0:4] == "html" and len(args) >= 1 and args[0][1] == type:
  914:                 found = 1
  915:                 func = nameFixup(name, classe, type, file)
  916:                 info = (0, func, name, ret, args, file)
  917:                 function_classes[classe].append(info)
  918:             elif name[0:4] == "html" and len(args) >= 2 and args[1][1] == type \
  919:                 and file != "python_accessor":
  920:                 found = 1
  921:                 func = nameFixup(name, classe, type, file)
  922:                 info = (1, func, name, ret, args, file)
  923:                 function_classes[classe].append(info)
  924:         if found == 1:
  925:             continue
  926:         if name[0:8] == "xmlXPath":
  927:             continue
  928:         if name[0:6] == "xmlStr":
  929:             continue
  930:         if name[0:10] == "xmlCharStr":
  931:             continue
  932:         func = nameFixup(name, "None", file, file)
  933:         info = (0, func, name, ret, args, file)
  934:         function_classes['None'].append(info)
  935:    
  936:     classes = open("libxml2class.py", "w")
  937:     txt = open("libxml2class.txt", "w")
  938:     txt.write("          Generated Classes for libxml2-python\n\n")
  939: 
  940:     txt.write("#\n# Global functions of the module\n#\n\n")
  941:     if "None" in function_classes:
  942:         flist = function_classes["None"]
  943:         flist = sorted(flist, key=cmp_to_key(functionCompare))
  944:         oldfile = ""
  945:         for info in flist:
  946:             (index, func, name, ret, args, file) = info
  947:             if file != oldfile:
  948:                 classes.write("#\n# Functions from module %s\n#\n\n" % file)
  949:                 txt.write("\n# functions from module %s\n" % file)
  950:                 oldfile = file
  951:             classes.write("def %s(" % func)
  952:             txt.write("%s()\n" % func)
  953:             n = 0
  954:             for arg in args:
  955:                 if n != 0:
  956:                     classes.write(", ")
  957:                 classes.write("%s" % arg[0])
  958:                 n = n + 1
  959:             classes.write("):\n")
  960:             writeDoc(name, args, '    ', classes)
  961: 
  962:             for arg in args:
  963:                 if arg[1] in classes_type:
  964:                     classes.write("    if %s is None: %s__o = None\n" %
  965:                                   (arg[0], arg[0]))
  966:                     classes.write("    else: %s__o = %s%s\n" %
  967:                                   (arg[0], arg[0], classes_type[arg[1]][0]))
  968:                 if arg[1] in py_types:
  969:                     (f, t, n, c) = py_types[arg[1]]
  970:                     if t == "File":
  971:                         classes.write("    if %s is not None: %s.flush()\n" % (
  972:                                       arg[0], arg[0]))
  973: 
  974:             if ret[0] != "void":
  975:                 classes.write("    ret = ")
  976:             else:
  977:                 classes.write("    ")
  978:             classes.write("libxml2mod.%s(" % name)
  979:             n = 0
  980:             for arg in args:
  981:                 if n != 0:
  982:                     classes.write(", ")
  983:                 classes.write("%s" % arg[0])
  984:                 if arg[1] in classes_type:
  985:                     classes.write("__o")
  986:                 n = n + 1
  987:             classes.write(")\n")
  988: 
  989: # This may be needed to reposition the I/O, but likely to cause more harm
  990: # than good. Those changes in Python3 really break the model.
  991: #           for arg in args:
  992: #               if arg[1] in py_types:
  993: #                   (f, t, n, c) = py_types[arg[1]]
  994: #                   if t == "File":
  995: #                       classes.write("    if %s is not None: %s.seek(0,0)\n"%(
  996: #                                     arg[0], arg[0]))
  997: 
  998:             if ret[0] != "void":
  999:                 if ret[0] in classes_type:
 1000:                     #
 1001:                     # Raise an exception
 1002:                     #
 1003:                     if name in functions_noexcept:
 1004:                         classes.write("    if ret is None:return None\n")
 1005:                     elif name.find("URI") >= 0:
 1006:                         classes.write(
 1007:                         "    if ret is None:raise uriError('%s() failed')\n"
 1008:                                       % (name))
 1009:                     elif name.find("XPath") >= 0:
 1010:                         classes.write(
 1011:                         "    if ret is None:raise xpathError('%s() failed')\n"
 1012:                                       % (name))
 1013:                     elif name.find("Parse") >= 0:
 1014:                         classes.write(
 1015:                         "    if ret is None:raise parserError('%s() failed')\n"
 1016:                                       % (name))
 1017:                     else:
 1018:                         classes.write(
 1019:                         "    if ret is None:raise treeError('%s() failed')\n"
 1020:                                       % (name))
 1021:                     classes.write("    return ")
 1022:                     classes.write(classes_type[ret[0]][1] % ("ret"))
 1023:                     classes.write("\n")
 1024:                 else:
 1025:                     classes.write("    return ret\n")
 1026:             classes.write("\n")
 1027: 
 1028:     txt.write("\n\n#\n# Set of classes of the module\n#\n\n")
 1029:     for classname in classes_list:
 1030:         if classname == "None":
 1031:             pass
 1032:         else:
 1033:             if classname in classes_ancestor:
 1034:                 txt.write("\n\nClass %s(%s)\n" % (classname,
 1035:                           classes_ancestor[classname]))
 1036:                 classes.write("class %s(%s):\n" % (classname,
 1037:                               classes_ancestor[classname]))
 1038:                 classes.write("    def __init__(self, _obj=None):\n")
 1039:                 if classes_ancestor[classname] == "xmlCore" or \
 1040:                    classes_ancestor[classname] == "xmlNode":
 1041:                     classes.write("        if checkWrapper(_obj) != 0:")
 1042:                     classes.write("            raise TypeError")
 1043:                     classes.write("('%s got a wrong wrapper object type')\n" % \
 1044:                                 classname)
 1045:                 if classname in reference_keepers:
 1046:                     rlist = reference_keepers[classname]
 1047:                     for ref in rlist:
 1048:                         classes.write("        self.%s = None\n" % ref[1])
 1049:                 classes.write("        self._o = _obj\n")
 1050:                 classes.write("        %s.__init__(self, _obj=_obj)\n\n" % (
 1051:                               classes_ancestor[classname]))
 1052:                 if classes_ancestor[classname] == "xmlCore" or \
 1053:                    classes_ancestor[classname] == "xmlNode":
 1054:                     classes.write("    def __repr__(self):\n")
 1055:                     format = "<%s (%%s) object at 0x%%x>" % (classname)
 1056:                     classes.write("        return \"%s\" %% (self.name, int(pos_id (self)))\n\n" % (
 1057:                                   format))
 1058:             else:
 1059:                 txt.write("Class %s()\n" % (classname))
 1060:                 classes.write("class %s:\n" % (classname))
 1061:                 classes.write("    def __init__(self, _obj=None):\n")
 1062:                 if classname in reference_keepers:
 1063:                     list = reference_keepers[classname]
 1064:                     for ref in list:
 1065:                         classes.write("        self.%s = None\n" % ref[1])
 1066:                 classes.write("        if _obj != None:self._o = _obj;return\n")
 1067:                 classes.write("        self._o = None\n\n")
 1068:             destruct=None
 1069:             if classname in classes_destructors:
 1070:                 classes.write("    def __del__(self):\n")
 1071:                 classes.write("        if self._o != None:\n")
 1072:                 classes.write("            libxml2mod.%s(self._o)\n" %
 1073:                               classes_destructors[classname])
 1074:                 classes.write("        self._o = None\n\n")
 1075:                 destruct=classes_destructors[classname]
 1076:             flist = function_classes[classname]
 1077:             flist = sorted(flist, key=cmp_to_key(functionCompare))
 1078:             oldfile = ""
 1079:             for info in flist:
 1080:                 (index, func, name, ret, args, file) = info
 1081:                 #
 1082:                 # Do not provide as method the destructors for the class
 1083:                 # to avoid double free
 1084:                 #
 1085:                 if name == destruct:
 1086:                     continue
 1087:                 if file != oldfile:
 1088:                     if file == "python_accessor":
 1089:                         classes.write("    # accessors for %s\n" % (classname))
 1090:                         txt.write("    # accessors\n")
 1091:                     else:
 1092:                         classes.write("    #\n")
 1093:                         classes.write("    # %s functions from module %s\n" % (
 1094:                                       classname, file))
 1095:                         txt.write("\n    # functions from module %s\n" % file)
 1096:                         classes.write("    #\n\n")
 1097:                 oldfile = file
 1098:                 classes.write("    def %s(self" % func)
 1099:                 txt.write("    %s()\n" % func)
 1100:                 n = 0
 1101:                 for arg in args:
 1102:                     if n != index:
 1103:                         classes.write(", %s" % arg[0])
 1104:                     n = n + 1
 1105:                 classes.write("):\n")
 1106:                 writeDoc(name, args, '        ', classes)
 1107:                 n = 0
 1108:                 for arg in args:
 1109:                     if arg[1] in classes_type:
 1110:                         if n != index:
 1111:                             classes.write("        if %s is None: %s__o = None\n" %
 1112:                                           (arg[0], arg[0]))
 1113:                             classes.write("        else: %s__o = %s%s\n" %
 1114:                                           (arg[0], arg[0], classes_type[arg[1]][0]))
 1115:                     n = n + 1
 1116:                 if ret[0] != "void":
 1117:                     classes.write("        ret = ")
 1118:                 else:
 1119:                     classes.write("        ")
 1120:                 classes.write("libxml2mod.%s(" % name)
 1121:                 n = 0
 1122:                 for arg in args:
 1123:                     if n != 0:
 1124:                         classes.write(", ")
 1125:                     if n != index:
 1126:                         classes.write("%s" % arg[0])
 1127:                         if arg[1] in classes_type:
 1128:                             classes.write("__o")
 1129:                     else:
 1130:                         classes.write("self")
 1131:                         if arg[1] in classes_type:
 1132:                             classes.write(classes_type[arg[1]][0])
 1133:                     n = n + 1
 1134:                 classes.write(")\n")
 1135:                 if ret[0] != "void":
 1136:                     if ret[0] in classes_type:
 1137:                         #
 1138:                         # Raise an exception
 1139:                         #
 1140:                         if name in functions_noexcept:
 1141:                             classes.write(
 1142:                                 "        if ret is None:return None\n")
 1143:                         elif name.find("URI") >= 0:
 1144:                             classes.write(
 1145:                     "        if ret is None:raise uriError('%s() failed')\n"
 1146:                                           % (name))
 1147:                         elif name.find("XPath") >= 0:
 1148:                             classes.write(
 1149:                     "        if ret is None:raise xpathError('%s() failed')\n"
 1150:                                           % (name))
 1151:                         elif name.find("Parse") >= 0:
 1152:                             classes.write(
 1153:                     "        if ret is None:raise parserError('%s() failed')\n"
 1154:                                           % (name))
 1155:                         else:
 1156:                             classes.write(
 1157:                     "        if ret is None:raise treeError('%s() failed')\n"
 1158:                                           % (name))
 1159: 
 1160:                         #
 1161:                         # generate the returned class wrapper for the object
 1162:                         #
 1163:                         classes.write("        __tmp = ")
 1164:                         classes.write(classes_type[ret[0]][1] % ("ret"))
 1165:                         classes.write("\n")
 1166: 
 1167:                         #
 1168:                         # Sometime one need to keep references of the source
 1169:                         # class in the returned class object.
 1170:                         # See reference_keepers for the list
 1171:                         #
 1172:                         tclass = classes_type[ret[0]][2]
 1173:                         if tclass in reference_keepers:
 1174:                             list = reference_keepers[tclass]
 1175:                             for pref in list:
 1176:                                 if pref[0] == classname:
 1177:                                     classes.write("        __tmp.%s = self\n" %
 1178:                                                   pref[1])
 1179:                         #
 1180:                         # return the class
 1181:                         #
 1182:                         classes.write("        return __tmp\n")
 1183:                     elif ret[0] in converter_type:
 1184:                         #
 1185:                         # Raise an exception
 1186:                         #
 1187:                         if name in functions_noexcept:
 1188:                             classes.write(
 1189:                                 "        if ret is None:return None")
 1190:                         elif name.find("URI") >= 0:
 1191:                             classes.write(
 1192:                     "        if ret is None:raise uriError('%s() failed')\n"
 1193:                                           % (name))
 1194:                         elif name.find("XPath") >= 0:
 1195:                             classes.write(
 1196:                     "        if ret is None:raise xpathError('%s() failed')\n"
 1197:                                           % (name))
 1198:                         elif name.find("Parse") >= 0:
 1199:                             classes.write(
 1200:                     "        if ret is None:raise parserError('%s() failed')\n"
 1201:                                           % (name))
 1202:                         else:
 1203:                             classes.write(
 1204:                     "        if ret is None:raise treeError('%s() failed')\n"
 1205:                                           % (name))
 1206:                         classes.write("        return ")
 1207:                         classes.write(converter_type[ret[0]] % ("ret"))
 1208:                         classes.write("\n")
 1209:                     else:
 1210:                         classes.write("        return ret\n")
 1211:                 classes.write("\n")
 1212: 
 1213:     #
 1214:     # Generate enum constants
 1215:     #
 1216:     for type,enum in enums.items():
 1217:         classes.write("# %s\n" % type)
 1218:         items = enum.items()
 1219:         items = sorted(items, key=(lambda i: int(i[1])))
 1220:         for name,value in items:
 1221:             classes.write("%s = %s\n" % (name,value))
 1222:         classes.write("\n")
 1223: 
 1224:     txt.close()
 1225:     classes.close()
 1226: 
 1227: buildStubs()
 1228: buildWrappers()

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>