removed a warning more cleanup, added ENTITY and ENTITIES support

* tree.c: removed a warning
* xmlschemastypes.c: more cleanup, added ENTITY and ENTITIES
  support
* check-relaxng-test-suite.py check-xsddata-test-suite.py:
  cleanup/improvements of the regression tests batch
* test/relaxng/testsuite.xml: augmented libxml2 own testsuite
Daniel
diff --git a/ChangeLog b/ChangeLog
index dae25b8..2ffc24d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Tue Mar 18 17:50:31 CET 2003 Daniel Veillard <daniel@veillard.com>
+
+	* tree.c: removed a warning
+	* xmlschemastypes.c: more cleanup, added ENTITY and ENTITIES
+	  support
+	* check-relaxng-test-suite.py check-xsddata-test-suite.py:
+	  cleanup/improvements of the regression tests batch
+	* test/relaxng/testsuite.xml: augmented libxml2 own testsuite
+
 Tue Mar 18 12:36:22 CET 2003 Daniel Veillard <daniel@veillard.com>
 
 	* relaxng.c: fixed error msg cleanup deallocation
diff --git a/check-relaxng-test-suite.py b/check-relaxng-test-suite.py
index 6f65264..2e378f4 100755
--- a/check-relaxng-test-suite.py
+++ b/check-relaxng-test-suite.py
@@ -10,6 +10,7 @@
 # Memory debug specific
 libxml2.debugMemory(1)
 debug = 0
+verbose = 0
 
 #
 # the testsuite description
@@ -336,7 +337,7 @@
         handle_testSuite(test, level + 1)
 	        
 
-    if level >= 1 and sections != []:
+    if verbose and level >= 1 and sections != []:
         msg = ""
         for section in sections:
 	    msg = msg + section.content + " "
diff --git a/check-xsddata-test-suite.py b/check-xsddata-test-suite.py
index ffe944a..b22d1aa 100755
--- a/check-xsddata-test-suite.py
+++ b/check-xsddata-test-suite.py
@@ -10,12 +10,13 @@
 # Memory debug specific
 libxml2.debugMemory(1)
 debug = 0
+verbose = 1
 
 #
 # the testsuite description
 #
 CONF="test/xsdtest/xsdtestsuite.xml"
-LOG="check-xsdtype-test-suite.log"
+LOG="check-xsddata-test-suite.log"
 
 log = open(LOG, "w")
 nb_schemas_tests = 0
@@ -56,13 +57,16 @@
     global nb_instances_success
     global nb_instances_failed
 
-    instance = ""
+    instance = node.prop("dtd")
+    if instance == None:
+        instance = ""
     child = node.children
     while child != None:
         if child.type != 'text':
 	    instance = instance + child.serialize()
 	child = child.next
 
+    mem = libxml2.debugMemory(1);
     try:
 	doc = libxml2.parseDoc(instance)
     except:
@@ -75,11 +79,21 @@
 	nb_instances_failed = nb_instances_failed + 1
 	return
 
+    if debug:
+        print "instance line %d" % (node.lineNo())
+       
     try:
         ctxt = schema.relaxNGNewValidCtxt()
 	ret = doc.relaxNGValidateDoc(ctxt)
+	del ctxt
     except:
         ret = -1
+
+    doc.freeDoc()
+    if mem != libxml2.debugMemory(1):
+	print "validating instance %d line %d leaks" % (
+		  nb_instances_tests, node.lineNo())
+
     if ret != 0:
         log.write("\nFailed to validate correct instance:\n-----\n")
 	log.write(instance)
@@ -87,7 +101,6 @@
 	nb_instances_failed = nb_instances_failed + 1
     else:
 	nb_instances_success = nb_instances_success + 1
-    doc.freeDoc()
 
 #
 # handle an invalid instance
@@ -97,13 +110,17 @@
     global nb_instances_success
     global nb_instances_failed
 
-    instance = ""
+    instance = node.prop("dtd")
+    if instance == None:
+        instance = ""
     child = node.children
     while child != None:
         if child.type != 'text':
 	    instance = instance + child.serialize()
 	child = child.next
 
+    mem = libxml2.debugMemory(1);
+
     try:
 	doc = libxml2.parseDoc(instance)
     except:
@@ -115,11 +132,22 @@
         log.write("\n-----\n")
 	return
 
+    if debug:
+        print "instance line %d" % (node.lineNo())
+       
     try:
         ctxt = schema.relaxNGNewValidCtxt()
 	ret = doc.relaxNGValidateDoc(ctxt)
+	del ctxt
+
     except:
         ret = -1
+
+    doc.freeDoc()
+    if mem != libxml2.debugMemory(1):
+	print "validating instance %d line %d leaks" % (
+		  nb_instances_tests, node.lineNo())
+    
     if ret == 0:
         log.write("\nFailed to detect validation problem in instance:\n-----\n")
 	log.write(instance)
@@ -127,7 +155,6 @@
 	nb_instances_failed = nb_instances_failed + 1
     else:
 	nb_instances_success = nb_instances_success + 1
-    doc.freeDoc()
 
 #
 # handle an incorrect test
@@ -293,12 +320,13 @@
 def handle_testSuite(node, level = 0):
     global nb_schemas_tests, nb_schemas_success, nb_schemas_failed
     global nb_instances_tests, nb_instances_success, nb_instances_failed
-    old_schemas_tests = nb_schemas_tests
-    old_schemas_success = nb_schemas_success
-    old_schemas_failed = nb_schemas_failed
-    old_instances_tests = nb_instances_tests
-    old_instances_success = nb_instances_success
-    old_instances_failed = nb_instances_failed
+    if verbose and level >= 0:
+	old_schemas_tests = nb_schemas_tests
+	old_schemas_success = nb_schemas_success
+	old_schemas_failed = nb_schemas_failed
+	old_instances_tests = nb_instances_tests
+	old_instances_success = nb_instances_success
+	old_instances_failed = nb_instances_failed
 
     docs = node.xpathEval('documentation')
     authors = node.xpathEval('author')
@@ -311,27 +339,48 @@
 	    for author in authors:
 	        msg = msg + author.content + " "
 	print msg
+    sections = node.xpathEval('section')
+    if sections != [] and level <= 0:
+        msg = ""
+        for section in sections:
+	    msg = msg + section.content + " "
+        print "Tests for section %s" % (msg)
     for test in node.xpathEval('testCase'):
         handle_testCase(test)
     for test in node.xpathEval('testSuite'):
         handle_testSuite(test, level + 1)
 	        
-    print "Result of tests for %s" % (node.xpathEval('string(documentation)'))
-    if nb_schemas_tests != old_schemas_tests:
-	print "found %d test schemas: %d success %d failures" % (
-	      nb_schemas_tests - old_schemas_tests,
-	      nb_schemas_success - old_schemas_success,
-	      nb_schemas_failed - old_schemas_failed)
-    if nb_instances_tests != old_instances_tests:
-	print "found %d test instances: %d success %d failures" % (
-	      nb_instances_tests - old_instances_tests,
-	      nb_instances_success - old_instances_success,
-	      nb_instances_failed - old_instances_failed)
+
+    if verbose and level >= 0 and sections != []:
+        msg = ""
+        for section in sections:
+	    msg = msg + section.content + " "
+        print "Result of tests for section %s" % (msg)
+        if nb_schemas_tests != old_schemas_tests:
+	    print "found %d test schemas: %d success %d failures" % (
+		  nb_schemas_tests - old_schemas_tests,
+		  nb_schemas_success - old_schemas_success,
+		  nb_schemas_failed - old_schemas_failed)
+	if nb_instances_tests != old_instances_tests:
+	    print "found %d test instances: %d success %d failures" % (
+		  nb_instances_tests - old_instances_tests,
+		  nb_instances_success - old_instances_success,
+		  nb_instances_failed - old_instances_failed)
 #
 # Parse the conf file
 #
 libxml2.substituteEntitiesDefault(1);
 testsuite = libxml2.parseFile(CONF)
+
+#
+# Error and warnng callbacks
+#
+def callback(ctx, str):
+    global log
+    log.write("%s%s" % (ctx, str))
+
+libxml2.registerErrorHandler(callback, "")
+
 libxml2.setEntityLoader(resolver)
 root = testsuite.getRootElement()
 if root.name != 'testSuite':
diff --git a/test/relaxng/testsuite.xml b/test/relaxng/testsuite.xml
index d176f69..0c1b41e 100644
--- a/test/relaxng/testsuite.xml
+++ b/test/relaxng/testsuite.xml
@@ -1377,6 +1377,14 @@
 </valid>

 <valid>

 <top>

+  <xref link="  id1 "/>

+  <ref id="     id1   "/>

+  <xref link="id1 "/>

+  <xref link="  id1"/>

+</top>

+</valid>

+<valid>

+<top>

   <ref id="id1"/>

   <xref link="id1"/>

 </top>

@@ -1388,5 +1396,139 @@
 </top>

 </invalid>

 </testCase>

+<testCase>

+<correct>

+<element name="top" xmlns="http://relaxng.org/ns/structure/1.0"

+         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">

+  <zeroOrMore>

+    <choice>

+      <element name="ref">

+        <attribute name="id">

+	  <data type="ID"/>

+	</attribute>

+	<text/>

+      </element>

+      <element name="xref">

+        <attribute name="link">

+	  <data type="IDREFS"/>

+	</attribute>

+	<text/>

+      </element>

+    </choice>

+  </zeroOrMore>

+</element>

+</correct>

+<valid>

+<top>

+</top>

+</valid>

+<invalid>

+<top>

+  <xref link="id1"/>

+</top>

+</invalid>

+<valid>

+<top>

+  <ref id="id1"/>

+</top>

+</valid>

+<valid>

+<top>

+  <xref link="id1"/>

+  <ref id="id1"/>

+</top>

+</valid>

+<valid>

+<top>

+  <xref link="id1 id1"/>

+  <ref id="id1"/>

+</top>

+</valid>

+<valid>

+<top>

+  <ref id="id1"/>

+  <xref link="id1"/>

+</top>

+</valid>

+<valid>

+<top>

+  <ref id="id2"/>

+  <xref link="id1 id2"/>

+  <ref id="id1"/>

+</top>

+</valid>

+<valid>

+<top>

+  <ref id="id2"/>

+  <xref link=" id2    id1   id2 "/>

+  <ref id="id1"/>

+</top>

+</valid>

+<invalid>

+<top>

+  <ref id="id2"/>

+  <xref link="id1 id2"/>

+</top>

+</invalid>

+<invalid>

+<top>

+  <xref link="id1 id2"/>

+  <ref id="id1"/>

+</top>

+</invalid>

+<invalid>

+<top>

+  <ref id="id1"/>

+  <ref id="id1"/>

+</top>

+</invalid>

+</testCase>

+</testSuite>

+<testSuite>

+<documentation>Test of ENTITY/ENTITIES</documentation>

+<testCase>

+<correct>

+<element xmlns="http://relaxng.org/ns/structure/1.0" name="doc" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">

+  <data type="ENTITY"/>

+</element>

+</correct>

+<invalid>

+<doc></doc>

+</invalid>

+<invalid>

+<doc>foo</doc>

+</invalid>

+<valid dtd="&#10;&lt;!DOCTYPE doc [&#10;&lt;!ENTITY foo SYSTEM 'whatever' NDATA jpeg&gt;&#10;]&gt;">

+<doc>foo</doc>

+</valid>

+<valid dtd="&#10;&lt;!DOCTYPE doc [&#10;&lt;!ENTITY foo SYSTEM 'whatever' NDATA jpeg&gt;&#10;]&gt;">

+<doc>  foo </doc>

+</valid>

+<invalid dtd="&#10;&lt;!DOCTYPE doc [&#10;&lt;!ENTITY foo SYSTEM 'whatever' NDATA jpeg&gt;&#10;]&gt;">

+<doc>foo bar</doc>

+</invalid>

+</testCase>

+<testCase>

+<correct>

+<element xmlns="http://relaxng.org/ns/structure/1.0" name="doc" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">

+  <data type="ENTITIES"/>

+</element>

+</correct>

+<invalid>

+<doc></doc>

+</invalid>

+<invalid>

+<doc>foo</doc>

+</invalid>

+<valid dtd="&#10;&lt;!DOCTYPE doc [&#10;&lt;!ENTITY foo SYSTEM 'whatever' NDATA jpeg&gt; &#10;&lt;!ENTITY bar SYSTEM 'whatever' NDATA jpeg&gt; &#10;]&gt;">

+<doc> foo bar </doc>

+</valid>

+<valid dtd="&#10;&lt;!DOCTYPE doc [&#10;&lt;!ENTITY foo SYSTEM 'whatever' NDATA jpeg&gt; &#10;&lt;!ENTITY bar SYSTEM 'whatever' NDATA jpeg&gt; &#10;]&gt;">

+<doc> foo bar foo</doc>

+</valid>

+<invalid dtd="&#10;&lt;!DOCTYPE doc [&#10;&lt;!ENTITY foo SYSTEM 'whatever' NDATA jpeg&gt;]&gt;">

+<doc>foo bar</doc>

+</invalid>

+</testCase>

 </testSuite>

 </testSuite>

diff --git a/tree.c b/tree.c
index f6b928c..2186d51 100644
--- a/tree.c
+++ b/tree.c
@@ -6994,7 +6994,7 @@
 	return;
     }
     if (cur->type == XML_ATTRIBUTE_NODE) {
-	xmlAttrDumpOutput(buf,doc,cur,encoding);
+	xmlAttrDumpOutput(buf,doc, (xmlAttrPtr) cur,encoding);
 	return;
     }
     if (cur->type == XML_NAMESPACE_DECL) {
diff --git a/xmlschemastypes.c b/xmlschemastypes.c
index 0508699..254e88d 100644
--- a/xmlschemastypes.c
+++ b/xmlschemastypes.c
@@ -185,6 +185,8 @@
 static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL;
 static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL;
 static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL;
+static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL;
 static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL;
 static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL;
 
@@ -306,6 +308,10 @@
             XML_SCHEMAS_IDREF);
     xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS",
             XML_SCHEMAS_IDREFS);
+    xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY",
+            XML_SCHEMAS_ENTITY);
+    xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES",
+            XML_SCHEMAS_ENTITIES);
     xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name",
 	    XML_SCHEMAS_NAME);
     xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName",
@@ -1055,6 +1061,29 @@
     return 1;
 }
 
+/**
+ * xmlSchemaStrip:
+ * @value: a value
+ *
+ * Removes the leading and ending spaces of a string
+ *
+ * Returns the new string or NULL if no change was required.
+ */
+static xmlChar *
+xmlSchemaStrip(const xmlChar *value) {
+    const xmlChar *start = value, *end, *f;
+
+    if (value == NULL) return(NULL);
+    while ((*start != 0) && (IS_BLANK(*start))) start++;
+    end = start;
+    while (*end != 0) end++;
+    f = end;
+    end--;
+    while ((end > start) && (IS_BLANK(*end))) end--;
+    end++;
+    if ((start == value) && (f == end)) return(NULL);
+    return(xmlStrndup(start, end - start));
+}
 
 /**
  * xmlSchemaValAtomicListNode:
@@ -1066,8 +1095,8 @@
  * Check that a value conforms to the lexical space of the predefined
  * list type. if true a value is computed and returned in @ret.
  *
- * Returns 0 if this validates, a positive error code number otherwise
- *         and -1 in case of internal or API error.
+ * Returns the number of items if this validates, a negative error code
+ *         number otherwise
  */
 static int
 xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value,
@@ -1087,7 +1116,7 @@
     /*
      * Split the list
      */
-    while (IS_BLANK(*cur)) cur++;
+    while (IS_BLANK(*cur)) *cur++ = 0;
     while (*cur != 0) {
 	if (IS_BLANK(*cur)) {
 	    *cur = 0;
@@ -1104,7 +1133,7 @@
 	    TODO
 	}
 	xmlFree(val);
-	return(0);
+	return(nb_values);
     }
     endval = cur;
     cur = val;
@@ -1120,7 +1149,9 @@
     if (ret != NULL) {
 	TODO
     }
-    return(tmp);
+    if (tmp == 0)
+	return(nb_values);
+    return(-1);
 }
 
 /**
@@ -1156,9 +1187,17 @@
     } else if (type == xmlSchemaTypeAnySimpleTypeDef) {
 	return(0);
     } else if (type == xmlSchemaTypeNmtokenDef) {
-	if (xmlValidateNmtokenValue(value))
+	if (xmlValidateNMToken(value, 1) == 0)
 	    return(0);
 	return(1);
+    } else if (type == xmlSchemaTypeNmtokensDef) {
+	ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef,
+		                         value, val, node);
+	if (ret >= 0)
+	    ret = 0;
+	else
+	    ret = 1;
+	return(ret);
     } else if (type == xmlSchemaTypeDecimalDef) {
 	const xmlChar *cur = value, *tmp;
 	int frac = 0, len, neg = 0;
@@ -1487,14 +1526,24 @@
 	if ((ret == 0) && (node != NULL) &&
 	    (node->type == XML_ATTRIBUTE_NODE)) {
 	    xmlAttrPtr attr = (xmlAttrPtr) node;
+	    xmlChar *strip;
 
-	    xmlAddRef(NULL, node->doc, value, attr);
+	    strip = xmlSchemaStrip(value);
+	    if (strip != NULL) {
+		xmlAddRef(NULL, node->doc, strip, attr);
+		xmlFree(strip);
+	    } else
+		xmlAddRef(NULL, node->doc, value, attr);
 	    attr->atype = XML_ATTRIBUTE_IDREF;
 	}
 	return(ret);
     } else if (type == xmlSchemaTypeIdrefsDef) {
 	ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef,
 		                         value, val, node);
+	if (ret < 0)
+	    ret = 2;
+	else
+	    ret = 0;
 	if ((ret == 0) && (node != NULL) &&
 	    (node->type == XML_ATTRIBUTE_NODE)) {
 	    xmlAttrPtr attr = (xmlAttrPtr) node;
@@ -1511,8 +1560,14 @@
 	    (node->type == XML_ATTRIBUTE_NODE)) {
 	    xmlAttrPtr attr = (xmlAttrPtr) node;
 	    xmlIDPtr res;
+	    xmlChar *strip;
 
-	    res = xmlAddID(NULL, node->doc, value, attr);
+	    strip = xmlSchemaStrip(value);
+	    if (strip != NULL) {
+		res = xmlAddID(NULL, node->doc, strip, attr);
+		xmlFree(strip);
+	    } else
+		res = xmlAddID(NULL, node->doc, value, attr);
 	    if (res == NULL) {
 		ret = 2;
 	    } else {
@@ -1520,6 +1575,51 @@
 	    }
 	}
 	return(ret);
+    } else if (type == xmlSchemaTypeEntitiesDef) {
+	if ((node == NULL) || (node->doc == NULL))
+	    return(3);
+	ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef,
+		                         value, val, node);
+	if (ret <= 0)
+	    ret = 1;
+	else
+	    ret = 0;
+	if ((ret == 0) && (node != NULL) &&
+	    (node->type == XML_ATTRIBUTE_NODE)) {
+	    xmlAttrPtr attr = (xmlAttrPtr) node;
+
+	    attr->atype = XML_ATTRIBUTE_ENTITIES;
+	}
+	return(ret);
+    } else if (type == xmlSchemaTypeEntityDef) {
+	xmlChar *strip;
+	ret = xmlValidateNCName(value, 1);
+	if ((node == NULL) || (node->doc == NULL))
+	    ret = 3;
+	if (ret == 0) {
+	    xmlEntityPtr ent;
+
+	    strip = xmlSchemaStrip(value);
+	    if (strip != NULL) {
+		ent = xmlGetDocEntity(node->doc, strip);
+		xmlFree(strip);
+	    } else {
+		ent = xmlGetDocEntity(node->doc, value);
+	    }
+	    if ((ent == NULL) ||
+		(ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY))
+		ret = 4;
+	}
+	if ((ret == 0) && (val != NULL)) {
+	    TODO;
+	}
+	if ((ret == 0) && (node != NULL) &&
+	    (node->type == XML_ATTRIBUTE_NODE)) {
+	    xmlAttrPtr attr = (xmlAttrPtr) node;
+
+	    attr->atype = XML_ATTRIBUTE_ENTITY;
+	}
+	return(ret);
     } else {
 	TODO
 	return(0);