1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2024-10-26 20:25:14 +03:00
libxml2/python/generator.py
Daniel Veillard 2b32e6f34c fixed a problem in the generator where the way functions are remapped as
* python/generator.py: fixed a problem in the generator where
  the way functions are remapped as methods on classes was
  not symetric and dependant on python internal hash order,
  as reported by Stphane Bidoul
Daniel
2003-04-26 12:03:54 +00:00

1133 lines
40 KiB
Python
Executable File

#!/usr/bin/python -u
#
# generate python wrappers from the XML API description
#
functions = {}
import sys
import string
#######################################################################
#
# That part if purely the API acquisition phase from the
# XML API description
#
#######################################################################
import os
import xmllib
try:
import sgmlop
except ImportError:
sgmlop = None # accelerator not available
debug = 0
if sgmlop:
class FastParser:
"""sgmlop based XML parser. this is typically 15x faster
than SlowParser..."""
def __init__(self, target):
# setup callbacks
self.finish_starttag = target.start
self.finish_endtag = target.end
self.handle_data = target.data
# activate parser
self.parser = sgmlop.XMLParser()
self.parser.register(self)
self.feed = self.parser.feed
self.entity = {
"amp": "&", "gt": ">", "lt": "<",
"apos": "'", "quot": '"'
}
def close(self):
try:
self.parser.close()
finally:
self.parser = self.feed = None # nuke circular reference
def handle_entityref(self, entity):
# <string> entity
try:
self.handle_data(self.entity[entity])
except KeyError:
self.handle_data("&%s;" % entity)
else:
FastParser = None
class SlowParser(xmllib.XMLParser):
"""slow but safe standard parser, based on the XML parser in
Python's standard library."""
def __init__(self, target):
self.unknown_starttag = target.start
self.handle_data = target.data
self.unknown_endtag = target.end
xmllib.XMLParser.__init__(self)
def getparser(target = None):
# get the fastest available parser, and attach it to an
# unmarshalling object. return both objects.
if target is None:
target = docParser()
if FastParser:
return FastParser(target), target
return SlowParser(target), target
class docParser:
def __init__(self):
self._methodname = None
self._data = []
self.in_function = 0
def close(self):
if debug:
print "close"
def getmethodname(self):
return self._methodname
def data(self, text):
if debug:
print "data %s" % text
self._data.append(text)
def start(self, tag, attrs):
if debug:
print "start %s, %s" % (tag, attrs)
if tag == 'function':
self._data = []
self.in_function = 1
self.function = None
self.function_args = []
self.function_descr = None
self.function_return = None
self.function_file = None
if attrs.has_key('name'):
self.function = attrs['name']
if attrs.has_key('file'):
self.function_file = attrs['file']
elif tag == 'info':
self._data = []
elif tag == 'arg':
if self.in_function == 1:
self.function_arg_name = None
self.function_arg_type = None
self.function_arg_info = None
if attrs.has_key('name'):
self.function_arg_name = attrs['name']
if attrs.has_key('type'):
self.function_arg_type = attrs['type']
if attrs.has_key('info'):
self.function_arg_info = attrs['info']
elif tag == 'return':
if self.in_function == 1:
self.function_return_type = None
self.function_return_info = None
self.function_return_field = None
if attrs.has_key('type'):
self.function_return_type = attrs['type']
if attrs.has_key('info'):
self.function_return_info = attrs['info']
if attrs.has_key('field'):
self.function_return_field = attrs['field']
def end(self, tag):
if debug:
print "end %s" % tag
if tag == 'function':
if self.function != None:
function(self.function, self.function_descr,
self.function_return, self.function_args,
self.function_file)
self.in_function = 0
elif tag == 'arg':
if self.in_function == 1:
self.function_args.append([self.function_arg_name,
self.function_arg_type,
self.function_arg_info])
elif tag == 'return':
if self.in_function == 1:
self.function_return = [self.function_return_type,
self.function_return_info,
self.function_return_field]
elif tag == 'info':
str = ''
for c in self._data:
str = str + c
if self.in_function == 1:
self.function_descr = str
def function(name, desc, ret, args, file):
global functions
functions[name] = (desc, ret, args, file)
#######################################################################
#
# Some filtering rukes to drop functions/types which should not
# be exposed as-is on the Python interface
#
#######################################################################
skipped_modules = {
'xmlmemory': None,
'DOCBparser': None,
'SAX': None,
'hash': None,
'list': None,
'threads': None,
# 'xpointer': None,
}
skipped_types = {
'int *': "usually a return type",
'xmlSAXHandlerPtr': "not the proper interface for SAX",
'htmlSAXHandlerPtr': "not the proper interface for SAX",
'xmlRMutexPtr': "thread specific, skipped",
'xmlMutexPtr': "thread specific, skipped",
'xmlGlobalStatePtr': "thread specific, skipped",
'xmlListPtr': "internal representation not suitable for python",
'xmlBufferPtr': "internal representation not suitable for python",
'FILE *': None,
}
#######################################################################
#
# Table of remapping to/from the python type or class to the C
# counterpart.
#
#######################################################################
py_types = {
'void': (None, None, None, None),
'int': ('i', None, "int", "int"),
'long': ('i', None, "int", "int"),
'double': ('d', None, "double", "double"),
'unsigned int': ('i', None, "int", "int"),
'xmlChar': ('c', None, "int", "int"),
'unsigned char *': ('z', None, "charPtr", "char *"),
'char *': ('z', None, "charPtr", "char *"),
'const char *': ('z', None, "charPtrConst", "const char *"),
'xmlChar *': ('z', None, "xmlCharPtr", "xmlChar *"),
'const xmlChar *': ('z', None, "xmlCharPtrConst", "const xmlChar *"),
'xmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'const xmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'xmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'const xmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'xmlDtdPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'const xmlDtdPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'xmlDtd *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'const xmlDtd *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'xmlAttrPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'const xmlAttrPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'xmlAttr *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'const xmlAttr *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'xmlEntityPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'const xmlEntityPtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'xmlEntity *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'const xmlEntity *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'xmlElementPtr': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
'const xmlElementPtr': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
'xmlElement *': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
'const xmlElement *': ('O', "xmlElement", "xmlElementPtr", "xmlElementPtr"),
'xmlAttributePtr': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
'const xmlAttributePtr': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
'xmlAttribute *': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
'const xmlAttribute *': ('O', "xmlAttribute", "xmlAttributePtr", "xmlAttributePtr"),
'xmlNsPtr': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
'const xmlNsPtr': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
'xmlNs *': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
'const xmlNs *': ('O', "xmlNode", "xmlNsPtr", "xmlNsPtr"),
'xmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
'const xmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
'xmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
'const xmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
'htmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
'const htmlDocPtr': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
'htmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
'const htmlDoc *': ('O', "xmlNode", "xmlDocPtr", "xmlDocPtr"),
'htmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'const htmlNodePtr': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'htmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'const htmlNode *': ('O', "xmlNode", "xmlNodePtr", "xmlNodePtr"),
'xmlXPathContextPtr': ('O', "xmlXPathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"),
'xmlXPathContext *': ('O', "xpathContext", "xmlXPathContextPtr", "xmlXPathContextPtr"),
'xmlXPathParserContextPtr': ('O', "xmlXPathParserContext", "xmlXPathParserContextPtr", "xmlXPathParserContextPtr"),
'xmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
'xmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
'htmlParserCtxtPtr': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
'htmlParserCtxt *': ('O', "parserCtxt", "xmlParserCtxtPtr", "xmlParserCtxtPtr"),
'xmlCatalogPtr': ('O', "catalog", "xmlCatalogPtr", "xmlCatalogPtr"),
'FILE *': ('O', "File", "FILEPtr", "FILE *"),
'xmlURIPtr': ('O', "URI", "xmlURIPtr", "xmlURIPtr"),
'xmlOutputBufferPtr': ('O', "outputBuffer", "xmlOutputBufferPtr", "xmlOutputBufferPtr"),
'xmlParserInputBufferPtr': ('O', "inputBuffer", "xmlParserInputBufferPtr", "xmlParserInputBufferPtr"),
'xmlRegexpPtr': ('O', "xmlReg", "xmlRegexpPtr", "xmlRegexpPtr"),
'xmlTextReaderLocatorPtr': ('O', "xmlTextReaderLocator", "xmlTextReaderLocatorPtr", "xmlTextReaderLocatorPtr"),
'xmlTextReaderPtr': ('O', "xmlTextReader", "xmlTextReaderPtr", "xmlTextReaderPtr"),
'xmlRelaxNGPtr': ('O', "relaxNgSchema", "xmlRelaxNGPtr", "xmlRelaxNGPtr"),
'xmlRelaxNGParserCtxtPtr': ('O', "relaxNgParserCtxt", "xmlRelaxNGParserCtxtPtr", "xmlRelaxNGParserCtxtPtr"),
'xmlRelaxNGValidCtxtPtr': ('O', "relaxNgValidCtxt", "xmlRelaxNGValidCtxtPtr", "xmlRelaxNGValidCtxtPtr"),
}
py_return_types = {
'xmlXPathObjectPtr': ('O', "foo", "xmlXPathObjectPtr", "xmlXPathObjectPtr"),
}
unknown_types = {}
#######################################################################
#
# This part writes the C <-> Python stubs libxml2-py.[ch] and
# the table libxml2-export.c to add when registrering the Python module
#
#######################################################################
def skip_function(name):
if name[0:12] == "xmlXPathWrap":
return 1
if name == "xmlFreeParserCtxt":
return 1
if name == "xmlFreeTextReader":
return 1
# if name[0:11] == "xmlXPathNew":
# return 1
return 0
def print_function_wrapper(name, output, export, include):
global py_types
global unknown_types
global functions
global skipped_modules
try:
(desc, ret, args, file) = functions[name]
except:
print "failed to get function %s infos"
return
if skipped_modules.has_key(file):
return 0
if skip_function(name) == 1:
return 0
c_call = "";
format=""
format_args=""
c_args=""
c_return=""
c_convert=""
for arg in args:
# This should be correct
if arg[1][0:6] == "const ":
arg[1] = arg[1][6:]
c_args = c_args + " %s %s;\n" % (arg[1], arg[0])
if py_types.has_key(arg[1]):
(f, t, n, c) = py_types[arg[1]]
if f != None:
format = format + f
if t != None:
format_args = format_args + ", &pyobj_%s" % (arg[0])
c_args = c_args + " PyObject *pyobj_%s;\n" % (arg[0])
c_convert = c_convert + \
" %s = (%s) Py%s_Get(pyobj_%s);\n" % (arg[0],
arg[1], t, arg[0]);
else:
format_args = format_args + ", &%s" % (arg[0])
if c_call != "":
c_call = c_call + ", ";
c_call = c_call + "%s" % (arg[0])
else:
if skipped_types.has_key(arg[1]):
return 0
if unknown_types.has_key(arg[1]):
lst = unknown_types[arg[1]]
lst.append(name)
else:
unknown_types[arg[1]] = [name]
return -1
if format != "":
format = format + ":%s" % (name)
if ret[0] == 'void':
if file == "python_accessor":
if args[1][1] == "char *" or args[1][1] == "xmlChar *":
c_call = "\n if (%s->%s != NULL) xmlFree(%s->%s);\n" % (
args[0][0], args[1][0], args[0][0], args[1][0])
c_call = c_call + " %s->%s = xmlStrdup((const xmlChar *)%s);\n" % (args[0][0],
args[1][0], args[1][0])
else:
c_call = "\n %s->%s = %s;\n" % (args[0][0], args[1][0],
args[1][0])
else:
c_call = "\n %s(%s);\n" % (name, c_call);
ret_convert = " Py_INCREF(Py_None);\n return(Py_None);\n"
elif py_types.has_key(ret[0]):
(f, t, n, c) = py_types[ret[0]]
c_return = " %s c_retval;\n" % (ret[0])
if file == "python_accessor" and ret[2] != None:
c_call = "\n c_retval = %s->%s;\n" % (args[0][0], ret[2])
else:
c_call = "\n c_retval = %s(%s);\n" % (name, c_call);
ret_convert = " py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c)
ret_convert = ret_convert + " return(py_retval);\n"
elif py_return_types.has_key(ret[0]):
(f, t, n, c) = py_return_types[ret[0]]
c_return = " %s c_retval;\n" % (ret[0])
c_call = "\n c_retval = %s(%s);\n" % (name, c_call);
ret_convert = " py_retval = libxml_%sWrap((%s) c_retval);\n" % (n,c)
ret_convert = ret_convert + " return(py_retval);\n"
else:
if skipped_types.has_key(ret[0]):
return 0
if unknown_types.has_key(ret[0]):
lst = unknown_types[ret[0]]
lst.append(name)
else:
unknown_types[ret[0]] = [name]
return -1
if file == "debugXML":
include.write("#ifdef LIBXML_DEBUG_ENABLED\n");
export.write("#ifdef LIBXML_DEBUG_ENABLED\n");
output.write("#ifdef LIBXML_DEBUG_ENABLED\n");
elif file == "HTMLtree" or file == "HTMLparser":
include.write("#ifdef LIBXML_HTML_ENABLED\n");
export.write("#ifdef LIBXML_HTML_ENABLED\n");
output.write("#ifdef LIBXML_HTML_ENABLED\n");
elif file == "c14n":
include.write("#ifdef LIBXML_C14N_ENABLED\n");
export.write("#ifdef LIBXML_C14N_ENABLED\n");
output.write("#ifdef LIBXML_C14N_ENABLED\n");
elif file == "xpathInternals" or file == "xpath":
include.write("#ifdef LIBXML_XPATH_ENABLED\n");
export.write("#ifdef LIBXML_XPATH_ENABLED\n");
output.write("#ifdef LIBXML_XPATH_ENABLED\n");
elif file == "xpointer":
include.write("#ifdef LIBXML_XPTR_ENABLED\n");
export.write("#ifdef LIBXML_XPTR_ENABLED\n");
output.write("#ifdef LIBXML_XPTR_ENABLED\n");
elif file == "xinclude":
include.write("#ifdef LIBXML_XINCLUDE_ENABLED\n");
export.write("#ifdef LIBXML_XINCLUDE_ENABLED\n");
output.write("#ifdef LIBXML_XINCLUDE_ENABLED\n");
elif file == "xmlregexp":
include.write("#ifdef LIBXML_REGEXP_ENABLED\n");
export.write("#ifdef LIBXML_REGEXP_ENABLED\n");
output.write("#ifdef LIBXML_REGEXP_ENABLED\n");
elif file == "xmlschemas" or file == "xmlschemastypes" or \
file == "relaxng":
include.write("#ifdef LIBXML_SCHEMAS_ENABLED\n");
export.write("#ifdef LIBXML_SCHEMAS_ENABLED\n");
output.write("#ifdef LIBXML_SCHEMAS_ENABLED\n");
include.write("PyObject * ")
include.write("libxml_%s(PyObject *self, PyObject *args);\n" % (name));
export.write(" { (char *)\"%s\", libxml_%s, METH_VARARGS, NULL },\n" %
(name, name))
if file == "python":
# Those have been manually generated
return 1
if file == "python_accessor" and ret[0] != "void" and ret[2] is None:
# Those have been manually generated
return 1
output.write("PyObject *\n")
output.write("libxml_%s(ATTRIBUTE_UNUSED PyObject *self," % (name))
if format == "":
output.write("ATTRIBUTE_UNUSED ")
output.write(" PyObject *args) {\n")
if ret[0] != 'void':
output.write(" PyObject *py_retval;\n")
if c_return != "":
output.write(c_return)
if c_args != "":
output.write(c_args)
if format != "":
output.write("\n if (!PyArg_ParseTuple(args, (char *)\"%s\"%s))\n" %
(format, format_args))
output.write(" return(NULL);\n")
if c_convert != "":
output.write(c_convert)
output.write(c_call)
output.write(ret_convert)
output.write("}\n\n")
if file == "debugXML":
include.write("#endif /* LIBXML_DEBUG_ENABLED */\n");
export.write("#endif /* LIBXML_DEBUG_ENABLED */\n");
output.write("#endif /* LIBXML_DEBUG_ENABLED */\n");
elif file == "HTMLtree" or file == "HTMLparser":
include.write("#endif /* LIBXML_HTML_ENABLED */\n");
export.write("#endif /* LIBXML_HTML_ENABLED */\n");
output.write("#endif /* LIBXML_HTML_ENABLED */\n");
elif file == "c14n":
include.write("#endif /* LIBXML_C14N_ENABLED */\n");
export.write("#endif /* LIBXML_C14N_ENABLED */\n");
output.write("#endif /* LIBXML_C14N_ENABLED */\n");
elif file == "xpathInternals" or file == "xpath":
include.write("#endif /* LIBXML_XPATH_ENABLED */\n");
export.write("#endif /* LIBXML_XPATH_ENABLED */\n");
output.write("#endif /* LIBXML_XPATH_ENABLED */\n");
elif file == "xpointer":
include.write("#endif /* LIBXML_XPTR_ENABLED */\n");
export.write("#endif /* LIBXML_XPTR_ENABLED */\n");
output.write("#endif /* LIBXML_XPTR_ENABLED */\n");
elif file == "xinclude":
include.write("#endif /* LIBXML_XINCLUDE_ENABLED */\n");
export.write("#endif /* LIBXML_XINCLUDE_ENABLED */\n");
output.write("#endif /* LIBXML_XINCLUDE_ENABLED */\n");
elif file == "xmlregexp":
include.write("#endif /* LIBXML_REGEXP_ENABLED */\n");
export.write("#endif /* LIBXML_REGEXP_ENABLED */\n");
output.write("#endif /* LIBXML_REGEXP_ENABLED */\n");
elif file == "xmlschemas" or file == "xmlschemastypes" or \
file == "relaxng":
include.write("#endif /* LIBXML_SCHEMAS_ENABLED */\n");
export.write("#endif /* LIBXML_SCHEMAS_ENABLED */\n");
output.write("#endif /* LIBXML_SCHEMAS_ENABLED */\n");
return 1
def buildStubs():
global py_types
global py_return_types
global unknown_types
try:
f = open("libxml2-api.xml")
data = f.read()
(parser, target) = getparser()
parser.feed(data)
parser.close()
except IOError, msg:
try:
f = open("../doc/libxml2-api.xml")
data = f.read()
(parser, target) = getparser()
parser.feed(data)
parser.close()
except IOError, msg:
print file, ":", msg
sys.exit(1)
n = len(functions.keys())
print "Found %d functions in libxml2-api.xml" % (n)
py_types['pythonObject'] = ('O', "pythonObject", "pythonObject", "pythonObject")
try:
f = open("libxml2-python-api.xml")
data = f.read()
(parser, target) = getparser()
parser.feed(data)
parser.close()
except IOError, msg:
print file, ":", msg
print "Found %d functions in libxml2-python-api.xml" % (
len(functions.keys()) - n)
nb_wrap = 0
failed = 0
skipped = 0
include = open("libxml2-py.h", "w")
include.write("/* Generated */\n\n")
export = open("libxml2-export.c", "w")
export.write("/* Generated */\n\n")
wrapper = open("libxml2-py.c", "w")
wrapper.write("/* Generated */\n\n")
wrapper.write("#include <Python.h>\n")
# wrapper.write("#include \"config.h\"\n")
wrapper.write("#include <libxml/xmlversion.h>\n")
wrapper.write("#include <libxml/tree.h>\n")
wrapper.write("#include \"libxml_wrap.h\"\n")
wrapper.write("#include \"libxml2-py.h\"\n\n")
for function in functions.keys():
ret = print_function_wrapper(function, wrapper, export, include)
if ret < 0:
failed = failed + 1
del functions[function]
if ret == 0:
skipped = skipped + 1
del functions[function]
if ret == 1:
nb_wrap = nb_wrap + 1
include.close()
export.close()
wrapper.close()
print "Generated %d wrapper functions, %d failed, %d skipped\n" % (nb_wrap,
failed, skipped);
print "Missing type converters: "
for type in unknown_types.keys():
print "%s:%d " % (type, len(unknown_types[type])),
print
#######################################################################
#
# This part writes part of the Python front-end classes based on
# mapping rules between types and classes and also based on function
# renaming to get consistent function names at the Python level
#
#######################################################################
#
# The type automatically remapped to generated classes
#
classes_type = {
"xmlNodePtr": ("._o", "xmlNode(_obj=%s)", "xmlNode"),
"xmlNode *": ("._o", "xmlNode(_obj=%s)", "xmlNode"),
"xmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
"xmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
"htmlDocPtr": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
"htmlxmlDocPtr *": ("._o", "xmlDoc(_obj=%s)", "xmlDoc"),
"xmlAttrPtr": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"),
"xmlAttr *": ("._o", "xmlAttr(_obj=%s)", "xmlAttr"),
"xmlNsPtr": ("._o", "xmlNs(_obj=%s)", "xmlNs"),
"xmlNs *": ("._o", "xmlNs(_obj=%s)", "xmlNs"),
"xmlDtdPtr": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"),
"xmlDtd *": ("._o", "xmlDtd(_obj=%s)", "xmlDtd"),
"xmlEntityPtr": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"),
"xmlEntity *": ("._o", "xmlEntity(_obj=%s)", "xmlEntity"),
"xmlElementPtr": ("._o", "xmlElement(_obj=%s)", "xmlElement"),
"xmlElement *": ("._o", "xmlElement(_obj=%s)", "xmlElement"),
"xmlAttributePtr": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"),
"xmlAttribute *": ("._o", "xmlAttribute(_obj=%s)", "xmlAttribute"),
"xmlXPathContextPtr": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
"xmlXPathContext *": ("._o", "xpathContext(_obj=%s)", "xpathContext"),
"xmlXPathParserContext *": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"),
"xmlXPathParserContextPtr": ("._o", "xpathParserContext(_obj=%s)", "xpathParserContext"),
"xmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
"xmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
"htmlParserCtxtPtr": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
"htmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
"xmlCatalogPtr": ("._o", "catalog(_obj=%s)", "catalog"),
"xmlURIPtr": ("._o", "URI(_obj=%s)", "URI"),
"xmlOutputBufferPtr": ("._o", "outputBuffer(_obj=%s)", "outputBuffer"),
"xmlParserInputBufferPtr": ("._o", "inputBuffer(_obj=%s)", "inputBuffer"),
"xmlRegexpPtr": ("._o", "xmlReg(_obj=%s)", "xmlReg"),
"xmlTextReaderLocatorPtr": ("._o", "xmlTextReaderLocator(_obj=%s)", "xmlTextReaderLocator"),
"xmlTextReaderPtr": ("._o", "xmlTextReader(_obj=%s)", "xmlTextReader"),
'xmlRelaxNGPtr': ('._o', "relaxNgSchema(_obj=%s)", "relaxNgSchema"),
'xmlRelaxNGParserCtxtPtr': ('._o', "relaxNgParserCtxt(_obj=%s)", "relaxNgParserCtxt"),
'xmlRelaxNGValidCtxtPtr': ('._o', "relaxNgValidCtxt(_obj=%s)", "relaxNgValidCtxt"),
}
converter_type = {
"xmlXPathObjectPtr": "xpathObjectRet(%s)",
}
primary_classes = ["xmlNode", "xmlDoc"]
classes_ancestor = {
"xmlNode" : "xmlCore",
"xmlDtd" : "xmlNode",
"xmlDoc" : "xmlNode",
"xmlAttr" : "xmlNode",
"xmlNs" : "xmlNode",
"xmlEntity" : "xmlNode",
"xmlElement" : "xmlNode",
"xmlAttribute" : "xmlNode",
"outputBuffer": "ioWriteWrapper",
"inputBuffer": "ioReadWrapper",
"parserCtxt": "parserCtxtCore",
"xmlTextReader": "xmlTextReaderCore",
}
classes_destructors = {
"parserCtxt": "xmlFreeParserCtxt",
"catalog": "xmlFreeCatalog",
"URI": "xmlFreeURI",
# "outputBuffer": "xmlOutputBufferClose",
"inputBuffer": "xmlFreeParserInputBuffer",
"xmlReg": "xmlRegFreeRegexp",
"xmlTextReader": "xmlFreeTextReader",
"relaxNgSchema": "xmlRelaxNGFree",
"relaxNgParserCtxt": "xmlRelaxNGFreeParserCtxt",
"relaxNgValidCtxt": "xmlRelaxNGFreeValidCtxt",
}
functions_noexcept = {
"xmlHasProp": 1,
"xmlHasNsProp": 1,
"xmlDocSetRootElement": 1,
}
reference_keepers = {
"xmlTextReader": [('inputBuffer', 'input')],
"relaxNgValidCtxt": [('relaxNgSchema', 'schema')],
}
function_classes = {}
function_classes["None"] = []
def nameFixup(name, classe, type, file):
listname = classe + "List"
ll = len(listname)
l = len(classe)
if name[0:l] == listname:
func = name[l:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:12] == "xmlParserGet" and file == "python_accessor":
func = name[12:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:12] == "xmlParserSet" and file == "python_accessor":
func = name[12:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:10] == "xmlNodeGet" and file == "python_accessor":
func = name[10:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:9] == "xmlURIGet" and file == "python_accessor":
func = name[9:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:9] == "xmlURISet" and file == "python_accessor":
func = name[6:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:17] == "xmlXPathParserGet" and file == "python_accessor":
func = name[17:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:11] == "xmlXPathGet" and file == "python_accessor":
func = name[11:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:11] == "xmlXPathSet" and file == "python_accessor":
func = name[8:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:15] == "xmlOutputBuffer" and file != "python":
func = name[15:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:20] == "xmlParserInputBuffer" and file != "python":
func = name[20:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:9] == "xmlRegexp" and file == "xmlregexp":
func = "regexp" + name[9:]
elif name[0:6] == "xmlReg" and file == "xmlregexp":
func = "regexp" + name[6:]
elif name[0:20] == "xmlTextReaderLocator" and file == "xmlreader":
func = name[20:]
elif name[0:13] == "xmlTextReader" and file == "xmlreader":
func = name[13:]
elif name[0:11] == "xmlACatalog":
func = name[11:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:l] == classe:
func = name[l:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:7] == "libxml_":
func = name[7:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:6] == "xmlGet":
func = name[6:]
func = string.lower(func[0:1]) + func[1:]
elif name[0:3] == "xml":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
else:
func = name
if func[0:5] == "xPath":
func = "xpath" + func[5:]
elif func[0:4] == "xPtr":
func = "xpointer" + func[4:]
elif func[0:8] == "xInclude":
func = "xinclude" + func[8:]
elif func[0:2] == "iD":
func = "ID" + func[2:]
elif func[0:3] == "uRI":
func = "URI" + func[3:]
elif func[0:4] == "uTF8":
func = "UTF8" + func[4:]
elif func[0:3] == 'sAX':
func = "SAX" + func[3:]
return func
def functionCompare(info1, info2):
(index1, func1, name1, ret1, args1, file1) = info1
(index2, func2, name2, ret2, args2, file2) = info2
if file1 == file2:
if func1 < func2:
return -1
if func1 > func2:
return 1
if file1 == "python_accessor":
return -1
if file2 == "python_accessor":
return 1
if file1 < file2:
return -1
if file1 > file2:
return 1
return 0
def writeDoc(name, args, indent, output):
if functions[name][0] is None or functions[name][0] == "":
return
val = functions[name][0]
val = string.replace(val, "NULL", "None");
output.write(indent)
output.write('"""')
while len(val) > 60:
str = val[0:60]
i = string.rfind(str, " ");
if i < 0:
i = 60
str = val[0:i]
val = val[i:]
output.write(str)
output.write('\n ');
output.write(indent)
output.write(val);
output.write(' """\n')
def buildWrappers():
global ctypes
global py_types
global py_return_types
global unknown_types
global functions
global function_classes
global classes_type
global classes_list
global converter_type
global primary_classes
global converter_type
global classes_ancestor
global converter_type
global primary_classes
global classes_ancestor
global classes_destructors
global functions_noexcept
for type in classes_type.keys():
function_classes[classes_type[type][2]] = []
#
# Build the list of C types to look for ordered to start
# with primary classes
#
ctypes = []
classes_list = []
ctypes_processed = {}
classes_processed = {}
for classe in primary_classes:
classes_list.append(classe)
classes_processed[classe] = ()
for type in classes_type.keys():
tinfo = classes_type[type]
if tinfo[2] == classe:
ctypes.append(type)
ctypes_processed[type] = ()
for type in classes_type.keys():
if ctypes_processed.has_key(type):
continue
tinfo = classes_type[type]
if not classes_processed.has_key(tinfo[2]):
classes_list.append(tinfo[2])
classes_processed[tinfo[2]] = ()
ctypes.append(type)
ctypes_processed[type] = ()
for name in functions.keys():
found = 0;
(desc, ret, args, file) = functions[name]
for type in ctypes:
classe = classes_type[type][2]
if name[0:3] == "xml" and len(args) >= 1 and args[0][1] == type:
found = 1
func = nameFixup(name, classe, type, file)
info = (0, func, name, ret, args, file)
function_classes[classe].append(info)
elif name[0:3] == "xml" and len(args) >= 2 and args[1][1] == type \
and file != "python_accessor":
found = 1
func = nameFixup(name, classe, type, file)
info = (1, func, name, ret, args, file)
function_classes[classe].append(info)
elif name[0:4] == "html" and len(args) >= 1 and args[0][1] == type:
found = 1
func = nameFixup(name, classe, type, file)
info = (0, func, name, ret, args, file)
function_classes[classe].append(info)
elif name[0:4] == "html" and len(args) >= 2 and args[1][1] == type \
and file != "python_accessor":
found = 1
func = nameFixup(name, classe, type, file)
info = (1, func, name, ret, args, file)
function_classes[classe].append(info)
if found == 1:
continue
if name[0:8] == "xmlXPath":
continue
if name[0:6] == "xmlStr":
continue
if name[0:10] == "xmlCharStr":
continue
func = nameFixup(name, "None", file, file)
info = (0, func, name, ret, args, file)
function_classes['None'].append(info)
classes = open("libxml2class.py", "w")
txt = open("libxml2class.txt", "w")
txt.write(" Generated Classes for libxml2-python\n\n")
txt.write("#\n# Global functions of the module\n#\n\n")
if function_classes.has_key("None"):
flist = function_classes["None"]
flist.sort(functionCompare)
oldfile = ""
for info in flist:
(index, func, name, ret, args, file) = info
if file != oldfile:
classes.write("#\n# Functions from module %s\n#\n\n" % file)
txt.write("\n# functions from module %s\n" % file)
oldfile = file
classes.write("def %s(" % func)
txt.write("%s()\n" % func);
n = 0
for arg in args:
if n != 0:
classes.write(", ")
classes.write("%s" % arg[0])
n = n + 1
classes.write("):\n")
writeDoc(name, args, ' ', classes);
for arg in args:
if classes_type.has_key(arg[1]):
classes.write(" if %s is None: %s__o = None\n" %
(arg[0], arg[0]))
classes.write(" else: %s__o = %s%s\n" %
(arg[0], arg[0], classes_type[arg[1]][0]))
if ret[0] != "void":
classes.write(" ret = ");
else:
classes.write(" ");
classes.write("libxml2mod.%s(" % name)
n = 0
for arg in args:
if n != 0:
classes.write(", ");
classes.write("%s" % arg[0])
if classes_type.has_key(arg[1]):
classes.write("__o");
n = n + 1
classes.write(")\n");
if ret[0] != "void":
if classes_type.has_key(ret[0]):
#
# Raise an exception
#
if functions_noexcept.has_key(name):
classes.write(" if ret is None:return None\n");
elif string.find(name, "URI") >= 0:
classes.write(
" if ret is None:raise uriError('%s() failed')\n"
% (name))
elif string.find(name, "XPath") >= 0:
classes.write(
" if ret is None:raise xpathError('%s() failed')\n"
% (name))
elif string.find(name, "Parse") >= 0:
classes.write(
" if ret is None:raise parserError('%s() failed')\n"
% (name))
else:
classes.write(
" if ret is None:raise treeError('%s() failed')\n"
% (name))
classes.write(" return ");
classes.write(classes_type[ret[0]][1] % ("ret"));
classes.write("\n");
else:
classes.write(" return ret\n");
classes.write("\n");
txt.write("\n\n#\n# Set of classes of the module\n#\n\n")
for classname in classes_list:
if classname == "None":
pass
else:
if classes_ancestor.has_key(classname):
txt.write("\n\nClass %s(%s)\n" % (classname,
classes_ancestor[classname]))
classes.write("class %s(%s):\n" % (classname,
classes_ancestor[classname]))
classes.write(" def __init__(self, _obj=None):\n")
if reference_keepers.has_key(classname):
rlist = reference_keepers[classname]
for ref in rlist:
classes.write(" self.%s = None\n" % ref[1])
classes.write(" self._o = None\n")
classes.write(" %s.__init__(self, _obj=_obj)\n\n" % (
classes_ancestor[classname]))
if classes_ancestor[classname] == "xmlCore" or \
classes_ancestor[classname] == "xmlNode":
classes.write(" def __repr__(self):\n")
format = "<%s (%%s) object at 0x%%x>" % (classname)
classes.write(" return \"%s\" %% (self.name, id (self))\n\n" % (
format))
else:
txt.write("Class %s()\n" % (classname))
classes.write("class %s:\n" % (classname))
classes.write(" def __init__(self, _obj=None):\n")
if reference_keepers.has_key(classname):
list = reference_keepers[classname]
for ref in list:
classes.write(" self.%s = None\n" % ref[1])
classes.write(" if _obj != None:self._o = _obj;return\n")
classes.write(" self._o = None\n\n");
if classes_destructors.has_key(classname):
classes.write(" def __del__(self):\n")
classes.write(" if self._o != None:\n")
classes.write(" libxml2mod.%s(self._o)\n" %
classes_destructors[classname]);
classes.write(" self._o = None\n\n");
flist = function_classes[classname]
flist.sort(functionCompare)
oldfile = ""
for info in flist:
(index, func, name, ret, args, file) = info
if file != oldfile:
if file == "python_accessor":
classes.write(" # accessors for %s\n" % (classname))
txt.write(" # accessors\n")
else:
classes.write(" #\n")
classes.write(" # %s functions from module %s\n" % (
classname, file))
txt.write("\n # functions from module %s\n" % file)
classes.write(" #\n\n")
oldfile = file
classes.write(" def %s(self" % func)
txt.write(" %s()\n" % func);
n = 0
for arg in args:
if n != index:
classes.write(", %s" % arg[0])
n = n + 1
classes.write("):\n")
writeDoc(name, args, ' ', classes);
n = 0
for arg in args:
if classes_type.has_key(arg[1]):
if n != index:
classes.write(" if %s is None: %s__o = None\n" %
(arg[0], arg[0]))
classes.write(" else: %s__o = %s%s\n" %
(arg[0], arg[0], classes_type[arg[1]][0]))
n = n + 1
if ret[0] != "void":
classes.write(" ret = ");
else:
classes.write(" ");
classes.write("libxml2mod.%s(" % name)
n = 0
for arg in args:
if n != 0:
classes.write(", ");
if n != index:
classes.write("%s" % arg[0])
if classes_type.has_key(arg[1]):
classes.write("__o");
else:
classes.write("self");
if classes_type.has_key(arg[1]):
classes.write(classes_type[arg[1]][0])
n = n + 1
classes.write(")\n");
if ret[0] != "void":
if classes_type.has_key(ret[0]):
#
# Raise an exception
#
if functions_noexcept.has_key(name):
classes.write(
" if ret is None:return None\n");
elif string.find(name, "URI") >= 0:
classes.write(
" if ret is None:raise uriError('%s() failed')\n"
% (name))
elif string.find(name, "XPath") >= 0:
classes.write(
" if ret is None:raise xpathError('%s() failed')\n"
% (name))
elif string.find(name, "Parse") >= 0:
classes.write(
" if ret is None:raise parserError('%s() failed')\n"
% (name))
else:
classes.write(
" if ret is None:raise treeError('%s() failed')\n"
% (name))
#
# generate the returned class wrapper for the object
#
classes.write(" __tmp = ");
classes.write(classes_type[ret[0]][1] % ("ret"));
classes.write("\n");
#
# Sometime one need to keep references of the source
# class in the returned class object.
# See reference_keepers for the list
#
tclass = classes_type[ret[0]][2]
if reference_keepers.has_key(tclass):
list = reference_keepers[tclass]
for pref in list:
if pref[0] == classname:
classes.write(" __tmp.%s = self\n" %
pref[1])
#
# return the class
#
classes.write(" return __tmp\n");
elif converter_type.has_key(ret[0]):
#
# Raise an exception
#
if functions_noexcept.has_key(name):
classes.write(
" if ret is None:return None");
elif string.find(name, "URI") >= 0:
classes.write(
" if ret is None:raise uriError('%s() failed')\n"
% (name))
elif string.find(name, "XPath") >= 0:
classes.write(
" if ret is None:raise xpathError('%s() failed')\n"
% (name))
elif string.find(name, "Parse") >= 0:
classes.write(
" if ret is None:raise parserError('%s() failed')\n"
% (name))
else:
classes.write(
" if ret is None:raise treeError('%s() failed')\n"
% (name))
classes.write(" return ");
classes.write(converter_type[ret[0]] % ("ret"));
classes.write("\n");
else:
classes.write(" return ret\n");
classes.write("\n");
txt.close()
classes.close()
buildStubs()
buildWrappers()