patch from Stéphane Bidoul for better per context error message APIs

* xmlreader.c python/drv_libxml2.py python/generator.py
  python/libxml.c python/libxml.py python/libxml_wrap.h
  python/types.c: patch from Stéphane Bidoul for better per
  context error message APIs
* python/tests/ctxterror.py python/tests/readererr.py:
  update of the tests
Daniel
diff --git a/python/drv_libxml2.py b/python/drv_libxml2.py
index c9951e6..977c868 100644
--- a/python/drv_libxml2.py
+++ b/python/drv_libxml2.py
@@ -9,10 +9,10 @@
 CAVEATS
     - Lexical handlers are supported, except for start/endEntity
       (waiting for XmlReader.ResolveEntity) and start/endDTD
-    - as understand it, libxml2 error handlers are globals (per thread);
-      each call to parse() registers a new error handler, 
-      overwriting any previously registered handler 
-      --> you can't have 2 LibXml2Reader active at the same time
+    - Error callbacks are not exactly synchronous, they tend
+      to be invoked before the corresponding content callback,
+      because the underlying reader interface parses
+      data by chunks of 512 bytes
     
 TODO
     - search for TODO
@@ -34,7 +34,7 @@
 """
 
 __author__  = u"Stéphane Bidoul <sbi@skynet.be>"
-__version__ = "0.2"
+__version__ = "0.3"
 
 import codecs
 import sys
@@ -69,15 +69,27 @@
     raise SAXReaderNotAvailable("libxml2 not available: " \
                                 "import error was: %s" % e)
 
-def _registerErrorHandler(handler):
-    if not sys.modules.has_key('libxslt'):
-        # normal behaviour when libxslt is not imported
-        libxml2.registerErrorHandler(handler,"drv_libxml2")
-    else:
-        # when libxslt is imported, one must
-        # use libxst's error handler instead (see libxml2 bug 102181)
-        import libxslt
-        libxslt.registerErrorHandler(handler,"drv_libxml2")
+class Locator(xmlreader.Locator):
+    """SAX Locator adapter for libxml2.xmlTextReaderLocator"""
+
+    def __init__(self,locator):
+        self.__locator = locator
+
+    def getColumnNumber(self):
+        "Return the column number where the current event ends."
+        return -1
+
+    def getLineNumber(self):
+        "Return the line number where the current event ends."
+        return self.__locator.LineNumber()
+
+    def getPublicId(self):
+        "Return the public identifier for the current event."
+        return None
+
+    def getSystemId(self):
+        "Return the system identifier for the current event."
+        return self.__locator.BaseURI()
 
 class LibXml2Reader(xmlreader.XMLReader):
 
@@ -95,21 +107,30 @@
         # error messages accumulator
         self.__errors = None
 
-    def _errorHandler(self,ctx,str):
+    def _errorHandler(self,arg,msg,severity,locator):
         if self.__errors is None:
             self.__errors = []
-        self.__errors.append(str)
+        self.__errors.append((severity,
+                              SAXParseException(msg,None,
+                                                Locator(locator))))
 
-    def _reportError(self,callback):
-        # TODO: use SAXParseException, but we need a Locator for that
-        # TODO: distinguish warnings from errors
-        msg = "".join(self.__errors)
+    def _reportErrors(self,fatal):
+        for severity,exception in self.__errors:
+            if severity in (libxml2.PARSER_SEVERITY_VALIDITY_WARNING,
+                            libxml2.PARSER_SEVERITY_WARNING):
+                self._err_handler.warning(exception)
+            else:
+                # when fatal is set, the parse will stop;
+                # we consider that the last error reported
+                # is the fatal one.
+                if fatal and exception is self.__errors[-1][1]:
+                    self._err_handler.fatalError(exception)
+                else:
+                    self._err_handler.error(exception)
         self.__errors = None
-        callback(SAXException(msg))
 
     def parse(self, source):
         self.__parsing = 1
-        _registerErrorHandler(self._errorHandler)
         try:
             # prepare source and create reader
             if type(source) in StringTypes:
@@ -118,6 +139,7 @@
                 source = saxutils.prepare_input_source(source)
                 input = libxml2.inputBuffer(source.getByteStream())
                 reader = input.newTextReader(source.getSystemId())
+            reader.SetErrorHandler(self._errorHandler,None)
             # configure reader
             reader.SetParserProp(libxml2.PARSER_LOADDTD,1)
             reader.SetParserProp(libxml2.PARSER_DEFAULTATTRS,1)
@@ -137,21 +159,18 @@
                 # check for errors
                 if r == 1:
                     if not self.__errors is None:
-                        # non-fatal error
-                        self._reportError(self._err_handler.error)
+                        self._reportErrors(0)
                 elif r == 0:
                     if not self.__errors is None:
-                        # non-fatal error
-                        self._reportError(self._err_handler.error)
-                    break
+                        self._reportErrors(0)
+                    break # end of parse
                 else:
-                    # fatal error
                     if not self.__errors is None:
-                        self._reportError(self._err_handler.fatalError)
+                        self._reportErrors(1)
                     else:
                         self._err_handler.fatalError(\
                             SAXException("Read failed (no details available)"))
-                    break
+                    break # fatal parse error
                 # get node type
                 nodeType = reader.NodeType()
                 # Element
@@ -180,6 +199,7 @@
                                        _d(reader.LocalName()))
                             qnames[attName] = qname
                             attrs[attName] = value
+                        reader.MoveToElement()
                         self._cont_handler.startElementNS( \
                             eltName,eltQName,attributesNSImpl) 
                         if reader.IsEmptyElement():
@@ -194,6 +214,7 @@
                         while reader.MoveToNextAttribute():
                             attName = _d(reader.Name())
                             attrs[attName] = _d(reader.Value())
+                        reader.MoveToElement()
                         self._cont_handler.startElement( \
                             eltName,attributesImpl)
                         if reader.IsEmptyElement():
@@ -275,7 +296,6 @@
             reader.Close()
         finally:
             self.__parsing = 0
-            # TODO: unregister error handler?
 
     def setDTDHandler(self, handler):
         # TODO (when supported, the inherited method works just fine)
diff --git a/python/generator.py b/python/generator.py
index cc1b41b..20e89b7 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -271,6 +271,7 @@
     'xmlOutputBufferPtr': ('O', "outputBuffer", "xmlOutputBufferPtr", "xmlOutputBufferPtr"),
     'xmlParserInputBufferPtr': ('O', "inputBuffer", "xmlParserInputBufferPtr", "xmlParserInputBufferPtr"),
     'xmlRegexpPtr': ('O', "xmlReg", "xmlRegexpPtr", "xmlRegexpPtr"),
+    'xmlTextReaderLocatorPtr': ('O', "xmlTextReaderLocator", "xmlTextReaderLocatorPtr", "xmlTextReaderLocatorPtr"),
     'xmlTextReaderPtr': ('O', "xmlTextReader", "xmlTextReaderPtr", "xmlTextReaderPtr"),
 }
 
@@ -602,6 +603,7 @@
     "xmlOutputBufferPtr": ("._o", "outputBuffer(_obj=%s)", "outputBuffer"),
     "xmlParserInputBufferPtr": ("._o", "inputBuffer(_obj=%s)", "inputBuffer"),
     "xmlRegexpPtr": ("._o", "xmlReg(_obj=%s)", "xmlReg"),
+    "xmlTextReaderLocatorPtr": ("._o", "xmlTextReaderLocator(_obj=%s)", "xmlTextReaderLocator"),
     "xmlTextReaderPtr": ("._o", "xmlTextReader(_obj=%s)", "xmlTextReader"),
 }
 
@@ -690,6 +692,8 @@
         func = "regexp" + name[9:]
     elif name[0:6] == "xmlReg" and file == "xmlregexp":
         func = "regexp" + name[6:]
+    elif name[0:20] == "xmlTextReaderLocator" and file == "xmlreader":
+        func = name[20:]
     elif name[0:13] == "xmlTextReader" and file == "xmlreader":
         func = name[13:]
     elif name[0:11] == "xmlACatalog":
diff --git a/python/libxml.c b/python/libxml.c
index a762ac7..0603950 100644
--- a/python/libxml.c
+++ b/python/libxml.c
@@ -1177,32 +1177,6 @@
     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				*
@@ -1332,44 +1306,87 @@
  *									*
  ************************************************************************/
 
-static void 
-libxml_xmlParserCtxtErrorFuncHandler(void *ctxt, const char *msg, ...)
+typedef struct 
 {
-    char *str;
-    va_list ap;
+    PyObject *f;
+    PyObject *arg;
+} xmlParserCtxtPyCtxt;
+typedef xmlParserCtxtPyCtxt *xmlParserCtxtPyCtxtPtr;
+
+static void
+libxml_xmlParserCtxtGenericErrorFuncHandler(void *ctx, int severity, char *str) 
+{
     PyObject *list;
-    PyObject *message;
     PyObject *result;
+    xmlParserCtxtPtr ctxt;
     xmlParserCtxtPyCtxtPtr pyCtxt;
     
 #ifdef DEBUG_ERROR
-    printf("libxml_xmlParserCtxtErrorFuncHandler(%p, %s, ...) called\n", ctx, msg);
+    printf("libxml_xmlParserCtxtGenericErrorFuncHandler(%p, %s, ...) called\n", ctx, msg);
 #endif
 
-    pyCtxt = (xmlParserCtxtPyCtxtPtr)((xmlParserCtxtPtr)ctxt)->_private;
+    ctxt = (xmlParserCtxtPtr)ctx;
+    pyCtxt = (xmlParserCtxtPyCtxtPtr)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);
+    list = PyTuple_New(4);
+    PyTuple_SetItem(list, 0, pyCtxt->arg);
+    Py_XINCREF(pyCtxt->arg);
+    PyTuple_SetItem(list, 1, libxml_charPtrWrap(str));
+    PyTuple_SetItem(list, 2, libxml_intWrap(severity));
+    PyTuple_SetItem(list, 3, Py_None);
+    Py_INCREF(Py_None);
+    result = PyEval_CallObject(pyCtxt->f, list);
+    if (result == NULL) 
+    {
+	/* TODO: manage for the exception to be propagated... */
+	PyErr_Print();
     }
+    Py_XDECREF(list);
+    Py_XDECREF(result);
+}
+
+static void 
+libxml_xmlParserCtxtErrorFuncHandler(void *ctx, const char *msg, ...) 
+{
+    va_list ap;
+
+    va_start(ap, msg);
+    libxml_xmlParserCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_ERROR,libxml_buildMessage(msg,ap));
+    va_end(ap);
+}
+
+static void 
+libxml_xmlParserCtxtWarningFuncHandler(void *ctx, const char *msg, ...) 
+{
+    va_list ap;
+
+    va_start(ap, msg);
+    libxml_xmlParserCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_WARNING,libxml_buildMessage(msg,ap));
+    va_end(ap);
+}
+
+static void 
+libxml_xmlParserCtxtValidityErrorFuncHandler(void *ctx, const char *msg, ...) 
+{
+    va_list ap;
+
+    va_start(ap, msg);
+    libxml_xmlParserCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_VALIDITY_ERROR,libxml_buildMessage(msg,ap));
+    va_end(ap);
+}
+
+static void 
+libxml_xmlParserCtxtValidityWarningFuncHandler(void *ctx, const char *msg, ...) 
+{
+    va_list ap;
+
+    va_start(ap, msg);
+    libxml_xmlParserCtxtGenericErrorFuncHandler(ctx,XML_PARSER_SEVERITY_VALIDITY_WARNING,libxml_buildMessage(msg,ap));
+    va_end(ap);
 }
 
 PyObject *
-libxml_xmlSetParserCtxtErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args)
+libxml_xmlParserCtxtSetErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) 
 {
     PyObject *py_retval;
     xmlParserCtxtPtr ctxt;
@@ -1378,7 +1395,7 @@
     PyObject *pyobj_f;
     PyObject *pyobj_arg;
 
-    if (!PyArg_ParseTuple(args, (char *)"OOO:xmlSetParserCtxtErrorHandler",
+    if (!PyArg_ParseTuple(args, (char *)"OOO:xmlParserCtxtSetErrorHandler",
 		          &pyobj_ctxt, &pyobj_f, &pyobj_arg))
         return(NULL);
     ctxt = (xmlParserCtxtPtr) PyparserCtxt_Get(pyobj_ctxt);
@@ -1392,99 +1409,88 @@
 	ctxt->_private = pyCtxt;
     }
     else {
-	pyCtxt = ctxt->_private;
+	pyCtxt = (xmlParserCtxtPyCtxtPtr)ctxt->_private;
     }
     /* TODO: check f is a function ! */
-    Py_XDECREF(pyCtxt->errorFunc);
+    Py_XDECREF(pyCtxt->f);
     Py_XINCREF(pyobj_f);
-    pyCtxt->errorFunc = pyobj_f;
-    Py_XDECREF(pyCtxt->errorFuncArg);
+    pyCtxt->f = pyobj_f;
+    Py_XDECREF(pyCtxt->arg);
     Py_XINCREF(pyobj_arg);
-    pyCtxt->errorFuncArg = pyobj_arg;
+    pyCtxt->arg = pyobj_arg;
 
-    ctxt->sax->error = libxml_xmlParserCtxtErrorFuncHandler;
-    ctxt->vctxt.error = libxml_xmlParserCtxtErrorFuncHandler;
+    if (pyobj_f != Py_None) {
+	ctxt->sax->error = libxml_xmlParserCtxtErrorFuncHandler;
+	ctxt->sax->warning = libxml_xmlParserCtxtWarningFuncHandler;
+	ctxt->vctxt.error = libxml_xmlParserCtxtValidityErrorFuncHandler;
+	ctxt->vctxt.warning = libxml_xmlParserCtxtValidityWarningFuncHandler;
+    }
+    else {
+	ctxt->sax->error = xmlParserError;
+	ctxt->vctxt.error = xmlParserValidityError;
+	ctxt->sax->warning = xmlParserWarning;
+	ctxt->vctxt.warning = xmlParserValidityWarning;
+    }
 
     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)
+libxml_xmlParserCtxtGetErrorHandler(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) 
 {
     PyObject *py_retval;
     xmlParserCtxtPtr ctxt;
     xmlParserCtxtPyCtxtPtr pyCtxt;
     PyObject *pyobj_ctxt;
-    PyObject *pyobj_f;
-    PyObject *pyobj_arg;
 
-    if (!PyArg_ParseTuple(args, (char *)"OOO:xmlSetParserCtxtWarningHandler", &pyobj_ctxt, &pyobj_f, &pyobj_arg))
+    if (!PyArg_ParseTuple(args, (char *)"O:xmlParserCtxtGetErrorHandler",
+		          &pyobj_ctxt))
         return(NULL);
     ctxt = (xmlParserCtxtPtr) PyparserCtxt_Get(pyobj_ctxt);
-    if (ctxt->_private == NULL) {
-	pyCtxt = xmlMalloc(sizeof(xmlParserCtxtPyCtxt));
-	if (pyCtxt == NULL) {
-	    py_retval = libxml_intWrap(-1);
-	    return(py_retval);
-	}
-	memset(pyCtxt,0,sizeof(xmlParserCtxtPyCtxt));
-	ctxt->_private = pyCtxt;
+    py_retval = PyTuple_New(2);
+    if (ctxt->_private != NULL) {
+	pyCtxt = (xmlParserCtxtPyCtxtPtr)ctxt->_private;
+
+	PyTuple_SetItem(py_retval, 0, pyCtxt->f);
+	Py_XINCREF(pyCtxt->f);
+	PyTuple_SetItem(py_retval, 1, pyCtxt->arg);
+	Py_XINCREF(pyCtxt->arg);
     }
     else {
-	pyCtxt = ctxt->_private;
+	/* no python error handler registered */
+	PyTuple_SetItem(py_retval, 0, Py_None);
+	Py_XINCREF(Py_None);
+	PyTuple_SetItem(py_retval, 1, Py_None);
+	Py_XINCREF(Py_None);
     }
-    /* TODO: check f is a function ! */
-    Py_XDECREF(pyCtxt->warningFunc);
-    Py_XINCREF(pyobj_f);
-    pyCtxt->warningFunc = pyobj_f;
-    Py_XDECREF(pyCtxt->warningFuncArg);
-    Py_XINCREF(pyobj_arg);
-    pyCtxt->warningFuncArg = pyobj_arg;
-
-    ctxt->sax->warning = libxml_xmlParserCtxtWarningFuncHandler;
-    ctxt->vctxt.warning = libxml_xmlParserCtxtWarningFuncHandler;
-
-    py_retval = libxml_intWrap(1);
     return(py_retval);
 }
 
+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->f);
+	    Py_XDECREF(pyCtxt->arg);
+	    xmlFree(pyCtxt);
+	}
+	xmlFreeParserCtxt(ctxt);
+    }
+
+    Py_INCREF(Py_None);
+    return(Py_None);
+}
+
 /************************************************************************
  *									*
  *                      Per xmlTextReader error handler                 *
@@ -1501,27 +1507,23 @@
 static void 
 libxml_xmlTextReaderErrorCallback(void *arg, 
 				  const char *msg,
-				  int line,
-				  int col,
-				  const char *URI,
-				  int severity)
+				  int severity,
+				  xmlTextReaderLocatorPtr locator)
 {
     xmlTextReaderPyCtxt *pyCtxt = (xmlTextReaderPyCtxt *)arg;
     PyObject *list;
     PyObject *result;
     
-    list = PyTuple_New(6);
+    list = PyTuple_New(4);
     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));
+    PyTuple_SetItem(list, 2, libxml_intWrap(severity));
+    PyTuple_SetItem(list, 3, libxml_xmlTextReaderLocatorPtrWrap(locator));
     result = PyEval_CallObject(pyCtxt->f, list);
     if (result == NULL)
     {
-	/* TODO: manage for the exception to be go up... */
+	/* TODO: manage for the exception to be propagated... */
 	PyErr_Print();
     }
     Py_XDECREF(list);
@@ -2558,8 +2560,8 @@
     {(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 *)"xmlParserCtxtSetErrorHandler", libxml_xmlParserCtxtSetErrorHandler, METH_VARARGS, NULL },
+    {(char *)"xmlParserCtxtGetErrorHandler", libxml_xmlParserCtxtGetErrorHandler, METH_VARARGS, NULL },
     {(char *)"xmlFreeParserCtxt", libxml_xmlFreeParserCtxt, METH_VARARGS, NULL },
     {(char *)"xmlTextReaderSetErrorHandler", libxml_xmlTextReaderSetErrorHandler, METH_VARARGS, NULL },
     {(char *)"xmlTextReaderGetErrorHandler", libxml_xmlTextReaderGetErrorHandler, METH_VARARGS, NULL },
diff --git a/python/libxml.py b/python/libxml.py
index 8f9185c..8ffa383 100644
--- a/python/libxml.py
+++ b/python/libxml.py
@@ -462,12 +462,12 @@
 PARSER_SUBST_ENTITIES=4
 
 #
-# For the xmlTextReader error severities
+# For the error callback severities
 #
-XMLREADER_SEVERITY_VALIDITY_WARNING=1
-XMLREADER_SEVERITY_VALIDITY_ERROR=2
-XMLREADER_SEVERITY_WARNING=3
-XMLREADER_SEVERITY_ERROR=4
+PARSER_SEVERITY_VALIDITY_WARNING=1
+PARSER_SEVERITY_VALIDITY_ERROR=2
+PARSER_SEVERITY_WARNING=3
+PARSER_SEVERITY_ERROR=4
 
 #
 # register the libxml2 error handler
@@ -499,11 +499,21 @@
             libxml2mod.xmlFreeParserCtxt(self._o)
 	self._o = None
 
-    def registerErrorHandler(self,f,arg):
-        libxml2mod.xmlSetParserCtxtErrorHandler(self._o,f,arg)
+    def setErrorHandler(self,f,arg):
+        """Register an error handler that will be called back as
+           f(arg,msg,severity,reserved).
+           
+           @reserved is currently always None."""
+        libxml2mod.xmlParserCtxtSetErrorHandler(self._o,f,arg)
 
-    def registerWarningHandler(self,f,arg):
-        libxml2mod.xmlSetParserCtxtWarningHandler(self._o,f,arg)
+    def getErrorHandler(self):
+        """Return (f,arg) as previously registered with setErrorHandler
+           or (None,None)."""
+        return libxml2mod.xmlParserCtxtGetErrorHandler(self._o)
+
+def _xmlTextReaderErrorFunc((f,arg),msg,severity,locator):
+    """Intermediate callback to wrap the locator"""
+    return f(arg,msg,severity,xmlTextReaderLocator(locator))
 
 class xmlTextReaderCore:
 
@@ -517,15 +527,25 @@
             libxml2mod.xmlFreeTextReader(self._o)
         self._o = None
 
-    def setErrorHandler(self,f,arg):
+    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)
+           f(arg,msg,severity,locator)."""
+        if f is None:
+            libxml2mod.xmlTextReaderSetErrorHandler(\
+                self._o,None,None)
+        else:
+            libxml2mod.xmlTextReaderSetErrorHandler(\
+                self._o,_xmlTextReaderErrorFunc,(f,arg))
 
-    def getErrorHandler(self):
+    def GetErrorHandler(self):
         """Return (f,arg) as previously registered with setErrorHandler
            or (None,None)."""
-        return libxml2mod.xmlTextReaderGetErrorHandler(self._o)
+        f,arg = libxml2mod.xmlTextReaderGetErrorHandler(self._o)
+        if f is None:
+            return None,None
+        else:
+            # assert f is _xmlTextReaderErrorFunc
+            return arg
 
 # WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
 #
diff --git a/python/libxml_wrap.h b/python/libxml_wrap.h
index c8730ca..c59b706 100644
--- a/python/libxml_wrap.h
+++ b/python/libxml_wrap.h
@@ -93,6 +93,14 @@
     xmlTextReaderPtr obj;
 } PyxmlTextReader_Object;
 
+#define PyxmlTextReaderLocator_Get(v) (((v) == Py_None) ? NULL : \
+        (((PyxmlTextReaderLocator_Object *)(v))->obj))
+
+typedef struct {
+    PyObject_HEAD
+    xmlTextReaderLocatorPtr obj;
+} PyxmlTextReaderLocator_Object;
+
 #define PyURI_Get(v) (((v) == Py_None) ? NULL : \
 	(((PyURI_Object *)(v))->obj))
 
@@ -147,19 +155,6 @@
 PyObject * libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer);
 PyObject * libxml_xmlRegexpPtrWrap(xmlRegexpPtr regexp);
 PyObject * libxml_xmlTextReaderPtrWrap(xmlTextReaderPtr reader);
+PyObject * libxml_xmlTextReaderLocatorPtrWrap(xmlTextReaderLocatorPtr locator);
 
 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/ctxterror.py b/python/tests/ctxterror.py
index 44589cd..265bb1e 100755
--- a/python/tests/ctxterror.py
+++ b/python/tests/ctxterror.py
@@ -9,20 +9,22 @@
 # Memory debug specific
 libxml2.debugMemory(1)
 
-expect="""--> Opening and ending tag mismatch: x and y
+expect="""--> (3) xmlns: URI foo is not absolute
+--> (4) Opening and ending tag mismatch: x and y
 """
 
 err=""
-def callback(ctx, str):
-     global err
+def callback(arg,msg,severity,reserved):
+    global err
+    err = err + "%s (%d) %s" % (arg,severity,msg)
 
-     err = err + "%s %s" % (ctx, str)
-
-s = """<x></y>"""
+s = """<x xmlns="foo"></y>"""
 
 parserCtxt = libxml2.createPushParser(None,"",0,"test.xml")
-parserCtxt.registerErrorHandler(callback, "-->")
-parserCtxt.registerWarningHandler(callback, "-->")
+parserCtxt.setErrorHandler(callback, "-->")
+if parserCtxt.getErrorHandler() != (callback,"-->"):
+    print "getErrorHandler failed"
+    sys.exit(1)
 parserCtxt.parseChunk(s,len(s),1)
 doc = parserCtxt.doc()
 doc.freeDoc()
@@ -37,8 +39,7 @@
 i = 10000
 while i > 0:
     parserCtxt = libxml2.createPushParser(None,"",0,"test.xml")
-    parserCtxt.registerErrorHandler(callback, "-->")
-    parserCtxt.registerWarningHandler(callback, "-->")
+    parserCtxt.setErrorHandler(callback, "-->")
     parserCtxt.parseChunk(s,len(s),1)
     doc = parserCtxt.doc()
     doc.freeDoc()
diff --git a/python/tests/readererr.py b/python/tests/readererr.py
index abbbba5..dbdeb47 100644
--- a/python/tests/readererr.py
+++ b/python/tests/readererr.py
@@ -13,14 +13,14 @@
 --> (4) test1:1:Opening and ending tag mismatch: c and a
 """
 err=""
-def myErrorHandler(arg,msg,line,col,URI,severity):
+def myErrorHandler(arg,msg,severity,locator):
     global err
-    err = err + "%s (%d) %s:%d:%s" % (arg,severity,URI,line,msg)
+    err = err + "%s (%d) %s:%d:%s" % (arg,severity,locator.BaseURI(),locator.LineNumber(),msg)
 
 f = StringIO.StringIO("""<a xmlns="foo"><b b1="b1"/><c>content of c</a>""")
 input = libxml2.inputBuffer(f)
 reader = input.newTextReader("test1")
-reader.setErrorHandler(myErrorHandler,"-->")
+reader.SetErrorHandler(myErrorHandler,"-->")
 while reader.Read() == 1:
     pass
 
@@ -30,9 +30,9 @@
     print "expected %s" %(expect)
     sys.exit(1)
 
-reader.setErrorHandler(None,None)
-if reader.getErrorHandler() != (None,None):
-    print "getErrorHandler failed"
+reader.SetErrorHandler(None,None)
+if reader.GetErrorHandler() != (None,None):
+    print "GetErrorHandler failed"
     sys.exit(1)
 
 #
diff --git a/python/types.c b/python/types.c
index 6562620..a05c48a 100644
--- a/python/types.c
+++ b/python/types.c
@@ -566,3 +566,22 @@
                                      (char *) "xmlTextReaderPtr", NULL);
     return (ret);
 }
+
+PyObject *
+libxml_xmlTextReaderLocatorPtrWrap(xmlTextReaderLocatorPtr locator)
+{
+    PyObject *ret;
+
+#ifdef DEBUG
+    printf("libxml_xmlTextReaderLocatorPtrWrap: locator = %p\n", locator);
+#endif
+    if (locator == NULL) {
+        Py_INCREF(Py_None);
+        return (Py_None);
+    }
+    ret =
+        PyCObject_FromVoidPtrAndDesc((void *) locator,
+                                     (char *) "xmlTextReaderLocatorPtr", NULL);
+    return (ret);
+}
+