aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rwxr-xr-xpython/generator.py3
-rw-r--r--python/libxml.c231
-rw-r--r--python/libxml.py19
-rw-r--r--python/libxml2class.txt5
-rw-r--r--python/libxml_wrap.h14
-rw-r--r--python/tests/Makefile.am4
-rwxr-xr-xpython/tests/ctxterror.py55
-rw-r--r--python/types.c1
9 files changed, 312 insertions, 29 deletions
diff --git a/ChangeLog b/ChangeLog
index e710c460..a271002c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);