diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rwxr-xr-x | python/generator.py | 3 | ||||
-rw-r--r-- | python/libxml.c | 231 | ||||
-rw-r--r-- | python/libxml.py | 19 | ||||
-rw-r--r-- | python/libxml2class.txt | 5 | ||||
-rw-r--r-- | python/libxml_wrap.h | 14 | ||||
-rw-r--r-- | python/tests/Makefile.am | 4 | ||||
-rwxr-xr-x | python/tests/ctxterror.py | 55 | ||||
-rw-r--r-- | python/types.c | 1 |
9 files changed, 312 insertions, 29 deletions
@@ -1,3 +1,12 @@ +Tue Jan 14 12:40:29 CET 2003 Daniel Veillard <daniel@veillard.com> + + * python/generator.py python/libxml.c python/libxml.py + python/libxml_wrap.h python/types.c: applied and fixed a patch + from Stephane Bibould to provide per parser error handlers at the + Python level. + * python/tests/Makefile.am python/tests/ctxterror.py: added a + regression test for it. + Tue Jan 14 01:15:04 CET 2003 Daniel Veillard <daniel@veillard.com> * xmlreader.c: fixed the streaming property of the reader, diff --git a/python/generator.py b/python/generator.py index 9adbfbee..f8a1e0b2 100755 --- a/python/generator.py +++ b/python/generator.py @@ -290,6 +290,8 @@ unknown_types = {} def skip_function(name): if name[0:12] == "xmlXPathWrap": return 1 + if name == "xmlFreeParserCtxt": + return 1 # if name[0:11] == "xmlXPathNew": # return 1 return 0 @@ -618,6 +620,7 @@ classes_ancestor = { "xmlAttribute" : "xmlNode", "outputBuffer": "ioWriteWrapper", "inputBuffer": "ioReadWrapper", + "parserCtxt": "parserCtxtCore", } classes_destructors = { "parserCtxt": "xmlFreeParserCtxt", diff --git a/python/libxml.c b/python/libxml.c index b67c4ebe..15a30b5a 100644 --- a/python/libxml.c +++ b/python/libxml.c @@ -1176,6 +1176,32 @@ libxml_htmlSAXParseFile(ATTRIBUTE_UNUSED PyObject * self, PyObject * args) return (Py_None); } +PyObject * +libxml_xmlFreeParserCtxt(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) { + xmlParserCtxtPtr ctxt; + PyObject *pyobj_ctxt; + xmlParserCtxtPyCtxtPtr pyCtxt; + + if (!PyArg_ParseTuple(args, (char *)"O:xmlFreeParserCtxt", &pyobj_ctxt)) + return(NULL); + ctxt = (xmlParserCtxtPtr) PyparserCtxt_Get(pyobj_ctxt); + + if (ctxt != NULL) { + pyCtxt = (xmlParserCtxtPyCtxtPtr)((xmlParserCtxtPtr)ctxt)->_private; + if (pyCtxt) { + Py_XDECREF(pyCtxt->errorFunc); + Py_XDECREF(pyCtxt->errorFuncArg); + Py_XDECREF(pyCtxt->warningFunc); + Py_XDECREF(pyCtxt->warningFuncArg); + xmlFree(pyCtxt); + } + xmlFreeParserCtxt(ctxt); + } + + Py_INCREF(Py_None); + return(Py_None); +} + /************************************************************************ * * * Error message callback * @@ -1185,13 +1211,43 @@ libxml_htmlSAXParseFile(ATTRIBUTE_UNUSED PyObject * self, PyObject * args) static PyObject *libxml_xmlPythonErrorFuncHandler = NULL; static PyObject *libxml_xmlPythonErrorFuncCtxt = NULL; -static void -libxml_xmlErrorFuncHandler(ATTRIBUTE_UNUSED void *ctx, const char *msg, - ...) +/* helper to build a xmlMalloc'ed string from a format and va_list */ +static char * +libxml_buildMessage(const char *msg, va_list ap) { int size; int chars; char *larger; + char *str; + + str = (char *) xmlMalloc(150); + if (str == NULL) + return NULL; + + size = 150; + + while (1) { + chars = vsnprintf(str, size, msg, ap); + if ((chars > -1) && (chars < size)) + break; + if (chars > -1) + size += chars + 1; + else + size += 100; + if ((larger = (char *) xmlRealloc(str, size)) == NULL) { + xmlFree(str); + return NULL; + } + str = larger; + } + + return str; +} + +static void +libxml_xmlErrorFuncHandler(ATTRIBUTE_UNUSED void *ctx, const char *msg, + ...) +{ va_list ap; char *str; PyObject *list; @@ -1208,28 +1264,9 @@ libxml_xmlErrorFuncHandler(ATTRIBUTE_UNUSED void *ctx, const char *msg, vfprintf(stdout, msg, ap); va_end(ap); } else { - str = (char *) xmlMalloc(150); - if (str == NULL) - return; - - size = 150; - - while (1) { - va_start(ap, msg); - chars = vsnprintf(str, size, msg, ap); - va_end(ap); - if ((chars > -1) && (chars < size)) - break; - if (chars > -1) - size += chars + 1; - else - size += 100; - if ((larger = (char *) xmlRealloc(str, size)) == NULL) { - xmlFree(str); - return; - } - str = larger; - } + va_start(ap, msg); + str = libxml_buildMessage(msg,ap); + va_end(ap); list = PyTuple_New(2); PyTuple_SetItem(list, 0, libxml_xmlPythonErrorFuncCtxt); @@ -1287,6 +1324,147 @@ libxml_xmlRegisterErrorHandler(ATTRIBUTE_UNUSED PyObject * self, return (py_retval); } + +/************************************************************************ + * * + * Per parserCtxt error handler * + * * + ************************************************************************/ + +static void +libxml_xmlParserCtxtErrorFuncHandler(void *ctxt, const char *msg, ...) +{ + char *str; + va_list ap; + PyObject *list; + PyObject *message; + PyObject *result; + xmlParserCtxtPyCtxtPtr pyCtxt; + +#ifdef DEBUG_ERROR + printf("libxml_xmlParserCtxtErrorFuncHandler(%p, %s, ...) called\n", ctx, msg); +#endif + + pyCtxt = (xmlParserCtxtPyCtxtPtr)((xmlParserCtxtPtr)ctxt)->_private; + + if (pyCtxt->errorFunc == NULL) { + va_start(ap, msg); + vfprintf(stdout, msg, ap); + va_end(ap); + } else { + va_start(ap, msg); + str = libxml_buildMessage(msg,ap); + va_end(ap); + + list = PyTuple_New(2); + PyTuple_SetItem(list, 0, pyCtxt->errorFuncArg); + Py_XINCREF(pyCtxt->errorFuncArg); + message = libxml_charPtrWrap(str); + PyTuple_SetItem(list, 1, message); + result = PyEval_CallObject(pyCtxt->errorFunc, list); + Py_XDECREF(list); + Py_XDECREF(result); + } +} + +PyObject * +libxml_xmlSetParserCtxtErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) +{ + PyObject *py_retval; + xmlParserCtxtPtr ctxt; + PyObject *pyobj_ctxt; + PyObject *pyobj_f; + PyObject *pyobj_arg; + + if (!PyArg_ParseTuple(args, (char *)"OOO:xmlSetParserCtxtErrorHandler", + &pyobj_ctxt, &pyobj_f, &pyobj_arg)) + return(NULL); + ctxt = (xmlParserCtxtPtr) PyparserCtxt_Get(pyobj_ctxt); + if (ctxt->_private == NULL) { + xmlParserCtxtPyCtxt *pyCtxt; + + pyCtxt = xmlMalloc(sizeof(xmlParserCtxtPyCtxt)); + if (pyCtxt == NULL) { + py_retval = libxml_intWrap(-1); + return(py_retval); + } + memset(pyCtxt,0,sizeof(xmlParserCtxtPyCtxt)); + ctxt->_private = pyCtxt; + } + /* TODO: check f is a function ! */ + Py_XINCREF(pyobj_f); + ((xmlParserCtxtPyCtxt *)ctxt->_private)->errorFunc = pyobj_f; + Py_XINCREF(pyobj_arg); + ((xmlParserCtxtPyCtxt *)ctxt->_private)->errorFuncArg = pyobj_arg; + + ctxt->sax->error = libxml_xmlParserCtxtErrorFuncHandler; + ctxt->vctxt.error = libxml_xmlParserCtxtErrorFuncHandler; + + py_retval = libxml_intWrap(1); + return(py_retval); +} + +static void +libxml_xmlParserCtxtWarningFuncHandler(void *ctxt, const char *msg, ...) +{ + char *str; + va_list ap; + PyObject *list; + PyObject *message; + PyObject *result; + xmlParserCtxtPyCtxtPtr pyCtxt; + +#ifdef DEBUG_ERROR + printf("libxml_xmlParserCtxtWarningFuncHandler(%p, %s, ...) called\n", ctx, msg); +#endif + + pyCtxt = (xmlParserCtxtPyCtxtPtr)((xmlParserCtxtPtr)ctxt)->_private; + + if (pyCtxt->warningFunc == NULL) { + va_start(ap, msg); + vfprintf(stdout, msg, ap); + va_end(ap); + } else { + va_start(ap, msg); + str = libxml_buildMessage(msg,ap); + va_end(ap); + + list = PyTuple_New(2); + PyTuple_SetItem(list, 0, pyCtxt->warningFuncArg); + Py_XINCREF(pyCtxt->warningFuncArg); + message = libxml_charPtrWrap(str); + PyTuple_SetItem(list, 1, message); + result = PyEval_CallObject(pyCtxt->warningFunc, list); + Py_XDECREF(list); + Py_XDECREF(result); + } +} + +PyObject * +libxml_xmlSetParserCtxtWarningHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) +{ + PyObject *py_retval; + xmlParserCtxtPtr ctxt; + PyObject *pyobj_ctxt; + PyObject *pyobj_f; + PyObject *pyobj_arg; + + if (!PyArg_ParseTuple(args, (char *)"OOO:xmlSetParserCtxtWarningHandler", &pyobj_ctxt, &pyobj_f, &pyobj_arg)) + return(NULL); + ctxt = (xmlParserCtxtPtr) PyparserCtxt_Get(pyobj_ctxt); + /* TODO: check f is a function ! */ + Py_XINCREF(pyobj_f); + ((xmlParserCtxtPyCtxt *)ctxt->_private)->warningFunc = pyobj_f; + Py_XINCREF(pyobj_arg); + ((xmlParserCtxtPyCtxt *)ctxt->_private)->warningFuncArg = pyobj_arg; + + ctxt->sax->warning = libxml_xmlParserCtxtWarningFuncHandler; + ctxt->vctxt.warning = libxml_xmlParserCtxtWarningFuncHandler; + + py_retval = libxml_intWrap(1); + return(py_retval); +} + /************************************************************************ * * * XPath extensions * @@ -2196,6 +2374,9 @@ static PyMethodDef libxmlMethods[] = { {(char *) "inputBufferCreate", libxml_xmlCreateInputBuffer, METH_VARARGS, NULL}, {(char *) "setEntityLoader", libxml_xmlSetEntityLoader, METH_VARARGS, NULL}, {(char *)"xmlRegisterErrorHandler", libxml_xmlRegisterErrorHandler, METH_VARARGS, NULL }, + {(char *)"xmlSetParserCtxtErrorHandler", libxml_xmlSetParserCtxtErrorHandler, METH_VARARGS, NULL }, + {(char *)"xmlSetParserCtxtWarningHandler", libxml_xmlSetParserCtxtWarningHandler, METH_VARARGS, NULL }, + {(char *)"xmlFreeParserCtxt", libxml_xmlFreeParserCtxt, METH_VARARGS, NULL }, {NULL, NULL, 0, NULL} }; diff --git a/python/libxml.py b/python/libxml.py index d6c782d8..3e878919 100644 --- a/python/libxml.py +++ b/python/libxml.py @@ -478,6 +478,25 @@ def registerErrorHandler(f, ctx): ret = libxslt.registerErrorHandler(f,ctx) return ret +class parserCtxtCore: + + def __init__(self, _obj=None): + if _obj != None: + self._o = _obj; + return + self._o = None + + def __del__(self): + if self._o != None: + libxml2mod.xmlFreeParserCtxt(self._o) + self._o = None + + def registerErrorHandler(self,f,arg): + libxml2mod.xmlSetParserCtxtErrorHandler(self._o,f,arg) + + def registerWarningHandler(self,f,arg): + libxml2mod.xmlSetParserCtxtWarningHandler(self._o,f,arg) + # WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING # # Everything before this line comes from libxml.py diff --git a/python/libxml2class.txt b/python/libxml2class.txt index a96bd53c..d35d34bd 100644 --- a/python/libxml2class.txt +++ b/python/libxml2class.txt @@ -662,7 +662,9 @@ Class xpathParserContext() xpathTrueFunction() xpathValueFlipSign() xpatherror() -Class parserCtxt() + + +Class parserCtxt(parserCtxtCore) # accessors doc() isValid() @@ -682,7 +684,6 @@ Class parserCtxt() # functions from module parser clearParserCtxt() - freeParserCtxt() initParserCtxt() parseChunk() parseDocument() diff --git a/python/libxml_wrap.h b/python/libxml_wrap.h index e318a15c..c8730caa 100644 --- a/python/libxml_wrap.h +++ b/python/libxml_wrap.h @@ -149,3 +149,17 @@ PyObject * libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp); PyObject * libxml_xmlTextReaderPtrWrap(xmlTextReaderPtr reader); xmlXPathObjectPtr libxml_xmlXPathObjectPtrConvert(PyObject * obj); + +/* + * Data structure that makes the link from the parser context + * to the python wrapper. + */ +typedef struct +{ + PyObject *errorFunc; + PyObject *errorFuncArg; + PyObject *warningFunc; + PyObject *warningFuncArg; +} xmlParserCtxtPyCtxt; +typedef xmlParserCtxtPyCtxt *xmlParserCtxtPyCtxtPtr; + diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am index 6ac6ab17..23c9b553 100644 --- a/python/tests/Makefile.am +++ b/python/tests/Makefile.am @@ -22,8 +22,8 @@ PYTESTS= \ regexp.py \ reader.py \ reader2.py \ - reader3.py - + reader3.py \ + ctxterror.py XMLS= \ tst.xml \ diff --git a/python/tests/ctxterror.py b/python/tests/ctxterror.py new file mode 100755 index 00000000..44589cd5 --- /dev/null +++ b/python/tests/ctxterror.py @@ -0,0 +1,55 @@ +#!/usr/bin/python -u +# +# This test exercise the redirection of error messages with a +# functions defined in Python. +# +import sys +import libxml2 + +# Memory debug specific +libxml2.debugMemory(1) + +expect="""--> Opening and ending tag mismatch: x and y +""" + +err="" +def callback(ctx, str): + global err + + err = err + "%s %s" % (ctx, str) + +s = """<x></y>""" + +parserCtxt = libxml2.createPushParser(None,"",0,"test.xml") +parserCtxt.registerErrorHandler(callback, "-->") +parserCtxt.registerWarningHandler(callback, "-->") +parserCtxt.parseChunk(s,len(s),1) +doc = parserCtxt.doc() +doc.freeDoc() +parserCtxt = None + +if err != expect: + print "error" + print "received %s" %(err) + print "expected %s" %(expect) + sys.exit(1) + +i = 10000 +while i > 0: + parserCtxt = libxml2.createPushParser(None,"",0,"test.xml") + parserCtxt.registerErrorHandler(callback, "-->") + parserCtxt.registerWarningHandler(callback, "-->") + parserCtxt.parseChunk(s,len(s),1) + doc = parserCtxt.doc() + doc.freeDoc() + parserCtxt = None + err = "" + i = i - 1 + +# Memory debug specific +libxml2.cleanupParser() +if libxml2.debugMemory(1) == 0: + print "OK" +else: + print "Memory leak %d bytes" % (libxml2.debugMemory(1)) + libxml2.dumpMemory() diff --git a/python/types.c b/python/types.c index 2c5a13ec..65626202 100644 --- a/python/types.c +++ b/python/types.c @@ -323,6 +323,7 @@ libxml_xmlParserCtxtPtrWrap(xmlParserCtxtPtr ctxt) Py_INCREF(Py_None); return (Py_None); } + ret = PyCObject_FromVoidPtrAndDesc((void *) ctxt, (char *) "xmlParserCtxtPtr", NULL); |