float/double check bugfix exported a function for NMTOKEN validation add a

* xmlschemastypes.c: float/double check bugfix
* tree.c include/libxml/tree.h: exported a function for NMTOKEN
  validation
* xmlreader.c: add a TODO for Jody
* relaxng.c: bugfix bugfix bugfix
  found 373 test schemas: 300 success 73 failures
  found 529 test instances: 507 success 10 failures
* result/relaxng/*: updated the results
Daniel
diff --git a/ChangeLog b/ChangeLog
index 2021242..348f93d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+Tue Feb 18 22:09:50 CET 2003 Daniel Veillard <daniel@veillard.com>
+
+	* xmlschemastypes.c: float/double check bugfix
+	* tree.c include/libxml/tree.h: exported a function for NMTOKEN
+	  validation
+	* xmlreader.c: add a TODO for Jody
+	* relaxng.c: bugfix bugfix bugfix
+	  found 373 test schemas: 300 success 73 failures
+	  found 529 test instances: 507 success 10 failures
+	* result/relaxng/*: updated the results
+
 Tue Feb 18 00:33:17 CET 2003 Daniel Veillard <daniel@veillard.com>
 
 	* relaxng.c check-relaxng-test-suite.py: more RelaxNG bug hunting
diff --git a/check-relaxng-test-suite.py b/check-relaxng-test-suite.py
index 7eba531..3cd328a 100755
--- a/check-relaxng-test-suite.py
+++ b/check-relaxng-test-suite.py
@@ -7,6 +7,8 @@
 sys.path.append("python")
 import libxml2
 
+debug = 0
+
 #
 # the testsuite description
 #
@@ -256,6 +258,8 @@
 
               nb_schemas_tests, node.lineNo()))
     resources = {}
+    if debug:
+        print "test %d line %d" % (nb_schemas_tests, node.lineNo())
 
     dirs = node.xpathEval('dir')
     for dir in dirs:
diff --git a/include/libxml/tree.h b/include/libxml/tree.h
index d77d704..8521a31 100644
--- a/include/libxml/tree.h
+++ b/include/libxml/tree.h
@@ -538,9 +538,11 @@
 LIBXML_DLL_IMPORT extern int xmlDefaultBufferSize; /* default buffer size */
 #endif
 
-int		 xmlValidateNCName	(const xmlChar *value, int space);
-int		 xmlValidateQName	(const xmlChar *value, int space);
-int		 xmlValidateName	(const xmlChar *value, int space);
+int		xmlValidateNCName	(const xmlChar *value, int space);
+int		xmlValidateQName	(const xmlChar *value, int space);
+int		xmlValidateName		(const xmlChar *value, int space);
+int		xmlValidateNMToken	(const xmlChar *value, int space);
+
 /*
  * Handling Buffers.
  */
diff --git a/relaxng.c b/relaxng.c
index ac8194c..5b0efab 100644
--- a/relaxng.c
+++ b/relaxng.c
@@ -100,9 +100,6 @@
     XML_RELAXNG_NOT_ALLOWED,    /* not allowed top */
     XML_RELAXNG_EXCEPT,    	/* except present in nameclass defs */
     XML_RELAXNG_TEXT,		/* textual content */
-#if 0
-    XML_RELAXNG_MIXED,		/* mixed content with single sub-content */
-#endif
     XML_RELAXNG_ELEMENT,	/* an element */
     XML_RELAXNG_DATATYPE,	/* extenal data type definition */
     XML_RELAXNG_VALUE,		/* value from an extenal data type definition */
@@ -128,6 +125,7 @@
     xmlChar       *ns;		/* the namespace local name if present */
     xmlChar       *value;	/* value when available */
     void          *data;	/* data lib or specific pointer */
+    int            depth;       /* used for the cycle detection */
     xmlRelaxNGDefinePtr content;/* the expected content */
     xmlRelaxNGDefinePtr parent;	/* the parent definition, if any */
     xmlRelaxNGDefinePtr next;	/* list within grouping sequences */
@@ -199,7 +197,7 @@
     xmlRelaxNGDocumentPtr *docTab;    /* array of docs */
 
     /* the include stack */
-    xmlRelaxNGIncludePtr inc;         /* Current parsed include */
+    xmlRelaxNGIncludePtr  inc;        /* Current parsed include */
     int                   incNr;      /* Depth of the include parsing stack */
     int                   incMax;     /* Max depth of the parsing stack */
     xmlRelaxNGIncludePtr *incTab;     /* array of incs */
@@ -554,6 +552,7 @@
     memset(ret, 0, sizeof(xmlRelaxNGDefine));
     ctxt->defTab[ctxt->defNr++] = ret;
     ret->node = node;
+    ret->depth = -1;
     return (ret);
 }
 
@@ -1450,7 +1449,24 @@
 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
 	                   const xmlChar *type ATTRIBUTE_UNUSED,
 			  const xmlChar *value ATTRIBUTE_UNUSED) {
-    return(1);
+    if (value == NULL)
+	return(-1);
+    if (xmlStrEqual(type, BAD_CAST "string"))
+	return(1);
+    if (xmlStrEqual(type, BAD_CAST "token")) {
+#if 0
+	const xmlChar *cur = value;
+
+	while (*cur != 0) {
+	    if (!IS_BLANK(*cur))
+		return(1);
+	    cur++;
+	}
+#endif
+	return(1);
+    }
+
+    return(0);
 }
 
 /**
@@ -1485,14 +1501,18 @@
 	    nval = xmlRelaxNGNormalize(NULL, value1);
 	    nvalue = xmlRelaxNGNormalize(NULL, value2);
 
-	    if ((nval == NULL) || (nvalue == NULL) ||
-		(!xmlStrEqual(nval, nvalue)))
+	    if ((nval == NULL) || (nvalue == NULL))
 		ret = -1;
+	    else if (xmlStrEqual(nval, nvalue))
+		ret = 1;
+	    else
+		ret = 0;
 	    if (nval != NULL)
 		xmlFree(nval);
 	    if (nvalue != NULL)
 		xmlFree(nvalue);
-	}
+	} else
+	    ret = 1;
     }
     return(ret);
 }
@@ -1782,10 +1802,7 @@
 	}
     }
     if (node->children == NULL) {
-	if (ctxt->error != NULL)
-	    ctxt->error(ctxt->userData,
-			"Element <value> has no content\n");
-	ctxt->nbErrors++;
+	def->value = xmlStrdup(BAD_CAST "");
     } else if ((node->children->type != XML_TEXT_NODE) ||
 	       (node->children->next != NULL)) {
 	if (ctxt->error != NULL)
@@ -2596,14 +2613,6 @@
 				def->name);
 		ctxt->nbErrors++;
 	    }
-	    if ((ctxt->define != NULL) &&
-	        (xmlStrEqual(ctxt->define, def->name))) {
-		if (ctxt->error != NULL)
-		    ctxt->error(ctxt->userData,
-			"Recursive reference to %s not in an element\n",
-			        def->name);
-		ctxt->nbErrors++;
-	    }
 	}
 	if (node->children != NULL) {
 	    if (ctxt->error != NULL)
@@ -2775,13 +2784,6 @@
 		    "Mixed is empty\n");
 	    ctxt->nbErrors++;
 	    def = NULL;
-#if 0
-	} else if (node->children->next == NULL) {
-	    def = xmlRelaxNGNewDefine(ctxt, node);
-	    if (def == NULL)
-		return(NULL);
-	    def->type = XML_RELAXNG_MIXED;
-#endif
 	} else {
 	    def = xmlRelaxNGParseInterleave(ctxt, node);
 	    if (def != NULL) {
@@ -2869,9 +2871,6 @@
 		case XML_RELAXNG_OPTIONAL:
 		case XML_RELAXNG_CHOICE:
 		case XML_RELAXNG_GROUP:
-#if 0
-		case XML_RELAXNG_MIXED:
-#endif
 		case XML_RELAXNG_INTERLEAVE:
 		    ret->content = cur;
 		    cur->parent = ret;
@@ -3050,6 +3049,12 @@
 			       (def->type == XML_RELAXNG_ATTRIBUTE));
 	}
     } else if (IS_RELAXNG(node, "choice")) {
+	ret = xmlRelaxNGNewDefine(ctxt, node);
+	if (ret == NULL)
+	    return(NULL);
+	ret->parent = def;
+	ret->type = XML_RELAXNG_CHOICE;
+
 	if (node->children == NULL) {
 	    if (ctxt->error != NULL)
 		ctxt->error(ctxt->userData,
@@ -3061,7 +3066,7 @@
 
 	    child = node->children;
 	    while (child != NULL) {
-		tmp = xmlRelaxNGParseNameClass(ctxt, child, def);
+		tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
 		if (tmp != NULL) {
 		    if (last == NULL) {
 			last = ret->nameClass = tmp;
@@ -3147,9 +3152,6 @@
 		case XML_RELAXNG_OPTIONAL:
 		case XML_RELAXNG_CHOICE:
 		case XML_RELAXNG_GROUP:
-#if 0
-		case XML_RELAXNG_MIXED:
-#endif
 		case XML_RELAXNG_INTERLEAVE:
 		    if (last == NULL) {
 			ret->content = last = cur;
@@ -3391,9 +3393,18 @@
 		cur = cur->nextHash;
 	    }
 	} else {
-	    TODO
+	    if (ctxt->error != NULL)
+		ctxt->error(ctxt->userData,
+		"Reference %s has no matching definition\n",
+			    name);
 	    ctxt->nbErrors++;
 	}
+    } else {
+	if (ctxt->error != NULL)
+	    ctxt->error(ctxt->userData,
+	    "Reference %s has no matching definition\n",
+			name);
+	ctxt->nbErrors++;
     }
     /*
      * TODO: make a closure and verify there is no loop !
@@ -3639,6 +3650,45 @@
 }
 
 /**
+ * xmlRelaxNGCheckCycles:
+ * @ctxt:  a Relax-NG parser context
+ * @nodes:  grammar children nodes
+ * @depth:  the counter
+ *
+ * Check for cycles.
+ *
+ * Returns 0 if check passed, and -1 in case of error
+ */
+static int
+xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt, 
+	              xmlRelaxNGDefinePtr cur, int depth) {
+    int ret = 0;
+
+    while ((ret == 0) && (cur != NULL)) {
+	if ((cur->type == XML_RELAXNG_REF) ||
+	    (cur->type == XML_RELAXNG_PARENTREF)) {
+	    if (cur->depth == -1) {
+		cur->depth = depth;
+		ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
+		cur->depth = -2;
+	    } else if (depth == cur->depth) {
+		if (ctxt->error != NULL)
+		    ctxt->error(ctxt->userData,
+		    "Detected a cycle in %s references\n", cur->name);
+		ctxt->nbErrors++;
+		return(-1);
+	    }
+	} else if (cur->type == XML_RELAXNG_ELEMENT) {
+	    ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
+	} else {
+	    ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
+	}
+	cur = cur->next;
+    }
+    return(ret);
+}
+
+/**
  * xmlRelaxNGParseGrammar:
  * @ctxt:  a Relax-NG parser context
  * @nodes:  grammar children nodes
@@ -3748,6 +3798,9 @@
 	    ctxt->grammar = old;
     }
     ctxt->define = olddefine;
+    if (schema->topgrammar->start != NULL) {
+	xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
+    }
 
 #ifdef DEBUG
     if (schema == NULL)
@@ -4628,13 +4681,6 @@
 	    xmlRelaxNGDumpDefines(output, define->content);
 	    fprintf(output, "</externalRef>\n");
 	    break;
-#if 0
-	case XML_RELAXNG_MIXED:
-	    fprintf(output, "<mixed>");
-	    xmlRelaxNGDumpDefines(output, define->content);
-	    fprintf(output, "</mixed>\n");
-	    break;
-#endif
         case XML_RELAXNG_DATATYPE:
         case XML_RELAXNG_VALUE:
 	    TODO
@@ -4938,10 +4984,17 @@
 
     value = ctxt->state->value;
     switch (define->type) {
-	case XML_RELAXNG_EMPTY:
-	    if ((value != NULL) && (value[0] != '0'))
-		ret = -1;
+	case XML_RELAXNG_EMPTY: {
+	    if ((value != NULL) && (value[0] != 0)) {
+		int idx = 0;
+
+		while (IS_BLANK(value[idx]))
+		    idx++;
+		if (value[idx] != 0)
+		    ret = -1;
+	    }
 	    break;
+	}
 	case XML_RELAXNG_TEXT:
 	    break;
 	case XML_RELAXNG_VALUE: {
@@ -5028,6 +5081,9 @@
 
 	    val = xmlStrdup(oldvalue);
 	    if (val == NULL) {
+		val = xmlStrdup(BAD_CAST "");
+	    }
+	    if (val == NULL) {
 		VALID_CTXT();
 		VALID_ERROR("Internal: no state\n");
 		return(-1);
@@ -5124,6 +5180,21 @@
 	    }
 	    break;
 	}
+        case XML_RELAXNG_GROUP: {
+	    xmlRelaxNGDefinePtr list;
+
+	    list = define->content;
+	    while (list != NULL) {
+		ret = xmlRelaxNGValidateValue(ctxt, list);
+		if (ret != 0) {
+		    ret = -1;
+		    break;
+		} else 
+		    ret = 0;
+		list = list->next;
+	    }
+	    break;
+	}
 	default:
 	    TODO
 	    ret = -1;
@@ -5804,6 +5875,7 @@
     ctxt->depth++;
     switch (define->type) {
         case XML_RELAXNG_EMPTY:
+	    node = xmlRelaxNGSkipIgnored(ctxt, node);
 	    if (node != NULL) {
 		VALID_CTXT();
 		VALID_ERROR("Expecting an empty element\n");
@@ -6042,39 +6114,83 @@
 	    ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
 	    break;
         case XML_RELAXNG_DATATYPE: {
-	    xmlChar *content;
+	    xmlNodePtr child;
+	    xmlChar *content = NULL;
 
-	    content = xmlNodeGetContent(node);
+	    child = node;
+	    while (child != NULL) {
+		if (child->type == XML_ELEMENT_NODE) {
+		    VALID_CTXT();
+		    VALID_ERROR2("Element %s has child elements\n",
+				 node->parent->name);
+		    ret = -1;
+		    break;
+		} else if ((child->type == XML_TEXT_NODE) ||
+			   (child->type == XML_CDATA_SECTION_NODE)) {
+		    content = xmlStrcat(content, child->content);
+		}
+		/* TODO: handle entities ... */
+		child = child->next;
+	    }
+	    if (ret == -1) {
+		if (content != NULL)
+		    xmlFree(content);
+		break;
+	    }
+	    if (content == NULL) {
+		content = xmlStrdup(BAD_CAST "");
+		if (content == NULL) {
+		    VALID_CTXT();
+		    VALID_ERROR("Allocation failure\n");
+		    ret = -1;
+		    break;
+		}
+	    }
 	    ret = xmlRelaxNGValidateDatatype(ctxt, content, define);
 	    if (ret == -1) {
 		VALID_CTXT();
 		VALID_ERROR2("internal error validating %s\n", define->name);
 	    } else if (ret == 0) {
-		if (node != NULL)
-		    ctxt->state->seq = node->next;
-		else
-		    ctxt->state->seq = NULL;
-	    }
-	    /*
-	     * 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_ERROR2("The data does not cover the full element %s\n",
-			    node->parent->name);
-		ret = -1;
+		ctxt->state->seq = NULL;
 	    }
 	    if (content != NULL)
 		xmlFree(content);
 	    break;
 	}
         case XML_RELAXNG_VALUE: {
-	    xmlChar *content;
+	    xmlChar *content = NULL;
 	    xmlChar *oldvalue;
+	    xmlNodePtr child;
 
-	    content = xmlNodeGetContent(node);
+	    child = node;
+	    while (child != NULL) {
+		if (child->type == XML_ELEMENT_NODE) {
+		    VALID_CTXT();
+		    VALID_ERROR2("Element %s has child elements\n",
+				 node->parent->name);
+		    ret = -1;
+		    break;
+		} else if ((child->type == XML_TEXT_NODE) ||
+			   (child->type == XML_CDATA_SECTION_NODE)) {
+		    content = xmlStrcat(content, child->content);
+		}
+		/* TODO: handle entities ... */
+		child = child->next;
+	    }
+	    if (ret == -1) {
+		if (content != NULL)
+		    xmlFree(content);
+		break;
+	    }
+	    if (content == NULL) {
+		content = xmlStrdup(BAD_CAST "");
+		if (content == NULL) {
+		    VALID_CTXT();
+		    VALID_ERROR("Allocation failure\n");
+		    ret = -1;
+		    break;
+		}
+	    }
 	    oldvalue = ctxt->state->value;
 	    ctxt->state->value = content;
 	    ret = xmlRelaxNGValidateValue(ctxt, define);
@@ -6087,18 +6203,7 @@
 		    VALID_ERROR("error validating value\n");
 		}
 	    } 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_ERROR2("The value does not cover the full element %s\n",
-			    node->parent->name);
-		ret = -1;
+		ctxt->state->seq = NULL;
 	    }
 	    if (content != NULL)
 		xmlFree(content);
@@ -6106,10 +6211,44 @@
 	}
         case XML_RELAXNG_LIST: {
 	    xmlChar *content;
+	    xmlNodePtr child;
 	    xmlChar *oldvalue, *oldendvalue;
 	    int len;
 
-	    content = xmlNodeGetContent(node);
+	    /*
+	     * Make sure it's only text nodes
+	     */
+	    
+	    content = NULL;
+	    child = node;
+	    while (child != NULL) {
+		if (child->type == XML_ELEMENT_NODE) {
+		    VALID_CTXT();
+		    VALID_ERROR2("Element %s has child elements\n",
+				 node->parent->name);
+		    ret = -1;
+		    break;
+		} else if ((child->type == XML_TEXT_NODE) ||
+			   (child->type == XML_CDATA_SECTION_NODE)) {
+		    content = xmlStrcat(content, child->content);
+		}
+		/* TODO: handle entities ... */
+		child = child->next;
+	    }
+	    if (ret == -1) {
+		if (content != NULL)
+		    xmlFree(content);
+		break;
+	    }
+	    if (content == NULL) {
+		content = xmlStrdup(BAD_CAST "");
+		if (content == NULL) {
+		    VALID_CTXT();
+		    VALID_ERROR("Allocation failure\n");
+		    ret = -1;
+		    break;
+		}
+	    }
 	    len = xmlStrlen(content);
 	    oldvalue = ctxt->state->value;
 	    oldendvalue = ctxt->state->endvalue;
@@ -6121,30 +6260,13 @@
 	    if (ret == -1) {
 		VALID_CTXT();
 		VALID_ERROR("internal error validating list\n");
-	    } else if (ret == 0) {
+	    } else if ((ret == 0) && (node != NULL)) {
 		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_ERROR2("The list does not cover the full element %s\n",
-			    node->parent->name);
-		ret = -1;
-	    }
 	    if (content != NULL)
 		xmlFree(content);
 	    break;
         }
-#if 0
-	case XML_RELAXNG_MIXED:
-	    TODO
-	    ret = -1;
-	    break;
-#endif
 	case XML_RELAXNG_START:
 	case XML_RELAXNG_EXCEPT:
 	    TODO
diff --git a/result/relaxng/spec1_err b/result/relaxng/spec1_err
index d672705..31d0f65 100644
--- a/result/relaxng/spec1_err
+++ b/result/relaxng/spec1_err
@@ -1 +1 @@
-Unimplemented block at relaxng.c:5502
+Unimplemented block at relaxng.c:5605
diff --git a/result/relaxng/tutor10_1_4.err b/result/relaxng/tutor10_1_4.err
index 0378cea..4c9685e 100644
--- a/result/relaxng/tutor10_1_4.err
+++ b/result/relaxng/tutor10_1_4.err
@@ -1,4 +1,4 @@
-error detected at relaxng.c:5686
+error detected at relaxng.c:5789
 Expecting a namespace for element foo
-error detected at relaxng.c:6174
+error detected at relaxng.c:6328
 extra data on the document
diff --git a/result/relaxng/tutor10_1_5.err b/result/relaxng/tutor10_1_5.err
index e483ad8..a430d81 100644
--- a/result/relaxng/tutor10_1_5.err
+++ b/result/relaxng/tutor10_1_5.err
@@ -1,4 +1,4 @@
-error detected at relaxng.c:5691
+error detected at relaxng.c:5794
 Expecting element foo has wrong namespace: expecting http://www.example.com
-error detected at relaxng.c:6174
+error detected at relaxng.c:6328
 extra data on the document
diff --git a/result/relaxng/tutor10_1_6.err b/result/relaxng/tutor10_1_6.err
index e483ad8..a430d81 100644
--- a/result/relaxng/tutor10_1_6.err
+++ b/result/relaxng/tutor10_1_6.err
@@ -1,4 +1,4 @@
-error detected at relaxng.c:5691
+error detected at relaxng.c:5794
 Expecting element foo has wrong namespace: expecting http://www.example.com
-error detected at relaxng.c:6174
+error detected at relaxng.c:6328
 extra data on the document
diff --git a/result/relaxng/tutor10_2_3.err b/result/relaxng/tutor10_2_3.err
index 0bf8041..611c7b5 100644
--- a/result/relaxng/tutor10_2_3.err
+++ b/result/relaxng/tutor10_2_3.err
@@ -1,4 +1,4 @@
-error detected at relaxng.c:5698
+error detected at relaxng.c:5801
 Expecting no namespace for element foo
-error detected at relaxng.c:6174
+error detected at relaxng.c:6328
 extra data on the document
diff --git a/result/relaxng/tutor10_2_4.err b/result/relaxng/tutor10_2_4.err
index 0bf8041..611c7b5 100644
--- a/result/relaxng/tutor10_2_4.err
+++ b/result/relaxng/tutor10_2_4.err
@@ -1,4 +1,4 @@
-error detected at relaxng.c:5698
+error detected at relaxng.c:5801
 Expecting no namespace for element foo
-error detected at relaxng.c:6174
+error detected at relaxng.c:6328
 extra data on the document
diff --git a/result/relaxng/tutor10_7_3.err b/result/relaxng/tutor10_7_3.err
index c9a8556..cd64b4a 100644
--- a/result/relaxng/tutor10_7_3.err
+++ b/result/relaxng/tutor10_7_3.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element addressBook: card
diff --git a/result/relaxng/tutor10_8_3.err b/result/relaxng/tutor10_8_3.err
index c9a8556..cd64b4a 100644
--- a/result/relaxng/tutor10_8_3.err
+++ b/result/relaxng/tutor10_8_3.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element addressBook: card
diff --git a/result/relaxng/tutor11_2_2.err b/result/relaxng/tutor11_2_2.err
index 12657cf..c388d92 100644
--- a/result/relaxng/tutor11_2_2.err
+++ b/result/relaxng/tutor11_2_2.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5879
+error detected at relaxng.c:5983
 Invalid attribute foo for element card
diff --git a/result/relaxng/tutor11_2_3.err b/result/relaxng/tutor11_2_3.err
index 384c886..9e645f2 100644
--- a/result/relaxng/tutor11_2_3.err
+++ b/result/relaxng/tutor11_2_3.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5879
+error detected at relaxng.c:5983
 Invalid attribute b for element card
diff --git a/result/relaxng/tutor12_1_err b/result/relaxng/tutor12_1_err
index d672705..31d0f65 100644
--- a/result/relaxng/tutor12_1_err
+++ b/result/relaxng/tutor12_1_err
@@ -1 +1 @@
-Unimplemented block at relaxng.c:5502
+Unimplemented block at relaxng.c:5605
diff --git a/result/relaxng/tutor3_2_1.err b/result/relaxng/tutor3_2_1.err
index 6ed44be..847b0ec 100644
--- a/result/relaxng/tutor3_2_1.err
+++ b/result/relaxng/tutor3_2_1.err
@@ -1,4 +1,4 @@
-error detected at relaxng.c:5678
+error detected at relaxng.c:5781
 Expecting element name, got email
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element card: email
diff --git a/result/relaxng/tutor3_5_2.err b/result/relaxng/tutor3_5_2.err
index c9a8556..cd64b4a 100644
--- a/result/relaxng/tutor3_5_2.err
+++ b/result/relaxng/tutor3_5_2.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element addressBook: card
diff --git a/result/relaxng/tutor3_7_err b/result/relaxng/tutor3_7_err
index d203d70..ce5ce38 100644
--- a/result/relaxng/tutor3_7_err
+++ b/result/relaxng/tutor3_7_err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:6174
+error detected at relaxng.c:6328
 extra data on the document
diff --git a/result/relaxng/tutor4_4_1.err b/result/relaxng/tutor4_4_1.err
index 97feebd..dd78d26 100644
--- a/result/relaxng/tutor4_4_1.err
+++ b/result/relaxng/tutor4_4_1.err
@@ -1 +1 @@
-Recursive reference to inline not in an element
+Detected a cycle in inline references
diff --git a/result/relaxng/tutor5_3_1.err b/result/relaxng/tutor5_3_1.err
index d767e35..b76bcc3 100644
--- a/result/relaxng/tutor5_3_1.err
+++ b/result/relaxng/tutor5_3_1.err
@@ -1,2 +1,6 @@
-error detected at relaxng.c:6032
-The data does not cover the full element bad
+error detected at relaxng.c:6123
+Element bad has child elements
+error detected at relaxng.c:5917
+Expecting an element got 3 type
+error detected at relaxng.c:5970
+Extra content for element bad: text
diff --git a/result/relaxng/tutor6_1_3.err b/result/relaxng/tutor6_1_3.err
index dff42c3..70bc013 100644
--- a/result/relaxng/tutor6_1_3.err
+++ b/result/relaxng/tutor6_1_3.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5879
+error detected at relaxng.c:5983
 Invalid attribute preferredFormat for element card
diff --git a/result/relaxng/tutor6_2_4.err b/result/relaxng/tutor6_2_4.err
index f20ab75..08444b6 100644
--- a/result/relaxng/tutor6_2_4.err
+++ b/result/relaxng/tutor6_2_4.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element preferredFormat: text
diff --git a/result/relaxng/tutor6_3_1.err b/result/relaxng/tutor6_3_1.err
index dff42c3..70bc013 100644
--- a/result/relaxng/tutor6_3_1.err
+++ b/result/relaxng/tutor6_3_1.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5879
+error detected at relaxng.c:5983
 Invalid attribute preferredFormat for element card
diff --git a/result/relaxng/tutor7_1_2.err b/result/relaxng/tutor7_1_2.err
index bca8415..ec67e9a 100644
--- a/result/relaxng/tutor7_1_2.err
+++ b/result/relaxng/tutor7_1_2.err
@@ -1,6 +1,6 @@
-error detected at relaxng.c:4817
+error detected at relaxng.c:4895
 Internal: failed to validate type float
-error detected at relaxng.c:6090
+error detected at relaxng.c:6261
 internal error validating list
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element vector: text
diff --git a/result/relaxng/tutor7_1_3.err b/result/relaxng/tutor7_1_3.err
index 4edebee..30ef2df 100644
--- a/result/relaxng/tutor7_1_3.err
+++ b/result/relaxng/tutor7_1_3.err
@@ -1,6 +1,6 @@
-error detected at relaxng.c:5044
+error detected at relaxng.c:5132
 Extra data in list: 5.6
-error detected at relaxng.c:6090
+error detected at relaxng.c:6261
 internal error validating list
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element vector: text
diff --git a/result/relaxng/tutor7_2_4.err b/result/relaxng/tutor7_2_4.err
index 80d04c6..dbcba9a 100644
--- a/result/relaxng/tutor7_2_4.err
+++ b/result/relaxng/tutor7_2_4.err
@@ -1,4 +1,4 @@
-error detected at relaxng.c:4999
-Internal: no state
-error detected at relaxng.c:6090
+error detected at relaxng.c:4901
+Type double doesn't allow value 
+error detected at relaxng.c:6261
 internal error validating list
diff --git a/result/relaxng/tutor7_3_4.err b/result/relaxng/tutor7_3_4.err
index 7653463..71b568a 100644
--- a/result/relaxng/tutor7_3_4.err
+++ b/result/relaxng/tutor7_3_4.err
@@ -1,6 +1,6 @@
-error detected at relaxng.c:5044
+error detected at relaxng.c:5132
 Extra data in list: 5.6
-error detected at relaxng.c:6090
+error detected at relaxng.c:6261
 internal error validating list
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element path: text
diff --git a/result/relaxng/tutor7_3_5.err b/result/relaxng/tutor7_3_5.err
index 1dec06d..afa1203 100644
--- a/result/relaxng/tutor7_3_5.err
+++ b/result/relaxng/tutor7_3_5.err
@@ -1,6 +1,6 @@
-error detected at relaxng.c:4817
+error detected at relaxng.c:4895
 Internal: failed to validate type double
-error detected at relaxng.c:6090
+error detected at relaxng.c:6261
 internal error validating list
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element path: text
diff --git a/result/relaxng/tutor8_2_4.err b/result/relaxng/tutor8_2_4.err
index 9a08754..efdd6e9 100644
--- a/result/relaxng/tutor8_2_4.err
+++ b/result/relaxng/tutor8_2_4.err
@@ -1,4 +1,4 @@
-Unimplemented block at relaxng.c:5502
-Unimplemented block at relaxng.c:5502
-error detected at relaxng.c:5866
+Unimplemented block at relaxng.c:5605
+Unimplemented block at relaxng.c:5605
+error detected at relaxng.c:5970
 Extra content for element head: meta
diff --git a/result/relaxng/tutor8_2_5.err b/result/relaxng/tutor8_2_5.err
index 8890db3..c790899 100644
--- a/result/relaxng/tutor8_2_5.err
+++ b/result/relaxng/tutor8_2_5.err
@@ -1,4 +1,4 @@
-error detected at relaxng.c:5807
+error detected at relaxng.c:5911
 Expecting an element, got empty
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element head: meta
diff --git a/result/relaxng/tutor8_2_6.err b/result/relaxng/tutor8_2_6.err
index 7301b17..0d75861 100644
--- a/result/relaxng/tutor8_2_6.err
+++ b/result/relaxng/tutor8_2_6.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element head: base
diff --git a/result/relaxng/tutor9_5_2.err b/result/relaxng/tutor9_5_2.err
index c9a8556..cd64b4a 100644
--- a/result/relaxng/tutor9_5_2.err
+++ b/result/relaxng/tutor9_5_2.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element addressBook: card
diff --git a/result/relaxng/tutor9_5_3.err b/result/relaxng/tutor9_5_3.err
index c9a8556..cd64b4a 100644
--- a/result/relaxng/tutor9_5_3.err
+++ b/result/relaxng/tutor9_5_3.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element addressBook: card
diff --git a/result/relaxng/tutor9_6_2.err b/result/relaxng/tutor9_6_2.err
index c9a8556..cd64b4a 100644
--- a/result/relaxng/tutor9_6_2.err
+++ b/result/relaxng/tutor9_6_2.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element addressBook: card
diff --git a/result/relaxng/tutor9_6_3.err b/result/relaxng/tutor9_6_3.err
index c9a8556..cd64b4a 100644
--- a/result/relaxng/tutor9_6_3.err
+++ b/result/relaxng/tutor9_6_3.err
@@ -1,2 +1,2 @@
-error detected at relaxng.c:5866
+error detected at relaxng.c:5970
 Extra content for element addressBook: card
diff --git a/tree.c b/tree.c
index e19817a..dbe94fb 100644
--- a/tree.c
+++ b/tree.c
@@ -363,6 +363,76 @@
     return(0);
 }
 
+/**
+ * xmlValidateNMToken:
+ * @value: the value to check
+ * @space: allow spaces in front and end of the string
+ *
+ * Check that a value conforms to the lexical space of NMToken
+ *
+ * Returns 0 if this validates, a positive error code number otherwise
+ *         and -1 in case of internal or API error.
+ */
+int
+xmlValidateNMToken(const xmlChar *value, int space) {
+    const xmlChar *cur = value;
+    int c,l;
+
+    /*
+     * First quick algorithm for ASCII range
+     */
+    if (space)
+	while (IS_BLANK(*cur)) cur++;
+    if (((*cur >= 'a') && (*cur <= 'z')) ||
+        ((*cur >= 'A') && (*cur <= 'Z')) ||
+        ((*cur >= '0') && (*cur <= '9')) ||
+        (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
+	cur++;
+    else
+	goto try_complex;
+    while (((*cur >= 'a') && (*cur <= 'z')) ||
+	   ((*cur >= 'A') && (*cur <= 'Z')) ||
+	   ((*cur >= '0') && (*cur <= '9')) ||
+	   (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':'))
+	cur++;
+    if (space)
+	while (IS_BLANK(*cur)) cur++;
+    if (*cur == 0)
+	return(0);
+
+try_complex:
+    /*
+     * Second check for chars outside the ASCII range
+     */
+    cur = value;
+    c = CUR_SCHAR(cur, l);
+    if (space) {
+	while (IS_BLANK(c)) {
+	    cur += l;
+	    c = CUR_SCHAR(cur, l);
+	}
+    }
+    if (!(xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
+        (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)))
+	return(1);
+    cur += l;
+    c = CUR_SCHAR(cur, l);
+    while (xmlIsLetter(c) || xmlIsDigit(c) || (c == '.') || (c == ':') ||
+	   (c == '-') || (c == '_') || xmlIsCombining(c) || xmlIsExtender(c)) {
+	cur += l;
+	c = CUR_SCHAR(cur, l);
+    }
+    if (space) {
+	while (IS_BLANK(c)) {
+	    cur += l;
+	    c = CUR_SCHAR(cur, l);
+	}
+    }
+    if (c != 0)
+	return(1);
+    return(0);
+}
+
 /************************************************************************
  *									*
  *		Allocation and deallocation of basic structures		*
diff --git a/xmlreader.c b/xmlreader.c
index 94b564f..8764e95 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -2492,6 +2492,7 @@
  * @tolen:  the size of the output (in), the size written to (out)
  *
  * Base64 decoder, reads from @in and save in @to
+ * TODO: tell jody when this is actually exported
  *
  * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
  *         2 if there wasn't enough space on the output or -1 in case of error.
diff --git a/xmlschemastypes.c b/xmlschemastypes.c
index 374eddb..e19391f 100644
--- a/xmlschemastypes.c
+++ b/xmlschemastypes.c
@@ -1193,6 +1193,8 @@
 	    neg = 1;
 	    cur++;
 	}
+	if (cur[0] == 0)
+	    return(1);
 	if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) {
 	    cur += 3;
 	    if (*cur != 0)