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/ChangeLog b/ChangeLog
index a43de44..2c5064c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Mon Jan 20 23:25:00 CET 2003 Daniel Veillard <daniel@veillard.com>
+
+	* 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
+
 Sun Jan 19 17:09:28 MST 2003 John Fleck <jfleck@inkstain.net>
 
 	* doc/guidelines.html
diff --git a/include/libxml/xmlreader.h b/include/libxml/xmlreader.h
index 53314b1..e9475a7 100644
--- a/include/libxml/xmlreader.h
+++ b/include/libxml/xmlreader.h
@@ -24,11 +24,11 @@
 } xmlParserProperties;
 
 typedef enum {
-    XMLREADER_SEVERITY_VALIDITY_WARNING = 1,
-    XMLREADER_SEVERITY_VALIDITY_ERROR = 2,
-    XMLREADER_SEVERITY_WARNING = 3,
-    XMLREADER_SEVERITY_ERROR = 4
-} xmlReaderSeverities;
+    XML_PARSER_SEVERITY_VALIDITY_WARNING = 1,
+    XML_PARSER_SEVERITY_VALIDITY_ERROR = 2,
+    XML_PARSER_SEVERITY_WARNING = 3,
+    XML_PARSER_SEVERITY_ERROR = 4
+} xmlParserSeverities;
 
 typedef struct _xmlTextReader xmlTextReader;
 typedef xmlTextReader *xmlTextReaderPtr;
@@ -110,12 +110,14 @@
 /*
  * Error handling extensions
  */
-typedef void (*xmlTextReaderErrorFunc)          (void *arg, 
+typedef void *  xmlTextReaderLocatorPtr;
+typedef void   (*xmlTextReaderErrorFunc)        (void *arg, 
 						 const char *msg,
-						 int line, 
-						 int col, 
-						 const char *URI, 
-						 xmlReaderSeverities severity);
+						 xmlParserSeverities severity,
+						 xmlTextReaderLocatorPtr locator);
+int             xmlTextReaderLocatorLineNumber  (xmlTextReaderLocatorPtr locator);
+/*int             xmlTextReaderLocatorLinePosition(xmlTextReaderLocatorPtr locator);*/
+xmlChar *       xmlTextReaderLocatorBaseURI     (xmlTextReaderLocatorPtr locator);
 void            xmlTextReaderSetErrorHandler    (xmlTextReaderPtr reader, 
 						 xmlTextReaderErrorFunc f, 
 						 void *arg);
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);
+}
+
diff --git a/win32/libxml2.def.src b/win32/libxml2.def.src
index 8d2a957..5023927 100644
--- a/win32/libxml2.def.src
+++ b/win32/libxml2.def.src
@@ -1219,6 +1219,9 @@
 	/* Error handling extensions */
 	xmlTextReaderSetErrorHandler
 	xmlTextReaderGetErrorHandler
+	xmlTextReaderLocatorLineNumber
+	/*xmlTextReaderLocatorLinePosition*/
+	xmlTextReaderLocatorBaseURI
 
 
 
diff --git a/xmlreader.c b/xmlreader.c
index 9ae4b6e..3632376 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -2281,6 +2281,74 @@
     return str;
 }
 
+/**
+ * xmlTextReaderLocatorLineNumber
+ * @locator: the xmlTextReaderLocatorPtr used
+ *
+ * Obtain the line number for the given locator.
+ *
+ * Returns the line number or -1 in case of error.
+ */
+int
+xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
+    /* we know that locator is a xmlParserCtxtPtr */
+    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
+    int ret = -1;
+
+    if (ctx->node != NULL) {
+	ret = xmlGetLineNo(ctx->node);
+    }
+    else {
+	/* inspired from error.c */
+	xmlParserInputPtr input;
+	input = ctx->input;
+	if ((input->filename == NULL) && (ctx->inputNr > 1))
+	    input = ctx->inputTab[ctx->inputNr - 2];
+	if (input != NULL) {
+	    ret = input->line;
+	} 
+	else {
+	    ret = -1;
+	}
+    }
+
+    return ret;
+}
+
+/**
+ * xmlTextReaderLocatorBaseURI
+ * @locator: the xmlTextReaderLocatorPtr used
+ *
+ * Obtain the base URI for the given locator.
+ *
+ * Returns the base URI or NULL in case of error.
+ */
+xmlChar *
+xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
+    /* we know that locator is a xmlParserCtxtPtr */
+    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
+    xmlChar *ret = NULL;
+
+    if (ctx->node != NULL) {
+	ret = xmlNodeGetBase(NULL,ctx->node);
+    }
+    else {
+	/* inspired from error.c */
+	xmlParserInputPtr input;
+	input = ctx->input;
+	if ((input->filename == NULL) && (ctx->inputNr > 1))
+	    input = ctx->inputTab[ctx->inputNr - 2];
+	if (input != NULL) {
+	    ret = xmlStrdup(input->filename);
+	} 
+	else {
+	    ret = NULL;
+	}
+    }
+
+    return ret;
+}
+
 static void
 xmlTextReaderGenericError(void *ctxt, int severity, char *str) {
     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt;
@@ -2289,10 +2357,8 @@
     if (str != NULL) {
 	reader->errorFunc(reader->errorFuncArg,
 			  str,
-			  ctx->input->line,
-			  ctx->input->col,
-			  ctx->input->filename,
-			  severity);
+			  severity,
+			  (xmlTextReaderLocatorPtr)ctx);
 	xmlFree(str);
     }
 }
@@ -2303,7 +2369,7 @@
 
     va_start(ap,msg);
     xmlTextReaderGenericError(ctxt,
-                              XMLREADER_SEVERITY_ERROR,
+                              XML_PARSER_SEVERITY_ERROR,
 	                      xmlTextReaderBuildMessage(msg,ap));
     va_end(ap);
 
@@ -2315,7 +2381,7 @@
 
     va_start(ap,msg);
     xmlTextReaderGenericError(ctxt,
-                              XMLREADER_SEVERITY_WARNING,
+                              XML_PARSER_SEVERITY_WARNING,
 	                      xmlTextReaderBuildMessage(msg,ap));
     va_end(ap);
 }
@@ -2323,24 +2389,37 @@
 static void 
 xmlTextReaderValidityError(void *ctxt, const char *msg, ...) {
     va_list ap;
+    int len = xmlStrlen((const xmlChar *) msg);
 
-    va_start(ap,msg);
-    xmlTextReaderGenericError(ctxt,
-                              XMLREADER_SEVERITY_VALIDITY_ERROR,
-	                      xmlTextReaderBuildMessage(msg,ap));
-    va_end(ap);
-
+    if ((len > 1) && (msg[len - 2] != ':')) {
+	/* 
+	 * some callbacks only report locator information: 
+	 * skip them (mimicking behaviour in error.c) 
+	 */
+	va_start(ap,msg);
+	xmlTextReaderGenericError(ctxt,
+				  XML_PARSER_SEVERITY_VALIDITY_ERROR,
+				  xmlTextReaderBuildMessage(msg,ap));
+	va_end(ap);
+    }
 }
 
 static void 
 xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) {
     va_list ap;
+    int len = xmlStrlen((const xmlChar *) msg);
 
-    va_start(ap,msg);
-    xmlTextReaderGenericError(ctxt,
-                              XMLREADER_SEVERITY_VALIDITY_WARNING,
-	                      xmlTextReaderBuildMessage(msg,ap));
-    va_end(ap);
+    if ((len != 0) && (msg[len - 1] != ':')) {
+	/* 
+	 * some callbacks only report locator information: 
+	 * skip them (mimicking behaviour in error.c) 
+	 */
+	va_start(ap,msg);
+	xmlTextReaderGenericError(ctxt,
+				  XML_PARSER_SEVERITY_VALIDITY_WARNING,
+				  xmlTextReaderBuildMessage(msg,ap));
+	va_end(ap);
+    }
 }
 
 /**
@@ -2349,13 +2428,14 @@
  * @f:	the callback function to call on error and warnings
  * @arg:    a user argument to pass to the callback function
  *
+ * Register a callback function that will be called on error and warnings.
+ *
  * If @f is NULL, the default error and warning handlers are restored.
  */
 void
 xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader, 
 			     xmlTextReaderErrorFunc f, 
-			     void *arg)
-{
+			     void *arg) {
     if (f != NULL) {
 	reader->ctxt->sax->error = xmlTextReaderError;
 	reader->ctxt->vctxt.error = xmlTextReaderValidityError;
@@ -2375,11 +2455,18 @@
     }
 }
 
+/**
+ * xmlTextReaderGetErrorHandler:
+ * @reader:  the xmlTextReaderPtr used
+ * @f:	the callback function or NULL is no callback has been registered
+ * @arg:    a user argument
+ *
+ * Retrieve the error callback function and user argument.
+ */
 void
 xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader, 
 			     xmlTextReaderErrorFunc *f, 
-			     void **arg)
-{
+			     void **arg) {
     *f = reader->errorFunc;
     *arg = reader->errorFuncArg;
 }