mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-07-28 00:21:53 +03:00
applied and fixed a patch from Stephane Bibould to provide per parser
* 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. Daniel
This commit is contained in:
@ -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",
|
||||
|
231
python/libxml.c
231
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}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
||||
|
@ -22,8 +22,8 @@ PYTESTS= \
|
||||
regexp.py \
|
||||
reader.py \
|
||||
reader2.py \
|
||||
reader3.py
|
||||
|
||||
reader3.py \
|
||||
ctxterror.py
|
||||
|
||||
XMLS= \
|
||||
tst.xml \
|
||||
|
55
python/tests/ctxterror.py
Executable file
55
python/tests/ctxterror.py
Executable file
@ -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()
|
@ -323,6 +323,7 @@ libxml_xmlParserCtxtPtrWrap(xmlParserCtxtPtr ctxt)
|
||||
Py_INCREF(Py_None);
|
||||
return (Py_None);
|
||||
}
|
||||
|
||||
ret =
|
||||
PyCObject_FromVoidPtrAndDesc((void *) ctxt,
|
||||
(char *) "xmlParserCtxtPtr", NULL);
|
||||
|
Reference in New Issue
Block a user