added Datatype ID and IDREF, usable from RelaxNG now need to add a new

* relaxng.c valid.c xmlschemastypes.c: added Datatype ID
  and IDREF, usable from RelaxNG now
* include/libxml/xmlschemastypes.h: need to add a new interface
  because the validation modifies the infoset
* test/relaxng/testsuite.xml: extended the testsuite
Daniel
diff --git a/relaxng.c b/relaxng.c
index 6b382f4..8249a96 100644
--- a/relaxng.c
+++ b/relaxng.c
@@ -154,16 +154,19 @@
  * A RelaxNGs definition
  */
 struct _xmlRelaxNG {
+    void *_private;	/* unused by the library for users or bindings */
     xmlRelaxNGGrammarPtr topgrammar;
     xmlDocPtr doc;
 
+    int             idref;      /* requires idref checking */
+
     xmlHashTablePtr defs;	/* define */
     xmlHashTablePtr refs;	/* references */
     xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
     xmlRelaxNGIncludePtr includes;   /* all the includes loaded */
     int                  defNr; /* number of defines used */
     xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
-    void *_private;	/* unused by the library for users or bindings */
+
 };
 
 #define XML_RELAXNG_IN_ATTRIBUTE	(1 << 0)
@@ -218,6 +221,8 @@
     int                   incNr;      /* Depth of the include parsing stack */
     int                   incMax;     /* Max depth of the parsing stack */
     xmlRelaxNGIncludePtr *incTab;     /* array of incs */
+
+    int                   idref;      /* requires idref checking */
 };
 
 #define FLAGS_IGNORABLE		1
@@ -279,6 +284,7 @@
     xmlRelaxNGValidStatePtr *tabState;
 };
 
+#define ERROR_IS_DUP	1
 /**
  * xmlRelaxNGValidError:
  *
@@ -288,6 +294,7 @@
 typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
 struct _xmlRelaxNGValidError {
     xmlRelaxNGValidErr	err;	/* the error number */
+    int			flags;	/* flags */
     xmlNodePtr		node;	/* the current node */
     xmlNodePtr		seq;	/* the current child */
     const xmlChar *	arg1;	/* first arg */
@@ -309,6 +316,7 @@
     xmlDocPtr               doc;	/* the document being validated */
     int                     flags;	/* validation flags */
     int                     depth;	/* validation depth */
+    int                     idref;	/* requires idref checking */
 
     /*
      * Errors accumulated in branches may have to be stacked to be
@@ -379,7 +387,8 @@
  * Returns 1 if yes, 0 if no and -1 in case of error.
  */
 typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
-	                            const xmlChar *value, void **result);
+	                            const xmlChar *value, void **result,
+				    xmlNodePtr node);
 
 /**
  * xmlRelaxNGFacetCheck:
@@ -1355,6 +1364,7 @@
  * @err:  the error code
  * @arg1:  the first string argument
  * @arg2:  the second string argument
+ * @dup:  arg need to be duplicated
  *
  * Pushes a new error on top of the error stack
  *
@@ -1362,7 +1372,7 @@
  */
 static int
 xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
-	const xmlChar *arg1, const xmlChar *arg2)
+	const xmlChar *arg1, const xmlChar *arg2, int dup)
 {
     xmlRelaxNGValidErrorPtr cur;
     if (ctxt->errTab == NULL) {
@@ -1391,8 +1401,15 @@
 	return(ctxt->errNr);
     cur = &ctxt->errTab[ctxt->errNr];
     cur->err = err;
-    cur->arg1 = arg1;
-    cur->arg2 = arg2;
+    if (dup) {
+        cur->arg1 = xmlStrdup(arg1);
+        cur->arg2 = xmlStrdup(arg2);
+	cur->flags = ERROR_IS_DUP;
+    } else {
+        cur->arg1 = arg1;
+        cur->arg2 = arg2;
+	cur->flags = 0;
+    }
     if (ctxt->state != NULL) {
 	cur->node = ctxt->state->node;
 	cur->seq = ctxt->state->seq;
@@ -1409,23 +1426,27 @@
  * @ctxt: the validation context
  *
  * Pops the top error from the error stack
- *
- * Returns the error just removed
  */
-static xmlRelaxNGValidErrorPtr
+static void
 xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
 {
-    xmlRelaxNGValidErrorPtr ret;
+    xmlRelaxNGValidErrorPtr cur;
 
     if (ctxt->errNr <= 0)
-        return (NULL);
+        return;
     ctxt->errNr--;
     if (ctxt->errNr > 0)
         ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
     else
         ctxt->err = NULL;
-    ret = &ctxt->errTab[ctxt->errNr];
-    return (ret);
+    cur = &ctxt->errTab[ctxt->errNr];
+    if (cur->flags & ERROR_IS_DUP) {
+	xmlFree((xmlChar *)cur->arg1);
+	cur->arg1 = NULL;
+	xmlFree((xmlChar *)cur->arg2);
+	cur->arg2 = NULL;
+	cur->flags = 0;
+    }
 }
 
 /**
@@ -1593,9 +1614,11 @@
  * 									*
  ************************************************************************/
 
-#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL);
-#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL);
-#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c);
+#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
+#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
+#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
+#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
+#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
 
 #ifdef DEBUG
 static const char *
@@ -1662,6 +1685,9 @@
 	case XML_RELAXNG_ERR_TYPEVAL:
 	    snprintf(msg, 1000, "Type %s doesn't allow value %s", arg1, arg2);
 	    break;
+	case XML_RELAXNG_ERR_DUPID:
+	    snprintf(msg, 1000, "ID %s redefined", arg1);
+	    break;
 	case XML_RELAXNG_ERR_TYPECMP:
 	    snprintf(msg, 1000, "failed to compare type %s", arg1);
 	    break;
@@ -1867,6 +1893,15 @@
 	err = &ctxt->errTab[i];
 	xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
 		                 err->arg1, err->arg2);
+	if (err->flags & ERROR_IS_DUP) {
+	    if (err->arg1 != NULL)
+		xmlFree((xmlChar *)err->arg1);
+	    err->arg1 = NULL;
+	    if (err->arg2 != NULL)
+		xmlFree((xmlChar *)err->arg2);
+	    err->arg2 = NULL;
+	    err->flags = 0;
+	}
     }
     ctxt->errNr = 0;
 }
@@ -1876,13 +1911,14 @@
  * @err:  the error number
  * @arg1:  the first argument
  * @arg2:  the second argument
+ * @dup:  need to dup the args
  *
  * Register a validation error, either generating it if it's sure
  * or stacking it for later handling if unsure.
  */
 static void
 xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
-			const xmlChar *arg1, const xmlChar *arg2)
+			const xmlChar *arg1, const xmlChar *arg2, int dup)
 {
     if ((ctxt == NULL) || (ctxt->error == NULL))
 	return;
@@ -1910,7 +1946,7 @@
      * Stack the error for later processing if needed
      */
     else {
-	xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2);
+	xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
     }
 }
 
@@ -1952,6 +1988,7 @@
  * @data:  data needed for the library
  * @type:  the type name
  * @value:  the value to check
+ * @node:  the node
  *
  * Check if the given type and value are validated by
  * the W3C XMLSchema Datatype library.
@@ -1962,7 +1999,8 @@
 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
 	                  const xmlChar *type,
 			  const xmlChar *value,
-			  void **result) {
+			  void **result,
+			  xmlNodePtr node) {
     xmlSchemaTypePtr typ;
     int ret;
 
@@ -1978,8 +2016,10 @@
 	       BAD_CAST "http://www.w3.org/2001/XMLSchema");
     if (typ == NULL)
 	return(-1);
-    ret = xmlSchemaValidatePredefinedType(typ, value,
-	                                  (xmlSchemaValPtr *) result);
+    ret = xmlSchemaValPredefTypeNode(typ, value,
+	                             (xmlSchemaValPtr *) result, node);
+    if (ret == 2) /* special ID error code */
+	return(2);
     if (ret == 0)
 	return(1);
     if (ret > 0)
@@ -2107,6 +2147,7 @@
  * @data:  data needed for the library
  * @type:  the type name
  * @value:  the value to check
+ * @node:  the node
  *
  * Check if the given type and value are validated by
  * the default datatype library.
@@ -2117,7 +2158,8 @@
 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
 	                   const xmlChar *type ATTRIBUTE_UNUSED,
 			   const xmlChar *value ATTRIBUTE_UNUSED,
-			   void **result ATTRIBUTE_UNUSED) {
+			   void **result ATTRIBUTE_UNUSED,
+			   xmlNodePtr node ATTRIBUTE_UNUSED) {
     if (value == NULL)
 	return(-1);
     if (xmlStrEqual(type, BAD_CAST "string"))
@@ -2707,6 +2749,11 @@
 		    "Error type '%s' is not exported by type library '%s'\n",
 			    def->name, library);
 		ctxt->nbErrors++;
+	    } else if ((xmlStrEqual(library, BAD_CAST
+			   "http://www.w3.org/2001/XMLSchema-datatypes")) &&
+		       ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
+		        (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
+		ctxt->idref = 1;
 	    }
 	}
     }
@@ -6317,6 +6364,8 @@
     ret->defNr = ctxt->defNr;
     ret->defTab = ctxt->defTab;
     ctxt->defTab = NULL;
+    if (ctxt->idref == 1)
+	ret->idref = 1;
 
     return (ret);
 }
@@ -6659,6 +6708,7 @@
  * @ctxt:  a Relax-NG validation context
  * @value:  the string value
  * @type:  the datatype definition
+ * @node:  the node
  *
  * Validate the given value against the dataype
  *
@@ -6666,7 +6716,7 @@
  */
 static int
 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
-	                   xmlRelaxNGDefinePtr define) {
+	                   xmlRelaxNGDefinePtr define, xmlNodePtr node) {
     int ret, tmp;
     xmlRelaxNGTypeLibraryPtr lib;
     void *result = NULL;
@@ -6679,9 +6729,9 @@
     if (lib->check != NULL) {
 	if ((define->attrs != NULL) &&
 	    (define->attrs->type == XML_RELAXNG_PARAM)) {
-	    ret = lib->check(lib->data, define->name, value, &result);
+	    ret = lib->check(lib->data, define->name, value, &result, node);
 	} else {
-	    ret = lib->check(lib->data, define->name, value, NULL);
+	    ret = lib->check(lib->data, define->name, value, NULL, node);
 	}
     } else 
 	ret = -1;
@@ -6692,8 +6742,10 @@
 	return(-1);
     } else if (ret == 1) {
 	ret = 0;
+    } else if (ret == 2) {
+	VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
     } else {
-	VALID_ERR3(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
+	VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
 	ret = -1;
     }
     cur = define->attrs;
@@ -6845,7 +6897,8 @@
 	    break;
 	}
 	case XML_RELAXNG_DATATYPE: {
-	    ret = xmlRelaxNGValidateDatatype(ctxt, value, define);
+	    ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
+		                             ctxt->state->seq);
 	    if (ret == 0)
 		xmlRelaxNGNextValue(ctxt);
 	    
@@ -7112,6 +7165,7 @@
     int ret = 0, i;
     xmlChar *value, *oldvalue;
     xmlAttrPtr prop = NULL, tmp;
+    xmlNodePtr oldseq;
 
     if (ctxt->state->nbAttrLeft <= 0)
 	return(-1);
@@ -7131,6 +7185,8 @@
 	if (prop != NULL) {
 	    value = xmlNodeListGetString(prop->doc, prop->children, 1);
 	    oldvalue = ctxt->state->value;
+	    oldseq = ctxt->state->seq;
+	    ctxt->state->seq = (xmlNodePtr) prop;
 	    ctxt->state->value = value;
 	    ctxt->state->endvalue = NULL;
 	    ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
@@ -7139,6 +7195,7 @@
 	    if (value != NULL)
 		xmlFree(value);
 	    ctxt->state->value = oldvalue;
+	    ctxt->state->seq = oldseq;
 	    if (ret == 0) {
 		/*
 		 * flag the attribute as processed
@@ -7165,6 +7222,8 @@
 	if (prop != NULL) {
 	    value = xmlNodeListGetString(prop->doc, prop->children, 1);
 	    oldvalue = ctxt->state->value;
+	    oldseq = ctxt->state->seq;
+	    ctxt->state->seq = (xmlNodePtr) prop;
 	    ctxt->state->value = value;
 	    ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
 	    if (ctxt->state->value != NULL)
@@ -7172,6 +7231,7 @@
 	    if (value != NULL)
 		xmlFree(value);
 	    ctxt->state->value = oldvalue;
+	    ctxt->state->seq = oldseq;
 	    if (ret == 0) {
 		/*
 		 * flag the attribute as processed
@@ -8050,7 +8110,8 @@
 		    break;
 		}
 	    }
-	    ret = xmlRelaxNGValidateDatatype(ctxt, content, define);
+	    ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
+		                             ctxt->state->seq);
 	    if (ret == -1) {
 		VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
 	    } else if (ret == 0) {
@@ -8374,6 +8435,18 @@
     xmlRelaxNGFreeValidState(state);
     if (ret != 0)
 	xmlRelaxNGDumpValidError(ctxt);
+    if (ctxt->idref == 1) {
+	xmlValidCtxt vctxt;
+
+	memset(&vctxt, 0, sizeof(xmlValidCtxt));
+	vctxt.valid = 1;
+	vctxt.error = ctxt->error;
+	vctxt.warning = ctxt->warning;
+	vctxt.userData = ctxt->userData;
+
+	if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
+	    ret = -1;
+    }
 
     return(ret);
 }
@@ -8409,6 +8482,7 @@
     ret->errMax = 0;
     ret->err = NULL;
     ret->errTab = NULL;
+    ret->idref = schema->idref;
     return (ret);
 }