[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [xml] Python bindings: per parser context error handlers



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]