[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
Re: [xml] Python bindings: per parser context error handlers
- From: Daniel Veillard <veillard redhat com>
- To: Stéphane Bidoul <stephane bidoul softwareag com>
- Cc: xml gnome org
- Subject: Re: [xml] Python bindings: per parser context error handlers
- Date: Tue, 14 Jan 2003 06:42:47 -0500
On Tue, Jan 14, 2003 at 06:08:03AM -0500, Daniel Veillard wrote:
> On Tue, Jan 14, 2003 at 10:47:28AM +0100, Stéphane Bidoul wrote:
> It applies cleanly, it looks sound overall, but it generate memory
Actually, the more I look at it the less I agree with the code.
libxml_xmlParserCtxtPtrWrap() allocate an empty xmlParserCtxtPyCtxt
each time the parser context reference is passed back to the Python
level. Plus it doesn't not even check if ctxt->_private existed or
not. I think that's wrong.
The ctxt->_private should be set *only* when the Python routine
for associating private handlers to the context is called after checking
that such a block doesn't exist already. I see no reason why
libxml_xmlParserCtxtPtrWrap() should be modified.
I fixed this, integrated ctxterror.py in the python/tests regressions
resulting in the enclosed patch, which was then commited to CVS
thanks,
Daniel
--
Daniel Veillard | Red Hat Network https://rhn.redhat.com/
veillard redhat com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/
http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/
Index: python/generator.py
===================================================================
RCS file: /cvs/gnome/gnome-xml/python/generator.py,v
retrieving revision 1.33
diff -c -r1.33 generator.py
*** python/generator.py 10 Jan 2003 15:21:50 -0000 1.33
--- python/generator.py 14 Jan 2003 11:38:13 -0000
***************
*** 290,295 ****
--- 290,297 ----
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,623 ****
--- 620,626 ----
"xmlAttribute" : "xmlNode",
"outputBuffer": "ioWriteWrapper",
"inputBuffer": "ioReadWrapper",
+ "parserCtxt": "parserCtxtCore",
}
classes_destructors = {
"parserCtxt": "xmlFreeParserCtxt",
Index: python/libxml.c
===================================================================
RCS file: /cvs/gnome/gnome-xml/python/libxml.c,v
retrieving revision 1.34
diff -c -r1.34 libxml.c
*** python/libxml.c 10 Jan 2003 13:14:40 -0000 1.34
--- python/libxml.c 14 Jan 2003 11:38:14 -0000
***************
*** 1176,1181 ****
--- 1176,1207 ----
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,1197 ****
static PyObject *libxml_xmlPythonErrorFuncHandler = NULL;
static PyObject *libxml_xmlPythonErrorFuncCtxt = NULL;
! static void
! libxml_xmlErrorFuncHandler(ATTRIBUTE_UNUSED void *ctx, const char *msg,
! ...)
{
int size;
int chars;
char *larger;
va_list ap;
char *str;
PyObject *list;
--- 1211,1253 ----
static PyObject *libxml_xmlPythonErrorFuncHandler = NULL;
static PyObject *libxml_xmlPythonErrorFuncCtxt = NULL;
! /* 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,1235 ****
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;
! }
list = PyTuple_New(2);
PyTuple_SetItem(list, 0, libxml_xmlPythonErrorFuncCtxt);
--- 1264,1272 ----
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, libxml_xmlPythonErrorFuncCtxt);
***************
*** 1287,1292 ****
--- 1324,1470 ----
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,2201 ****
--- 2374,2382 ----
{(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}
};
Index: python/libxml.py
===================================================================
RCS file: /cvs/gnome/gnome-xml/python/libxml.py,v
retrieving revision 1.20
diff -c -r1.20 libxml.py
*** python/libxml.py 10 Jan 2003 13:14:40 -0000 1.20
--- python/libxml.py 14 Jan 2003 11:38:15 -0000
***************
*** 478,483 ****
--- 478,502 ----
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
Index: python/libxml2class.txt
===================================================================
RCS file: /cvs/gnome/gnome-xml/python/libxml2class.txt,v
retrieving revision 1.34
diff -c -r1.34 libxml2class.txt
*** python/libxml2class.txt 10 Jan 2003 13:14:40 -0000 1.34
--- python/libxml2class.txt 14 Jan 2003 11:38:15 -0000
***************
*** 662,668 ****
xpathTrueFunction()
xpathValueFlipSign()
xpatherror()
! Class parserCtxt()
# accessors
doc()
isValid()
--- 662,670 ----
xpathTrueFunction()
xpathValueFlipSign()
xpatherror()
!
!
! Class parserCtxt(parserCtxtCore)
# accessors
doc()
isValid()
***************
*** 682,688 ****
# functions from module parser
clearParserCtxt()
- freeParserCtxt()
initParserCtxt()
parseChunk()
parseDocument()
--- 684,689 ----
Index: python/libxml_wrap.h
===================================================================
RCS file: /cvs/gnome/gnome-xml/python/libxml_wrap.h,v
retrieving revision 1.14
diff -c -r1.14 libxml_wrap.h
*** python/libxml_wrap.h 27 Dec 2002 11:58:25 -0000 1.14
--- python/libxml_wrap.h 14 Jan 2003 11:38:15 -0000
***************
*** 149,151 ****
--- 149,165 ----
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;
+
Index: python/types.c
===================================================================
RCS file: /cvs/gnome/gnome-xml/python/types.c,v
retrieving revision 1.12
diff -c -r1.12 types.c
*** python/types.c 14 Dec 2002 23:00:34 -0000 1.12
--- python/types.c 14 Jan 2003 11:38:15 -0000
***************
*** 323,328 ****
--- 323,329 ----
Py_INCREF(Py_None);
return (Py_None);
}
+
ret =
PyCObject_FromVoidPtrAndDesc((void *) ctxt,
(char *) "xmlParserCtxtPtr", NULL);
Index: python/tests/Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-xml/python/tests/Makefile.am,v
retrieving revision 1.22
diff -c -r1.22 Makefile.am
*** python/tests/Makefile.am 28 Dec 2002 22:56:33 -0000 1.22
--- python/tests/Makefile.am 14 Jan 2003 11:38:15 -0000
***************
*** 22,29 ****
regexp.py \
reader.py \
reader2.py \
! reader3.py
!
XMLS= \
tst.xml \
--- 22,29 ----
regexp.py \
reader.py \
reader2.py \
! reader3.py \
! ctxterror.py
XMLS= \
tst.xml \
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]