Applied patch from Torkel Lyng to add Schemas support to the Python

* xmlschemas.c include/libxml/xmlschemas.h python/generator.py
  python/libxml.c python/libxml_wrap.h python/types.c
  python/tests/schema.py python/tests/Makefile.am: Applied patch
  from Torkel Lyng to add Schemas support to the Python bindings
  and extend the schemas error API, registered a new test.
* doc/* elfgcchack.h: rebuilt to regenerate the bindings
Daniel
diff --git a/python/generator.py b/python/generator.py
index 6b66c92..df89c4e 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -282,6 +282,9 @@
     'xmlRelaxNGPtr': ('O', "relaxNgSchema", "xmlRelaxNGPtr", "xmlRelaxNGPtr"),
     'xmlRelaxNGParserCtxtPtr': ('O', "relaxNgParserCtxt", "xmlRelaxNGParserCtxtPtr", "xmlRelaxNGParserCtxtPtr"),
     'xmlRelaxNGValidCtxtPtr': ('O', "relaxNgValidCtxt", "xmlRelaxNGValidCtxtPtr", "xmlRelaxNGValidCtxtPtr"),
+    'xmlSchemaPtr': ('O', "Schema", "xmlSchemaPtr", "xmlSchemaPtr"),
+    'xmlSchemaParserCtxtPtr': ('O', "SchemaParserCtxt", "xmlSchemaParserCtxtPtr", "xmlSchemaParserCtxtPtr"),
+    'xmlSchemaValidCtxtPtr': ('O', "SchemaValidCtxt", "xmlSchemaValidCtxtPtr", "xmlSchemaValidCtxtPtr"),
 }
 
 py_return_types = {
@@ -666,6 +669,9 @@
     'xmlRelaxNGPtr': ('._o', "relaxNgSchema(_obj=%s)", "relaxNgSchema"),
     'xmlRelaxNGParserCtxtPtr': ('._o', "relaxNgParserCtxt(_obj=%s)", "relaxNgParserCtxt"),
     'xmlRelaxNGValidCtxtPtr': ('._o', "relaxNgValidCtxt(_obj=%s)", "relaxNgValidCtxt"),
+    'xmlSchemaPtr': ("._o", "Schema(_obj=%s)", "Schema"),
+    'xmlSchemaParserCtxtPtr': ("._o", "SchemaParserCtxt(_obj=%s)", "SchemaParserCtxt"),
+    'xmlSchemaValidCtxtPtr': ("._o", "SchemaValidCtxt(_obj=%s)", "SchemaValidCtxt"),
 }
 
 converter_type = {
@@ -699,6 +705,9 @@
     "relaxNgSchema": "xmlRelaxNGFree",
     "relaxNgParserCtxt": "xmlRelaxNGFreeParserCtxt",
     "relaxNgValidCtxt": "xmlRelaxNGFreeValidCtxt",
+	"Schema": "xmlSchemaFree",
+	"SchemaParserCtxt": "xmlSchemaFreeParserCtxt",
+	"SchemaValidCtxt": "xmlSchemaFreeValidCtxt",
 }
 
 functions_noexcept = {
@@ -710,6 +719,7 @@
 reference_keepers = {
     "xmlTextReader": [('inputBuffer', 'input')],
     "relaxNgValidCtxt": [('relaxNgSchema', 'schema')],
+	"SchemaValidCtxt": [('Schema', 'schema')],
 }
 
 function_classes = {}
diff --git a/python/libxml.c b/python/libxml.c
index 9dda18c..1c65e72 100644
--- a/python/libxml.c
+++ b/python/libxml.c
@@ -2948,6 +2948,171 @@
     return(Py_None);
 }
 
+typedef struct
+{
+	PyObject *warn;
+	PyObject *error;
+	PyObject *arg;
+} xmlSchemaValidCtxtPyCtxt;
+typedef xmlSchemaValidCtxtPyCtxt *xmlSchemaValidCtxtPyCtxtPtr;
+
+static void
+libxml_xmlSchemaValidityGenericErrorFuncHandler(void *ctx, char *str)
+{
+	PyObject *list;
+	PyObject *result;
+	xmlSchemaValidCtxtPyCtxtPtr pyCtxt;
+
+#ifdef DEBUG_ERROR
+	printf("libxml_xmlSchemaValiditiyGenericErrorFuncHandler(%p, %s, ...) called\n", ctx, str);
+#endif
+
+	pyCtxt = (xmlSchemaValidCtxtPyCtxtPtr) ctx;
+
+	list = PyTuple_New(2);
+	PyTuple_SetItem(list, 0, libxml_charPtrWrap(str));
+	PyTuple_SetItem(list, 1, pyCtxt->arg);
+	Py_XINCREF(pyCtxt->arg);
+	result = PyEval_CallObject(pyCtxt->error, list);
+	if (result == NULL) 
+	{
+		/* TODO: manage for the exception to be propagated... */
+		PyErr_Print();
+	}
+	Py_XDECREF(list);
+	Py_XDECREF(result);
+}
+
+static void
+libxml_xmlSchemaValidityGenericWarningFuncHandler(void *ctx, char *str)
+{
+	PyObject *list;
+	PyObject *result;
+	xmlSchemaValidCtxtPyCtxtPtr pyCtxt;
+
+#ifdef DEBUG_ERROR
+	printf("libxml_xmlSchemaValidityGenericWarningFuncHandler(%p, %s, ...) called\n", ctx, str);
+#endif
+	
+	pyCtxt = (xmlSchemaValidCtxtPyCtxtPtr) ctx;
+
+	list = PyTuple_New(2);
+	PyTuple_SetItem(list, 0, libxml_charPtrWrap(str));
+	PyTuple_SetItem(list, 1, pyCtxt->arg);
+	Py_XINCREF(pyCtxt->arg);
+	result = PyEval_CallObject(pyCtxt->warn, list);
+	if (result == NULL)
+	{
+		/* TODO: manage for the exception to be propagated... */
+		PyErr_Print();
+	}
+	Py_XDECREF(list);
+	Py_XDECREF(result);
+}
+
+static void
+libxml_xmlSchemaValidityErrorFunc(void *ctx, const char *msg, ...)
+{
+	va_list ap;
+	
+	va_start(ap, msg);
+	libxml_xmlSchemaValidityGenericErrorFuncHandler(ctx, libxml_buildMessage(msg, ap));
+	va_end(ap);
+}
+
+static void
+libxml_xmlSchemaValidityWarningFunc(void *ctx, const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	libxml_xmlSchemaValidityGenericWarningFuncHandler(ctx, libxml_buildMessage(msg, ap));
+	va_end(ap);
+}
+
+static PyObject *
+libxml_xmlSchemaSetValidErrors(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
+{
+	PyObject *py_retval;
+	PyObject *pyobj_error;
+	PyObject *pyobj_warn;
+	PyObject *pyobj_ctx;
+	PyObject *pyobj_arg = Py_None;
+	xmlSchemaValidCtxtPtr ctxt;
+	xmlSchemaValidCtxtPyCtxtPtr pyCtxt;
+
+	if (!PyArg_ParseTuple
+		(args, (char *) "OOO|O:xmlSchemaSetValidErrors", &pyobj_ctx, &pyobj_error, &pyobj_warn, &pyobj_arg))
+		return (NULL);
+
+#ifdef DEBUG_ERROR
+	printf("libxml_xmlSchemaSetValidErrors(%p, %p, %p) called\n", pyobj_ctx, pyobj_error, pyobj_warn);
+#endif
+
+	ctxt = PySchemaValidCtxt_Get(pyobj_ctx);
+	if (xmlSchemaGetValidErrors(ctxt, NULL, NULL, (void **) &pyCtxt) == -1)
+	{
+		py_retval = libxml_intWrap(-1);
+		return(py_retval);
+	}
+
+	if (pyCtxt == NULL)
+	{
+		/* first time to set the error handlers */
+		pyCtxt = xmlMalloc(sizeof(xmlSchemaValidCtxtPyCtxt));
+		if (pyCtxt == NULL) {
+			py_retval = libxml_intWrap(-1);
+			return(py_retval);
+		}
+		memset(pyCtxt, 0, sizeof(xmlSchemaValidCtxtPyCtxt));
+	}
+
+	/* TODO: check warn and error is a function ! */
+	Py_XDECREF(pyCtxt->error);
+	Py_XINCREF(pyobj_error);
+	pyCtxt->error = pyobj_error;
+
+	Py_XDECREF(pyCtxt->warn);
+	Py_XINCREF(pyobj_warn);
+	pyCtxt->warn = pyobj_warn;
+
+	Py_XDECREF(pyCtxt->arg);
+	Py_XINCREF(pyobj_arg);
+	pyCtxt->arg = pyobj_arg;
+
+	xmlSchemaSetValidErrors(ctxt, &libxml_xmlSchemaValidityErrorFunc, &libxml_xmlSchemaValidityWarningFunc, pyCtxt);
+
+	py_retval = libxml_intWrap(1);
+	return(py_retval);
+}
+
+static PyObject *
+libxml_xmlSchemaFreeValidCtxt(ATTRIBUTE_UNUSED PyObject * self, PyObject * args)
+{
+	xmlSchemaValidCtxtPtr ctxt;
+	xmlSchemaValidCtxtPyCtxtPtr pyCtxt;
+	PyObject *pyobj_ctxt;
+
+	if (!PyArg_ParseTuple(args, (char *)"O:xmlSchemaFreeValidCtxt", &pyobj_ctxt))
+		return(NULL);
+	ctxt = (xmlSchemaValidCtxtPtr) PySchemaValidCtxt_Get(pyobj_ctxt);
+
+	if (xmlSchemaGetValidErrors(ctxt, NULL, NULL, (void **) &pyCtxt) == 0)
+	{
+		if (pyCtxt != NULL)
+		{
+			Py_XDECREF(pyCtxt->error);
+			Py_XDECREF(pyCtxt->warn);
+			Py_XDECREF(pyCtxt->arg);
+			xmlFree(pyCtxt);
+		}
+	}
+
+	xmlSchemaFreeValidCtxt(ctxt);
+	Py_INCREF(Py_None);
+	return(Py_None);
+}
+
 #endif
 
 #ifdef LIBXML_C14N_ENABLED
diff --git a/python/libxml2class.txt b/python/libxml2class.txt
index 2f082ea..9e2496e 100644
--- a/python/libxml2class.txt
+++ b/python/libxml2class.txt
@@ -219,6 +219,10 @@
 # functions from module xmlregexp
 regexpCompile()
 
+# functions from module xmlschemas
+schemaNewMemParserCtxt()
+schemaNewParserCtxt()
+
 # functions from module xmlschemastypes
 schemaCleanupTypes()
 schemaCollapseString()
@@ -630,6 +634,10 @@
     NewWalker()
     readerWalker()
 
+    # functions from module xmlschemas
+    schemaNewDocParserCtxt()
+    schemaValidateDoc()
+
     # functions from module xpath
     xpathNewContext()
     xpathOrderDocElems()
@@ -781,6 +789,11 @@
 
     # functions from module xmlreader
     RelaxNGSetSchema()
+Class Schema()
+
+    # functions from module xmlschemas
+    schemaDump()
+    schemaNewValidCtxt()
 Class Error()
     # accessors
     code()
@@ -1032,6 +1045,14 @@
     # functions from module xmlIO
     write()
     writeString()
+Class SchemaParserCtxt()
+
+    # functions from module xmlschemas
+    schemaParse()
+Class SchemaValidCtxt()
+
+    # functions from module xmlschemas
+    schemaValidateDoc()
 Class xmlTextReaderLocator()
 
     # functions from module xmlreader
diff --git a/python/libxml_wrap.h b/python/libxml_wrap.h
index 09fc77f..ad62be2 100644
--- a/python/libxml_wrap.h
+++ b/python/libxml_wrap.h
@@ -18,7 +18,10 @@
 #include <libxml/xmlregexp.h>
 #include <libxml/xmlautomata.h>
 #include <libxml/xmlreader.h>
+#ifdef LIBXML_SCHEMAS_ENABLED
 #include <libxml/relaxng.h>
+#include <libxml/xmlschemas.h>
+#endif
 
 /**
  * ATTRIBUTE_UNUSED:
@@ -165,6 +168,30 @@
 #define PyrelaxNgValidCtxt_Get(v) (((v) == Py_None) ? NULL : \
 	(((PyrelaxNgValidCtxt_Object *)(v))->obj))
 
+typedef struct {
+	PyObject_HEAD
+	xmlSchemaPtr obj;
+} PySchema_Object;
+
+#define PySchema_Get(v) (((v) == Py_None) ? NULL : \
+	(((PySchema_Object *)(v))->obj))
+
+typedef struct {
+	PyObject_HEAD
+	xmlSchemaParserCtxtPtr obj;
+} PySchemaParserCtxt_Object;
+
+#define PySchemaParserCtxt_Get(v) (((v) == Py_None) ? NULL : \
+	(((PySchemaParserCtxt_Object *)(v))->obj))
+
+typedef struct {
+	PyObject_HEAD
+	xmlSchemaValidCtxtPtr obj;
+} PySchemaValidCtxt_Object;
+
+#define PySchemaValidCtxt_Get(v) (((v) == Py_None) ? NULL : \
+	(((PySchemaValidCtxt_Object *)(v))->obj))
+
 #endif /* LIBXML_SCHEMAS_ENABLED */
 
 PyObject * libxml_intWrap(int val);
@@ -201,5 +228,8 @@
 PyObject * libxml_xmlRelaxNGPtrWrap(xmlRelaxNGPtr ctxt);
 PyObject * libxml_xmlRelaxNGParserCtxtPtrWrap(xmlRelaxNGParserCtxtPtr ctxt);
 PyObject * libxml_xmlRelaxNGValidCtxtPtrWrap(xmlRelaxNGValidCtxtPtr valid);
+PyObject * libxml_xmlSchemaPtrWrap(xmlSchemaPtr ctxt);
+PyObject * libxml_xmlSchemaParserCtxtPtrWrap(xmlSchemaParserCtxtPtr ctxt);
+PyObject * libxml_xmlSchemaValidCtxtPtrWrap(xmlSchemaValidCtxtPtr valid);
 #endif /* LIBXML_SCHEMAS_ENABLED */
 PyObject * libxml_xmlErrorPtrWrap(xmlErrorPtr error);
diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am
index 2788c0c..722e0ec 100644
--- a/python/tests/Makefile.am
+++ b/python/tests/Makefile.am
@@ -32,6 +32,7 @@
     ctxterror.py\
     readererr.py\
     relaxng.py	\
+    schema.py	\
     thread2.py \
     sync.py \
     tstLastError.py \
diff --git a/python/tests/schema.py b/python/tests/schema.py
new file mode 100755
index 0000000..bfa8423
--- /dev/null
+++ b/python/tests/schema.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python -u
+import libxml2
+import sys
+
+# Memory debug specific
+libxml2.debugMemory(1)
+
+schema="""<?xml version="1.0" encoding="iso-8859-1"?>
+<schema xmlns = "http://www.w3.org/2001/XMLSchema">
+	<element name = "Customer">
+		<complexType>
+			<sequence>
+				<element name = "FirstName" type = "string" />
+				<element name = "MiddleInitial" type = "string" />
+				<element name = "LastName" type = "string" />
+			</sequence>
+			<attribute name = "customerID" type = "integer" />
+		</complexType>
+	</element>
+</schema>"""
+
+instance="""<?xml version="1.0" encoding="iso-8859-1"?>
+<Customer customerID = "24332">
+	<FirstName>Raymond</FirstName>
+	<MiddleInitial>G</MiddleInitial>
+	<LastName>Bayliss</LastName>
+</Customer>	
+"""
+
+ctxt_parser = libxml2.schemaNewMemParserCtxt(schema, len(schema))
+ctxt_schema = ctxt_parser.schemaParse()
+ctxt_valid  = ctxt_schema.schemaNewValidCtxt()
+doc = libxml2.parseDoc(instance)
+ret = doc.schemaValidateDoc(ctxt_valid)
+if ret != 0:
+    print "error doing schema validation"
+    sys.exit(1)
+
+doc.freeDoc()
+del ctxt_parser
+del ctxt_schema
+del ctxt_valid
+libxml2.schemaCleanupTypes()
+
+# Memory debug specific
+libxml2.cleanupParser()
+if libxml2.debugMemory(1) == 0:
+    print "OK"
+else:
+    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+    libxml2.dumpMemory()
+
diff --git a/python/types.c b/python/types.c
index 42279d0..fa91a65 100644
--- a/python/types.c
+++ b/python/types.c
@@ -640,6 +640,63 @@
                                      (char *) "xmlRelaxNGValidCtxtPtr", NULL);
     return (ret);
 }
+
+PyObject *
+libxml_xmlSchemaPtrWrap(xmlSchemaPtr ctxt)
+{
+	PyObject *ret;
+
+#ifdef DEBUG
+	printf("libxml_xmlSchemaPtrWrap: ctxt = %p\n", ctxt);
+#endif
+	if (ctxt == NULL) {
+		Py_INCREF(Py_None);
+		return (Py_None);
+	}
+	ret =
+		PyCObject_FromVoidPtrAndDesc((void *) ctxt,
+									 (char *) "xmlSchemaPtr", NULL);
+	return (ret);
+}
+
+PyObject *
+libxml_xmlSchemaParserCtxtPtrWrap(xmlSchemaParserCtxtPtr ctxt)
+{
+	PyObject *ret;
+
+#ifdef DEBUG
+	printf("libxml_xmlSchemaParserCtxtPtrWrap: ctxt = %p\n", ctxt);
+#endif
+	if (ctxt == NULL) {
+		Py_INCREF(Py_None);
+		return (Py_None);
+	}
+	ret = 
+		PyCObject_FromVoidPtrAndDesc((void *) ctxt,
+									 (char *) "xmlSchemaParserCtxtPtr", NULL);
+
+	return (ret);
+}
+
+PyObject *
+libxml_xmlSchemaValidCtxtPtrWrap(xmlSchemaValidCtxtPtr valid)
+{
+	PyObject *ret;
+	
+#ifdef DEBUG
+	printf("libxml_xmlSchemaValidCtxtPtrWrap: valid = %p\n", valid);
+#endif
+	if (valid == NULL) {
+		Py_INCREF(Py_None);
+		return (Py_None);
+	}
+
+	ret = 
+		PyCObject_FromVoidPtrAndDesc((void *) valid,
+									 (char *) "xmlSchemaValidCtxtPtr", NULL);
+
+	return (ret);
+}
 #endif /* LIBXML_SCHEMAS_ENABLED */
 
 PyObject *