adding error redirections and preformat to a python handler cleanup made

* python/Makefile.am python/libxml.c python/libxml2-python-api.xml
  python/libxml2class.txt: adding error redirections and preformat
  to a python handler
* python/tests/Makefile.am python/tests/*.py: cleanup made all
  tests self checking
Daniel
diff --git a/ChangeLog b/ChangeLog
index 61cb2b6..43d7aa3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Sat Feb  2 22:47:10 CET 2002 Daniel Veillard <daniel@veillard.com>
+
+	* python/Makefile.am python/libxml.c python/libxml2-python-api.xml
+	  python/libxml2class.txt: adding error redirections and preformat
+	  to a python handler
+	* python/tests/Makefile.am python/tests/*.py: cleanup made all
+	  tests self checking
+
 Sat Feb  2 13:18:54 CET 2002 Daniel Veillard <daniel@veillard.com>
 
 	* python/libxml.c python/libxml.py: fixed a stupid bug when renaming
diff --git a/python/Makefile.am b/python/Makefile.am
index a7eca5b..0da7d79 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -2,7 +2,7 @@
 
 LIBS=-L../.libs -L.. $(XML_LIBS)
 INCLUDES=-I/usr/include/python$(PYTHON_VERSION) -I$(PYTHON_INCLUDES) -I$(top_srcdir)/include
-SHCFLAGS=$(INCLUDES) -Wall -fPIC
+SHCFLAGS=$(INCLUDES) -Wall -fPIC -g
 LINK_FLAGS= -shared
 DOCS_DIR = $(prefix)/share/doc/libxml2-python-$(LIBXML_VERSION)
 
diff --git a/python/TODO b/python/TODO
index 0fc997b..d8e39b1 100644
--- a/python/TODO
+++ b/python/TODO
@@ -7,7 +7,6 @@
 
 - handling of node.content
 - SAX interfaces
-- error redirections and preformat
 - memory debug interfaces
 - enums -> libxml.py
 - access to XPath variables
@@ -41,5 +40,6 @@
 - spec file: automatically generate for pythonX.Y if found
   Done, a bit ugly by running new makes in %install for each level
   found.
+- error redirections and preformat
 
 Daniel Veillard
diff --git a/python/libxml.c b/python/libxml.c
index efd2a7a..cca2b04 100644
--- a/python/libxml.c
+++ b/python/libxml.c
@@ -4,12 +4,14 @@
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 #include <libxml/xpath.h>
+#include <libxml/xmlerror.h>
 #include <libxml/xpathInternals.h>
 #include "libxml_wrap.h"
 #include "libxml2-py.h"
 
 /* #define DEBUG */
 /* #define DEBUG_XPATH */
+/* #define DEBUG_ERROR */
 
 /************************************************************************
  *									*
@@ -285,6 +287,110 @@
     Py_DECREF(obj);
     return(ret);
 }
+
+/************************************************************************
+ *									*
+ *			Error message callback				*
+ *									*
+ ************************************************************************/
+
+static PyObject *libxml_xmlPythonErrorFuncHandler = NULL;
+static PyObject *libxml_xmlPythonErrorFuncCtxt = NULL;
+
+static void
+libxml_xmlErrorFuncHandler(void *ctx, const char *msg, ...) {
+    int       size;
+    int       chars;
+    char     *larger;
+    va_list   ap;
+    char     *str;
+    PyObject *list;
+    PyObject *message;
+    PyObject *result;
+
+#ifdef DEBUG_ERROR
+    printf("libxml_xmlErrorFuncHandler(%p, %s, ...) called\n", ctx, msg);
+#endif
+
+
+    if (libxml_xmlPythonErrorFuncHandler == NULL) {
+	va_start(ap, 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;
+	}
+
+	list = PyTuple_New(2);
+	PyTuple_SetItem(list, 0, libxml_xmlPythonErrorFuncCtxt);
+	Py_XINCREF(libxml_xmlPythonErrorFuncCtxt);
+	message = libxml_charPtrWrap(str);
+	PyTuple_SetItem(list, 1, message);
+	result = PyEval_CallObject(libxml_xmlPythonErrorFuncHandler, list);
+	Py_XDECREF(list);
+	Py_XDECREF(result);
+    }
+}
+
+static void
+libxml_xmlErrorInitialize(void) {
+#ifdef DEBUG_ERROR
+    printf("libxml_xmlErrorInitialize() called\n");
+#endif
+    xmlSetGenericErrorFunc(NULL, libxml_xmlErrorFuncHandler);
+}
+
+PyObject *
+libxml_xmlRegisterErrorHandler(PyObject *self, PyObject *args) {
+    PyObject *py_retval;
+    PyObject *pyobj_f;
+    PyObject *pyobj_ctx;
+
+    if (!PyArg_ParseTuple(args, "OO:xmlRegisterErrorHandler", &pyobj_f,
+		          &pyobj_ctx))
+        return(NULL);
+
+#ifdef DEBUG_ERROR
+    printf("libxml_registerXPathFunction(%p, %p) called\n", pyobj_ctx, pyobj_f);
+#endif
+
+    if (libxml_xmlPythonErrorFuncHandler != NULL) {
+	Py_XDECREF(libxml_xmlPythonErrorFuncHandler);
+    }
+    if (libxml_xmlPythonErrorFuncCtxt != NULL) {
+	Py_XDECREF(libxml_xmlPythonErrorFuncCtxt);
+    }
+
+    Py_XINCREF(pyobj_ctx);
+    Py_XINCREF(pyobj_f);
+
+    /* TODO: check f is a function ! */
+    libxml_xmlPythonErrorFuncHandler = pyobj_f;
+    libxml_xmlPythonErrorFuncCtxt = pyobj_ctx;
+
+    py_retval = libxml_intWrap(1);
+    return(py_retval);
+}
 /************************************************************************
  *									*
  *			XPath extensions				*
@@ -954,5 +1060,6 @@
     d = PyModule_GetDict(m);
     PyDict_SetItemString(d, "xmlNodeType", (PyObject *)&PyxmlNode_Type);
     PyDict_SetItemString(d, "xmlXPathContextType", (PyObject *)&PyxmlXPathContext_Type);
+    libxml_xmlErrorInitialize();
 }
 
diff --git a/python/libxml2-python-api.xml b/python/libxml2-python-api.xml
index 29dca23..5cdc992 100644
--- a/python/libxml2-python-api.xml
+++ b/python/libxml2-python-api.xml
@@ -14,5 +14,11 @@
       <arg name='ns_uri' type='xmlChar *' info='the namespace or NULL'/>
       <arg name='f' type='pythonObject' info='the python function'/>
     </function>
+    <function name='xmlRegisterErrorHandler' file='python'>
+      <info>Register a Python written function to for error reporting. The function is called back as f(ctx, error).</info>
+      <return type='int' info="1 in case of success, 0 or -1 in case of error"/>
+      <arg name='f' type='pythonObject' info='the python function'/>
+      <arg name='ctx' type='pythonObject' info='a context for the callback'/>
+    </function>
   </symbols>
 </api>
diff --git a/python/libxml2class.txt b/python/libxml2class.txt
index a5c45d3..0411124 100644
--- a/python/libxml2class.txt
+++ b/python/libxml2class.txt
@@ -99,6 +99,9 @@
 isLetter()
 isPubidChar()
 
+# functions from module python
+registerErrorHandler()
+
 # functions from module tree
 compressMode()
 newComment()
diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am
index 366ad06..79d5456 100644
--- a/python/tests/Makefile.am
+++ b/python/tests/Makefile.am
@@ -4,6 +4,7 @@
     tst.py	\
     tstxpath.py	\
     xpathext.py	\
+    error.py	\
     xpath.py
 
 XMLS=		\
@@ -13,7 +14,7 @@
 
 if WITH_PYTHON
 tests: $(TESTS)
-	-@(CLASSPATH=".." ; export CLASSPATH; \
+	-@(PYTHONPATH=".." ; export PYTHONPATH; \
 	   for test in $(TESTS) ; do echo "-- $$test" ; $(PYTHON) $$test ; done)
 else
 tests:
diff --git a/python/tests/tst.py b/python/tests/tst.py
index 86ac64b..dc6e4d4 100755
--- a/python/tests/tst.py
+++ b/python/tests/tst.py
@@ -1,10 +1,18 @@
 #!/usr/bin/python -u
+import sys
 import libxml2
 
 doc = libxml2.parseFile("tst.xml")
-print doc.name
+if doc.name != "tst.xml":
+    print "doc.name failed"
+    sys.exit(1)
 root = doc.children
-print root.name
+if root.name != "doc":
+    print "root.name failed"
+    sys.exit(1)
 child = root.children
-print child.name
+if child.name != "foo":
+    print "child.name failed"
+    sys.exit(1)
 doc.freeDoc()
+print "OK"
diff --git a/python/tests/tstxpath.py b/python/tests/tstxpath.py
index f6c675a..97d392c 100755
--- a/python/tests/tstxpath.py
+++ b/python/tests/tstxpath.py
@@ -1,29 +1,38 @@
 #!/usr/bin/python -u
+import sys
 import libxml2
 
 def foo(x):
-    # print "foo called %s" % (x)
     return x + 1
 
 def bar(x):
-    # print "foo called %s" % (x)
-    return "%s" % (x + 1)
+    return "%d" % (x + 2)
 
 doc = libxml2.parseFile("tst.xml")
 ctxt = doc.xpathNewContext()
 res = ctxt.xpathEval("//*")
-print res
+if len(res) != 2:
+    print "xpath query: wrong node set size"
+    sys.exit(1)
+if res[0].name != "doc" or res[1].name != "foo":
+    print "xpath query: wrong node set value"
+    sys.exit(1)
 
 libxml2.registerXPathFunction(ctxt._o, "foo", None, foo)
 libxml2.registerXPathFunction(ctxt._o, "bar", None, bar)
 i = 10000
 while i > 0:
     res = ctxt.xpathEval("foo(1)")
+    if res != 2:
+        print "xpath extension failure"
+	sys.exit(1)
     i = i - 1
-print res
 i = 10000
 while i > 0:
     res = ctxt.xpathEval("bar(1)")
+    if res != "3":
+        print "xpath extension failure got %s expecting '3'"
+	sys.exit(1)
     i = i - 1
-print res
 doc.freeDoc()
+print "OK"
diff --git a/python/tests/xpath.py b/python/tests/xpath.py
index fdbd839..49a697f 100755
--- a/python/tests/xpath.py
+++ b/python/tests/xpath.py
@@ -3,10 +3,23 @@
 # this test exercise the XPath basic engine, parser, etc, and
 # allows to detect memory leaks
 #
+import sys
 import libxml2
 
 doc = libxml2.parseFile("tst.xml")
-print doc
+if doc.name != "tst.xml":
+    print "doc.name error"
+    sys.exit(1);
+
+ctxt = doc.xpathNewContext()
+res = ctxt.xpathEval("//*")
+if len(res) != 2:
+    print "xpath query: wrong node set size"
+    sys.exit(1)
+if res[0].name != "doc" or res[1].name != "foo":
+    print "xpath query: wrong node set value"
+    sys.exit(1)
+doc.freeDoc()
 i = 1000
 while i > 0:
     doc = libxml2.parseFile("tst.xml")
@@ -14,8 +27,4 @@
     res = ctxt.xpathEval("//*")
     doc.freeDoc()
     i = i -1
-doc = libxml2.parseFile("tst.xml")
-ctxt = doc.xpathNewContext()
-res = ctxt.xpathEval("//*")
-print res
-doc.freeDoc()
+print "OK"
diff --git a/python/tests/xpathext.py b/python/tests/xpathext.py
index d6f0455..97d392c 100755
--- a/python/tests/xpathext.py
+++ b/python/tests/xpathext.py
@@ -1,33 +1,38 @@
 #!/usr/bin/python -u
-#
-# This test exercise the extension of the XPath engine with
-# functions defined in Python.
-#
+import sys
 import libxml2
 
 def foo(x):
-    # print "foo called %s" % (x)
     return x + 1
 
 def bar(x):
-    # print "foo called %s" % (x)
-    return "%s" % (x + 1)
+    return "%d" % (x + 2)
 
 doc = libxml2.parseFile("tst.xml")
 ctxt = doc.xpathNewContext()
 res = ctxt.xpathEval("//*")
-print res
+if len(res) != 2:
+    print "xpath query: wrong node set size"
+    sys.exit(1)
+if res[0].name != "doc" or res[1].name != "foo":
+    print "xpath query: wrong node set value"
+    sys.exit(1)
 
 libxml2.registerXPathFunction(ctxt._o, "foo", None, foo)
 libxml2.registerXPathFunction(ctxt._o, "bar", None, bar)
 i = 10000
 while i > 0:
     res = ctxt.xpathEval("foo(1)")
+    if res != 2:
+        print "xpath extension failure"
+	sys.exit(1)
     i = i - 1
-print res
 i = 10000
 while i > 0:
     res = ctxt.xpathEval("bar(1)")
+    if res != "3":
+        print "xpath extension failure got %s expecting '3'"
+	sys.exit(1)
     i = i - 1
-print res
 doc.freeDoc()
+print "OK"