From 26f70269c80140a7fb8a7aae9ef09c95efa98e70 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Thu, 16 Jan 2003 22:45:08 +0000 Subject: [PATCH] =?UTF-8?q?applied=20a=20patch=20from=20St=E9phane=20Bidou?= =?UTF-8?q?l=20to=20allow=20per=20XMLtextReader=20error=20and?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * xmlreader.c include/libxml/xmlreader.h python/generator.py python/libxml.c python/libxml.py win32/libxml2.def.src: applied a patch from Stéphane Bidoul to allow per XMLtextReader error and warning handling * python/tests/Makefile.am python/tests/readererr.py: adding the specific regression test Daniel --- ChangeLog | 9 ++ include/libxml/xmlreader.h | 24 ++++++ python/generator.py | 3 + python/libxml.c | 167 +++++++++++++++++++++++++++++++++++++ python/libxml.py | 30 +++++++ python/libxml2class.txt | 5 +- python/tests/Makefile.am | 3 +- win32/libxml2.def.src | 3 + xmlreader.c | 149 +++++++++++++++++++++++++++++++++ 9 files changed, 390 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index b1345721..7c834c19 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +Fri Jan 17 00:31:30 CET 2003 Daniel Veillard + + * xmlreader.c include/libxml/xmlreader.h python/generator.py + python/libxml.c python/libxml.py win32/libxml2.def.src: applied + a patch from Stéphane Bidoul to allow per XMLtextReader error + and warning handling + * python/tests/Makefile.am python/tests/readererr.py: adding the + specific regression test + Tue Jan 14 17:00:08 CET 2003 Daniel Veillard * xpath.c: Alexey Efimov pointed out that concat('a', 'b', ) diff --git a/include/libxml/xmlreader.h b/include/libxml/xmlreader.h index 457dcd52..53314b1b 100644 --- a/include/libxml/xmlreader.h +++ b/include/libxml/xmlreader.h @@ -23,6 +23,13 @@ typedef enum { XML_PARSER_SUBST_ENTITIES = 4 } xmlParserProperties; +typedef enum { + XMLREADER_SEVERITY_VALIDITY_WARNING = 1, + XMLREADER_SEVERITY_VALIDITY_ERROR = 2, + XMLREADER_SEVERITY_WARNING = 3, + XMLREADER_SEVERITY_ERROR = 4 +} xmlReaderSeverities; + typedef struct _xmlTextReader xmlTextReader; typedef xmlTextReader *xmlTextReaderPtr; @@ -99,6 +106,23 @@ int xmlTextReaderGetParserProp (xmlTextReaderPtr reader, int prop); xmlNodePtr xmlTextReaderCurrentNode (xmlTextReaderPtr reader); xmlDocPtr xmlTextReaderCurrentDoc (xmlTextReaderPtr reader); + +/* + * Error handling extensions + */ +typedef void (*xmlTextReaderErrorFunc) (void *arg, + const char *msg, + int line, + int col, + const char *URI, + xmlReaderSeverities severity); +void xmlTextReaderSetErrorHandler (xmlTextReaderPtr reader, + xmlTextReaderErrorFunc f, + void *arg); +void xmlTextReaderGetErrorHandler (xmlTextReaderPtr reader, + xmlTextReaderErrorFunc *f, + void **arg); + #ifdef __cplusplus } #endif diff --git a/python/generator.py b/python/generator.py index f8a1e0b2..cc1b41b0 100755 --- a/python/generator.py +++ b/python/generator.py @@ -292,6 +292,8 @@ def skip_function(name): return 1 if name == "xmlFreeParserCtxt": return 1 + if name == "xmlFreeTextReader": + return 1 # if name[0:11] == "xmlXPathNew": # return 1 return 0 @@ -621,6 +623,7 @@ classes_ancestor = { "outputBuffer": "ioWriteWrapper", "inputBuffer": "ioReadWrapper", "parserCtxt": "parserCtxtCore", + "xmlTextReader": "xmlTextReaderCore", } classes_destructors = { "parserCtxt": "xmlFreeParserCtxt", diff --git a/python/libxml.c b/python/libxml.c index f1b0d6a2..a762ac7e 100644 --- a/python/libxml.c +++ b/python/libxml.c @@ -1485,6 +1485,170 @@ libxml_xmlSetParserCtxtWarningHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject return(py_retval); } +/************************************************************************ + * * + * Per xmlTextReader error handler * + * * + ************************************************************************/ + +typedef struct +{ + PyObject *f; + PyObject *arg; +} xmlTextReaderPyCtxt; +typedef xmlTextReaderPyCtxt *xmlTextReaderPyCtxtPtr; + +static void +libxml_xmlTextReaderErrorCallback(void *arg, + const char *msg, + int line, + int col, + const char *URI, + int severity) +{ + xmlTextReaderPyCtxt *pyCtxt = (xmlTextReaderPyCtxt *)arg; + PyObject *list; + PyObject *result; + + list = PyTuple_New(6); + PyTuple_SetItem(list, 0, pyCtxt->arg); + Py_XINCREF(pyCtxt->arg); + PyTuple_SetItem(list, 1, libxml_charPtrConstWrap(msg)); + PyTuple_SetItem(list, 2, libxml_intWrap(line)); + PyTuple_SetItem(list, 3, libxml_intWrap(col)); + PyTuple_SetItem(list, 4, libxml_charPtrConstWrap(URI)); + PyTuple_SetItem(list, 5, libxml_intWrap(severity)); + result = PyEval_CallObject(pyCtxt->f, list); + if (result == NULL) + { + /* TODO: manage for the exception to be go up... */ + PyErr_Print(); + } + Py_XDECREF(list); + Py_XDECREF(result); +} + +PyObject * +libxml_xmlTextReaderSetErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) +{ + xmlTextReaderPtr reader; + xmlTextReaderPyCtxtPtr pyCtxt; + xmlTextReaderErrorFunc f; + void *arg; + PyObject *pyobj_reader; + PyObject *pyobj_f; + PyObject *pyobj_arg; + PyObject *py_retval; + + if (!PyArg_ParseTuple(args, (char *)"OOO:xmlTextReaderSetErrorHandler", &pyobj_reader, &pyobj_f, &pyobj_arg)) + return(NULL); + reader = (xmlTextReaderPtr) PyxmlTextReader_Get(pyobj_reader); + /* clear previous error handler */ + xmlTextReaderGetErrorHandler(reader,&f,&arg); + if (arg != NULL) { + if (f == libxml_xmlTextReaderErrorCallback) { + /* ok, it's our error handler! */ + pyCtxt = (xmlTextReaderPyCtxtPtr)arg; + Py_XDECREF(pyCtxt->f); + Py_XDECREF(pyCtxt->arg); + xmlFree(pyCtxt); + } + else { + /* + * there already an arg, and it's not ours, + * there is definitely something wrong going on here... + * we don't know how to free it, so we bail out... + */ + py_retval = libxml_intWrap(-1); + return(py_retval); + } + } + xmlTextReaderSetErrorHandler(reader,NULL,NULL); + /* set new error handler */ + if (pyobj_f != Py_None) + { + pyCtxt = (xmlTextReaderPyCtxtPtr)xmlMalloc(sizeof(xmlTextReaderPyCtxt)); + if (pyCtxt == NULL) { + py_retval = libxml_intWrap(-1); + return(py_retval); + } + Py_XINCREF(pyobj_f); + pyCtxt->f = pyobj_f; + Py_XINCREF(pyobj_arg); + pyCtxt->arg = pyobj_arg; + xmlTextReaderSetErrorHandler(reader,libxml_xmlTextReaderErrorCallback,pyCtxt); + } + + py_retval = libxml_intWrap(1); + return(py_retval); +} + +PyObject * +libxml_xmlTextReaderGetErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) +{ + xmlTextReaderPtr reader; + xmlTextReaderPyCtxtPtr pyCtxt; + xmlTextReaderErrorFunc f; + void *arg; + PyObject *pyobj_reader; + PyObject *py_retval; + + if (!PyArg_ParseTuple(args, (char *)"O:xmlTextReaderSetErrorHandler", &pyobj_reader)) + return(NULL); + reader = (xmlTextReaderPtr) PyxmlTextReader_Get(pyobj_reader); + xmlTextReaderGetErrorHandler(reader,&f,&arg); + py_retval = PyTuple_New(2); + if (f == libxml_xmlTextReaderErrorCallback) { + /* ok, it's our error handler! */ + pyCtxt = (xmlTextReaderPyCtxtPtr)arg; + PyTuple_SetItem(py_retval, 0, pyCtxt->f); + Py_XINCREF(pyCtxt->f); + PyTuple_SetItem(py_retval, 1, pyCtxt->arg); + Py_XINCREF(pyCtxt->arg); + } + else + { + /* f is null or it's not our error handler */ + PyTuple_SetItem(py_retval, 0, Py_None); + Py_XINCREF(Py_None); + PyTuple_SetItem(py_retval, 1, Py_None); + Py_XINCREF(Py_None); + } + return(py_retval); +} + +PyObject * +libxml_xmlFreeTextReader(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) { + xmlTextReaderPtr reader; + PyObject *pyobj_reader; + xmlTextReaderPyCtxtPtr pyCtxt; + xmlTextReaderErrorFunc f; + void *arg; + + if (!PyArg_ParseTuple(args, (char *)"O:xmlFreeTextReader", &pyobj_reader)) + return(NULL); + reader = (xmlTextReaderPtr) PyxmlTextReader_Get(pyobj_reader); + + xmlTextReaderGetErrorHandler(reader,&f,&arg); + if (arg != NULL) { + if (f == libxml_xmlTextReaderErrorCallback) { + /* ok, it's our error handler! */ + pyCtxt = (xmlTextReaderPyCtxtPtr)arg; + Py_XDECREF(pyCtxt->f); + Py_XDECREF(pyCtxt->arg); + xmlFree(pyCtxt); + } + /* + * else, something wrong happened, because the error handler is + * not owned by the python bindings... + */ + } + + xmlFreeTextReader(reader); + Py_INCREF(Py_None); + return(Py_None); +} + /************************************************************************ * * * XPath extensions * @@ -2397,6 +2561,9 @@ static PyMethodDef libxmlMethods[] = { {(char *)"xmlSetParserCtxtErrorHandler", libxml_xmlSetParserCtxtErrorHandler, METH_VARARGS, NULL }, {(char *)"xmlSetParserCtxtWarningHandler", libxml_xmlSetParserCtxtWarningHandler, METH_VARARGS, NULL }, {(char *)"xmlFreeParserCtxt", libxml_xmlFreeParserCtxt, METH_VARARGS, NULL }, + {(char *)"xmlTextReaderSetErrorHandler", libxml_xmlTextReaderSetErrorHandler, METH_VARARGS, NULL }, + {(char *)"xmlTextReaderGetErrorHandler", libxml_xmlTextReaderGetErrorHandler, METH_VARARGS, NULL }, + {(char *)"xmlFreeTextReader", libxml_xmlFreeTextReader, METH_VARARGS, NULL }, {NULL, NULL, 0, NULL} }; diff --git a/python/libxml.py b/python/libxml.py index 3e878919..8f9185ca 100644 --- a/python/libxml.py +++ b/python/libxml.py @@ -461,6 +461,14 @@ PARSER_DEFAULTATTRS=2 PARSER_VALIDATE=3 PARSER_SUBST_ENTITIES=4 +# +# For the xmlTextReader error severities +# +XMLREADER_SEVERITY_VALIDITY_WARNING=1 +XMLREADER_SEVERITY_VALIDITY_ERROR=2 +XMLREADER_SEVERITY_WARNING=3 +XMLREADER_SEVERITY_ERROR=4 + # # register the libxml2 error handler # @@ -497,6 +505,28 @@ class parserCtxtCore: def registerWarningHandler(self,f,arg): libxml2mod.xmlSetParserCtxtWarningHandler(self._o,f,arg) +class xmlTextReaderCore: + + def __init__(self, _obj=None): + self.input = None + if _obj != None:self._o = _obj;return + self._o = None + + def __del__(self): + if self._o != None: + libxml2mod.xmlFreeTextReader(self._o) + self._o = None + + def setErrorHandler(self,f,arg): + """Register an error handler that will be called back as + f(arg,msg,line,col,URI,severity).""" + libxml2mod.xmlTextReaderSetErrorHandler(self._o,f,arg) + + def getErrorHandler(self): + """Return (f,arg) as previously registered with setErrorHandler + or (None,None).""" + return libxml2mod.xmlTextReaderGetErrorHandler(self._o) + # 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 d35d34bd..a116126e 100644 --- a/python/libxml2class.txt +++ b/python/libxml2class.txt @@ -558,7 +558,9 @@ Class xmlAttr(xmlNode) freeProp() freePropList() removeProp() -Class xmlTextReader() + + +Class xmlTextReader(xmlTextReaderCore) # functions from module xmlreader AttributeCount() @@ -599,7 +601,6 @@ Class xmlTextReader() SetParserProp() Value() XmlLang() - freeTextReader() Class xmlReg() # functions from module xmlregexp diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am index 23c9b553..55a9acb5 100644 --- a/python/tests/Makefile.am +++ b/python/tests/Makefile.am @@ -23,7 +23,8 @@ PYTESTS= \ reader.py \ reader2.py \ reader3.py \ - ctxterror.py + ctxterror.py\ + readererr.py XMLS= \ tst.xml \ diff --git a/win32/libxml2.def.src b/win32/libxml2.def.src index 3b26afca..8d2a9570 100644 --- a/win32/libxml2.def.src +++ b/win32/libxml2.def.src @@ -1216,6 +1216,9 @@ xmlCleanupPredefinedEntities xmlTextReaderGetParserProp xmlTextReaderCurrentNode xmlTextReaderCurrentDoc + /* Error handling extensions */ + xmlTextReaderSetErrorHandler + xmlTextReaderGetErrorHandler diff --git a/xmlreader.c b/xmlreader.c index 72032174..9ae4b6e2 100644 --- a/xmlreader.c +++ b/xmlreader.c @@ -24,6 +24,7 @@ #include "libxml.h" #include /* for memset() only ! */ +#include #ifdef HAVE_CTYPE_H #include @@ -107,6 +108,10 @@ struct _xmlTextReader { int entNr; /* Depth of the entities stack */ int entMax; /* Max depth of the entities stack */ xmlNodePtr *entTab; /* array of entities */ + + /* error handling */ + xmlTextReaderErrorFunc errorFunc; /* callback function */ + void *errorFuncArg; /* callback function user argument */ }; static const char *xmlTextReaderIsEmpty = "This element is empty"; @@ -2235,6 +2240,150 @@ xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) { return(reader->ctxt->myDoc); } +/************************************************************************ + * * + * Error Handling Extensions * + * * + ************************************************************************/ + +/* helper to build a xmlMalloc'ed string from a format and va_list */ +static char * +xmlTextReaderBuildMessage(const char *msg, va_list ap) { + int size; + int chars; + char *larger; + char *str; + + str = (char *) xmlMalloc(150); + if (str == NULL) { + xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n"); + 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) { + xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n"); + xmlFree(str); + return NULL; + } + str = larger; + } + + return str; +} + +static void +xmlTextReaderGenericError(void *ctxt, int severity, char *str) { + xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt; + xmlTextReaderPtr reader = (xmlTextReaderPtr)ctx->_private; + + if (str != NULL) { + reader->errorFunc(reader->errorFuncArg, + str, + ctx->input->line, + ctx->input->col, + ctx->input->filename, + severity); + xmlFree(str); + } +} + +static void +xmlTextReaderError(void *ctxt, const char *msg, ...) { + va_list ap; + + va_start(ap,msg); + xmlTextReaderGenericError(ctxt, + XMLREADER_SEVERITY_ERROR, + xmlTextReaderBuildMessage(msg,ap)); + va_end(ap); + +} + +static void +xmlTextReaderWarning(void *ctxt, const char *msg, ...) { + va_list ap; + + va_start(ap,msg); + xmlTextReaderGenericError(ctxt, + XMLREADER_SEVERITY_WARNING, + xmlTextReaderBuildMessage(msg,ap)); + va_end(ap); +} + +static void +xmlTextReaderValidityError(void *ctxt, const char *msg, ...) { + va_list ap; + + va_start(ap,msg); + xmlTextReaderGenericError(ctxt, + XMLREADER_SEVERITY_VALIDITY_ERROR, + xmlTextReaderBuildMessage(msg,ap)); + va_end(ap); + +} + +static void +xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) { + va_list ap; + + va_start(ap,msg); + xmlTextReaderGenericError(ctxt, + XMLREADER_SEVERITY_VALIDITY_WARNING, + xmlTextReaderBuildMessage(msg,ap)); + va_end(ap); +} + +/** + * xmlTextReaderSetErrorHandler: + * @reader: the xmlTextReaderPtr used + * @f: the callback function to call on error and warnings + * @arg: a user argument to pass to the callback function + * + * If @f is NULL, the default error and warning handlers are restored. + */ +void +xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader, + xmlTextReaderErrorFunc f, + void *arg) +{ + if (f != NULL) { + reader->ctxt->sax->error = xmlTextReaderError; + reader->ctxt->vctxt.error = xmlTextReaderValidityError; + reader->ctxt->sax->warning = xmlTextReaderWarning; + reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning; + reader->errorFunc = f; + reader->errorFuncArg = arg; + } + else { + /* restore defaults */ + reader->ctxt->sax->error = xmlParserError; + reader->ctxt->vctxt.error = xmlParserValidityError; + reader->ctxt->sax->warning = xmlParserWarning; + reader->ctxt->vctxt.warning = xmlParserValidityWarning; + reader->errorFunc = NULL; + reader->errorFuncArg = NULL; + } +} + +void +xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader, + xmlTextReaderErrorFunc *f, + void **arg) +{ + *f = reader->errorFunc; + *arg = reader->errorFuncArg; +} + /************************************************************************ * * * Utilities *