updated the policy on private mail answers more work on Relax-NG

* README: updated the policy on private mail answers
* relaxng.c: more work on Relax-NG
* test/relaxng/* result/relaxng/*: augmented/updated the
  regression tests
Daniel
diff --git a/relaxng.c b/relaxng.c
index 7ca09a3..61af8c0 100644
--- a/relaxng.c
+++ b/relaxng.c
@@ -74,11 +74,6 @@
 };
 
 
-#if 0
-struct _xmlRelaxNGSchema {
-};
-#endif
-
 typedef enum {
     XML_RELAXNG_EMPTY = 0,	/* an empty pattern */
     XML_RELAXNG_NOT_ALLOWED,    /* not allowed top */
@@ -103,6 +98,7 @@
     xmlNodePtr	   node;	/* the node in the source */
     xmlChar       *name;	/* the element local name if present */
     xmlChar       *ns;		/* the namespace local name if present */
+    void          *data;	/* data lib or specific pointer */
     xmlRelaxNGDefinePtr content;/* the expected content */
     xmlRelaxNGDefinePtr next;	/* list within grouping sequences */
     xmlRelaxNGDefinePtr attrs;	/* list of attributes for elements */
@@ -197,6 +193,61 @@
 
 /************************************************************************
  * 									*
+ * 		Preliminary type checking interfaces			*
+ * 									*
+ ************************************************************************/
+/**
+ * xmlRelaxNGTypeHave:
+ * @data:  data needed for the library
+ * @type:  the type name
+ * @value:  the value to check
+ *
+ * Function provided by a type library to check if a type is exported
+ *
+ * Returns 1 if yes, 0 if no and -1 in case of error.
+ */
+typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
+
+/**
+ * xmlRelaxNGTypeCheck:
+ * @data:  data needed for the library
+ * @type:  the type name
+ * @value:  the value to check
+ *
+ * Function provided by a type library to check if a value match a type
+ *
+ * Returns 1 if yes, 0 if no and -1 in case of error.
+ */
+typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
+	                            const xmlChar *value);
+
+/**
+ * xmlRelaxNGTypeCompare:
+ * @data:  data needed for the library
+ * @type:  the type name
+ * @value1:  the first value
+ * @value2:  the second value
+ *
+ * Function provided by a type library to compare two values accordingly
+ * to a type.
+ *
+ * Returns 1 if yes, 0 if no and -1 in case of error.
+ */
+typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
+	                              const xmlChar *value1,
+				      const xmlChar *value2);
+typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
+typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
+struct _xmlRelaxNGTypeLibrary {
+    const xmlChar     *namespace;	/* the datatypeLibrary value */
+    void                   *data;	/* data needed for the library */
+    xmlRelaxNGTypeHave      have;	/* the export function */
+    xmlRelaxNGTypeCheck    check;	/* the checking function */
+    xmlRelaxNGTypeCompare   comp;	/* the compare function */
+};
+
+/************************************************************************
+ * 									*
  * 			Allocation functions				*
  * 									*
  ************************************************************************/
@@ -600,8 +651,226 @@
  * 									*
  ************************************************************************/
 
+/**
+ * xmlRelaxNGSchemaTypeHave:
+ * @data:  data needed for the library
+ * @type:  the type name
+ *
+ * Check if the given type is provided by
+ * the W3C XMLSchema Datatype library.
+ *
+ * Returns 1 if yes, 0 if no and -1 in case of error.
+ */
+static int
+xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
+	                 const xmlChar *type ATTRIBUTE_UNUSED) {
+    TODO
+    return(1);
+}
+
+/**
+ * xmlRelaxNGSchemaTypeCheck:
+ * @data:  data needed for the library
+ * @type:  the type name
+ * @value:  the value to check
+ *
+ * Check if the given type and value are validated by
+ * the W3C XMLSchema Datatype library.
+ *
+ * Returns 1 if yes, 0 if no and -1 in case of error.
+ */
+static int
+xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
+	                  const xmlChar *type ATTRIBUTE_UNUSED,
+			  const xmlChar *value ATTRIBUTE_UNUSED) {
+    TODO
+    return(1);
+}
+
+/**
+ * xmlRelaxNGSchemaTypeCompare:
+ * @data:  data needed for the library
+ * @type:  the type name
+ * @value1:  the first value
+ * @value2:  the second value
+ *
+ * Compare two values accordingly a type from the W3C XMLSchema
+ * Datatype library.
+ *
+ * Returns 1 if yes, 0 if no and -1 in case of error.
+ */
+static int
+xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
+	                    const xmlChar *type ATTRIBUTE_UNUSED,
+	                    const xmlChar *value1 ATTRIBUTE_UNUSED,
+			    const xmlChar *value2 ATTRIBUTE_UNUSED) {
+    TODO
+    return(1);
+}
+ 
+/**
+ * xmlRelaxNGDefaultTypeHave:
+ * @data:  data needed for the library
+ * @type:  the type name
+ *
+ * Check if the given type is provided by
+ * the default datatype library.
+ *
+ * Returns 1 if yes, 0 if no and -1 in case of error.
+ */
+static int
+xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
+    if (type == NULL)
+	return(-1);
+    if (xmlStrEqual(type, BAD_CAST "string"))
+	return(1);
+    if (xmlStrEqual(type, BAD_CAST "token"))
+	return(1);
+    return(0);
+}
+
+/**
+ * xmlRelaxNGDefaultTypeCheck:
+ * @data:  data needed for the library
+ * @type:  the type name
+ * @value:  the value to check
+ *
+ * Check if the given type and value are validated by
+ * the default datatype library.
+ *
+ * Returns 1 if yes, 0 if no and -1 in case of error.
+ */
+static int
+xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
+	                   const xmlChar *type ATTRIBUTE_UNUSED,
+			  const xmlChar *value ATTRIBUTE_UNUSED) {
+    return(1);
+}
+
+/**
+ * xmlRelaxNGDefaultTypeCompare:
+ * @data:  data needed for the library
+ * @type:  the type name
+ * @value1:  the first value
+ * @value2:  the second value
+ *
+ * Compare two values accordingly a type from the default
+ * datatype library.
+ *
+ * Returns 1 if yes, 0 if no and -1 in case of error.
+ */
+static int
+xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
+	                     const xmlChar *type ATTRIBUTE_UNUSED,
+	                     const xmlChar *value1 ATTRIBUTE_UNUSED,
+			     const xmlChar *value2 ATTRIBUTE_UNUSED) {
+    TODO
+    return(1);
+}
+ 
+static int xmlRelaxNGTypeInitialized = 0;
+static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
+
+/**
+ * xmlRelaxNGFreeTypeLibrary:
+ * @lib:  the type library structure
+ * @namespace:  the URI bound to the library
+ *
+ * Free the structure associated to the type library
+ */
 static void
+xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
+	                  const xmlChar *namespace ATTRIBUTE_UNUSED) {
+    if (lib == NULL)
+	return;
+    if (lib->namespace != NULL)
+	xmlFree((xmlChar *)lib->namespace);
+    xmlFree(lib);
+}
+
+/**
+ * xmlRelaxNGRegisterTypeLibrary:
+ * @namespace:  the URI bound to the library
+ * @data:  data associated to the library
+ * @have:  the provide function
+ * @check:  the checking function
+ * @comp:  the comparison function
+ *
+ * Register a new type library
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+static int
+xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
+    xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
+    xmlRelaxNGTypeCompare comp) {
+    xmlRelaxNGTypeLibraryPtr lib;
+    int ret;
+
+    if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
+	(check == NULL) || (comp == NULL))
+	return(-1);
+    if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"Relax-NG types library '%s' already registered\n",
+		        namespace);
+	return(-1);
+    }
+    lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
+    if (lib == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"Relax-NG types library '%s' malloc() failed\n",
+		        namespace);
+        return (-1);
+    }
+    memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
+    lib->namespace = xmlStrdup(namespace);
+    lib->data = data;
+    lib->have = have;
+    lib->comp = comp;
+    lib->check = check;
+    ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
+    if (ret < 0) {
+	xmlGenericError(xmlGenericErrorContext,
+		"Relax-NG types library failed to register '%s'\n",
+		        namespace);
+	xmlRelaxNGFreeTypeLibrary(lib, namespace);
+	return(-1);
+    }
+    return(0);
+}
+
+/**
+ * xmlRelaxNGInitTypes:
+ *
+ * Initilize the default type libraries.
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+static int
 xmlRelaxNGInitTypes(void) {
+    if (xmlRelaxNGTypeInitialized != 0)
+	return(0);
+    xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
+    if (xmlRelaxNGRegisteredTypes == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"Failed to allocate sh table for Relax-NG types\n");
+	return(-1);
+    }
+    xmlRelaxNGRegisterTypeLibrary(
+	    BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
+	    NULL,
+	    xmlRelaxNGSchemaTypeHave,
+	    xmlRelaxNGSchemaTypeCheck,
+	    xmlRelaxNGSchemaTypeCompare);
+    xmlRelaxNGRegisterTypeLibrary(
+	    xmlRelaxNGNs,
+	    NULL,
+	    xmlRelaxNGDefaultTypeHave,
+	    xmlRelaxNGDefaultTypeCheck,
+	    xmlRelaxNGDefaultTypeCompare);
+    xmlRelaxNGTypeInitialized = 1;
+    return(0);
 }
 
 /**
@@ -611,7 +880,12 @@
  */
 void	
 xmlRelaxNGCleanupTypes(void) {
+    if (xmlRelaxNGTypeInitialized == 0)
+	return;
     xmlSchemaCleanupTypes();
+    xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
+	        xmlRelaxNGFreeTypeLibrary);
+    xmlRelaxNGTypeInitialized = 0;
 }
 
 /************************************************************************
@@ -650,7 +924,6 @@
     return(1);
 }
 
-#if 0
 /**
  * xmlRelaxNGGetDataTypeLibrary:
  * @ctxt:  a Relax-NG parser context
@@ -665,15 +938,10 @@
 	                     xmlNodePtr node) {
     xmlChar *ret, *escape;
 
-#ifdef DEBUG
-    xmlGenericError(xmlGenericErrorContext,
-		    "xmlRelaxNGGetDataTypeLibrary()\n");
-#endif
-
     if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
 	ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
 	if (ret != NULL) {
-	    escape = xmlURIEscapeStr(ret, BAD_CAST "");
+	    escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
 	    if (escape == NULL) {
 		return(ret);
 	    }
@@ -686,7 +954,7 @@
 	if (IS_RELAXNG(node, "element")) {
 	    ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
 	    if (ret != NULL) {
-		escape = xmlURIEscapeStr(ret, BAD_CAST "");
+		escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
 		if (escape == NULL) {
 		    return(ret);
 		}
@@ -698,7 +966,81 @@
     }
     return(NULL);
 }
-#endif
+
+/**
+ * xmlRelaxNGParseData:
+ * @ctxt:  a Relax-NG parser context
+ * @node:  the data node.
+ *
+ * parse the content of a RelaxNG data node.
+ *
+ * Returns the definition pointer or NULL in case of error
+ */
+static xmlRelaxNGDefinePtr
+xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
+    xmlRelaxNGDefinePtr def = NULL;
+    xmlRelaxNGTypeLibraryPtr lib;
+    xmlChar *type;
+    xmlChar *library;
+    xmlNodePtr content;
+    int tmp;
+
+    type = xmlGetProp(node, BAD_CAST "type");
+    if (type == NULL) {
+	if (ctxt->error != NULL)
+	    ctxt->error(ctxt->userData,
+			"data has no type\n");
+	ctxt->nbErrors++;
+	return(NULL);
+    }
+    library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
+    if (library == NULL)
+	library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
+
+    def = xmlRelaxNGNewDefine(ctxt, node);
+    if (def == NULL) {
+	xmlFree(type);
+	return(NULL);
+    }
+    def->type = XML_RELAXNG_DATATYPE;
+    def->name = type;
+    def->ns = library;
+
+    lib = (xmlRelaxNGTypeLibraryPtr)
+	xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
+    if (lib == NULL) {
+	if (ctxt->error != NULL)
+	    ctxt->error(ctxt->userData,
+		"Use of unregistered type library '%s'\n",
+		        library);
+	ctxt->nbErrors++;
+	def->data = NULL;
+    } else {
+	def->data = lib;
+	if (lib->have == NULL) {
+	    ctxt->error(ctxt->userData,
+		"Internal error with type library '%s': no 'have'\n",
+		        library);
+	    ctxt->nbErrors++;
+	} else {
+	    tmp = lib->have(lib->data, def->name);
+	    if (tmp != 1) {
+		ctxt->error(ctxt->userData,
+		    "Error type '%s' is not exported by type library '%s'\n",
+			    def->name, library);
+		ctxt->nbErrors++;
+	    }
+	}
+    }
+    content = node->children;
+    while (content != NULL) {
+	TODO
+	content = content->next;
+    }
+
+    return(def);
+}
+
 
 /**
  * xmlRelaxNGParseDefine:
@@ -887,6 +1229,8 @@
 		}
 	    }
 	}
+    } else if (IS_RELAXNG(node, "data")) {
+	def = xmlRelaxNGParseData(ctxt, node);
     } else if (IS_RELAXNG(node, "define")) {
 	xmlRelaxNGParseDefine(ctxt, node);
 	def = NULL;
@@ -2202,6 +2546,45 @@
 }
 
 /**
+ * xmlRelaxNGValidateDatatype:
+ * @ctxt:  a Relax-NG validation context
+ * @value:  the string value
+ * @type:  the datatype definition
+ *
+ * Validate the given value against the dataype
+ *
+ * Returns 0 if the validation succeeded or an error code.
+ */
+static int
+xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
+	                   xmlRelaxNGDefinePtr define) {
+    int ret;
+    xmlRelaxNGTypeLibraryPtr lib;
+
+    if ((define == NULL) || (define->data == NULL)) {
+	return(-1);
+    }
+    lib = (xmlRelaxNGTypeLibraryPtr) define->data;
+    if (lib->check != NULL)
+	ret = lib->check(lib->data, define->name, value);
+    else 
+	ret = -1;
+    if (ret < 0) {
+	VALID_CTXT();
+	VALID_ERROR("Internal: failed to validate type %s\n", define->name);
+	return(-1);
+    } else if (ret == 1) {
+	ret = 0;
+    } else {
+	VALID_CTXT();
+	VALID_ERROR("Type %s doesn't allow value %s\n", define->name, value);
+	return(-1);
+	ret = -1;
+    }
+    return(ret);
+}
+
+/**
  * xmlRelaxNGValidateValue:
  * @ctxt:  a Relax-NG validation context
  * @define:  the definition to verify
@@ -2590,7 +2973,32 @@
         case XML_RELAXNG_DEF:
 	    ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
 	    break;
-        case XML_RELAXNG_DATATYPE:
+        case XML_RELAXNG_DATATYPE: {
+	    xmlChar *content;
+
+	    content = xmlNodeGetContent(node);
+	    ret = xmlRelaxNGValidateDatatype(ctxt, content, define);
+	    if (ret == -1) {
+		VALID_CTXT();
+		VALID_ERROR("internal error validating %s\n", define->name);
+	    } else if (ret == 0) {
+		ctxt->state->seq = node->next;
+	    }
+	    /*
+	     * TODO cover the problems with
+	     * <p>12<!-- comment -->34</p>
+	     * TODO detect full element coverage at compilation time.
+	     */
+	    if ((node != NULL) && (node->next != NULL)) {
+		VALID_CTXT();
+		VALID_ERROR("The data does not cover the full element %s\n",
+			    node->parent->name);
+		ret = -1;
+	    }
+	    if (content != NULL)
+		xmlFree(content);
+	    break;
+	}
         case XML_RELAXNG_VALUE:
 	    TODO
 	    break;