Speed, conformance testing, more parsing, general improvements, Daniel.
diff --git a/tree.c b/tree.c
index e1dbd29..4d643d8 100644
--- a/tree.c
+++ b/tree.c
@@ -3,9 +3,9 @@
  *
  * See Copyright for the status of this software.
  *
- * $Id$
- *
  * TODO Cleanup the Dump mechanism.
+ *
+ * Daniel.Veillard@w3.org
  */
 
 #include "config.h"
@@ -27,6 +27,15 @@
 
 static int xmlCompressMode = 0;
 
+#define UPDATE_LAST_CHILD(n) if ((n) != NULL) {				\
+    xmlNodePtr ulccur = (n)->childs;					\
+    if (ulccur == NULL) {						\
+        (n)->last = NULL;						\
+    } else {								\
+        while (ulccur->next != NULL) ulccur = ulccur->next;		\
+	(n)->last = ulccur;						\
+}   }
+
 /************************************************************************
  *									*
  *		Allocation and deallocation of basic structures		*
@@ -234,9 +243,10 @@
                     const CHAR *ExternalID, const CHAR *SystemID) {
     xmlDtdPtr cur;
 
-    if ((doc != NULL) && (doc->dtd != NULL)) {
+    if ((doc != NULL) && (doc->extSubset != NULL)) {
         fprintf(stderr, "xmlNewDtd(%s): document %s already have a DTD %s\n",
-	/* !!! */ (char *) name, doc->name, /* !!! */ (char *)doc->dtd->name);
+	    /* !!! */ (char *) name, doc->name,
+	    /* !!! */ (char *)doc->extSubset->name);
     }
 
     /*
@@ -263,7 +273,58 @@
     cur->elements = NULL;
     cur->entities = NULL;
     if (doc != NULL)
-	doc->dtd = cur;
+	doc->extSubset = cur;
+
+    return(cur);
+}
+
+/**
+ * xmlCreateIntSubset:
+ * @doc:  the document pointer
+ * @name:  the DTD name
+ * @ExternalID:  the external ID
+ * @SystemID:  the system ID
+ *
+ * Creatte the internal subset of a document
+ * return values: a pointer to the new DTD structure
+ */
+xmlDtdPtr
+xmlCreateIntSubset(xmlDocPtr doc, const CHAR *name,
+                   const CHAR *ExternalID, const CHAR *SystemID) {
+    xmlDtdPtr cur;
+
+    if ((doc != NULL) && (doc->intSubset != NULL)) {
+        fprintf(stderr, 
+     "xmlCreateIntSubset(): document %s already have an internal subset\n",
+	    doc->name);
+	return(NULL);
+    }
+
+    /*
+     * Allocate a new DTD and fill the fields.
+     */
+    cur = (xmlDtdPtr) malloc(sizeof(xmlDtd));
+    if (cur == NULL) {
+        fprintf(stderr, "xmlNewDtd : malloc failed\n");
+	return(NULL);
+    }
+
+    if (name != NULL)
+	cur->name = xmlStrdup(name); 
+    else
+        cur->name = NULL;
+    if (ExternalID != NULL)
+	cur->ExternalID = xmlStrdup(ExternalID); 
+    else
+        cur->ExternalID = NULL;
+    if (SystemID != NULL)
+	cur->SystemID = xmlStrdup(SystemID); 
+    else
+        cur->SystemID = NULL;
+    cur->elements = NULL;
+    cur->entities = NULL;
+    if (doc != NULL)
+	doc->intSubset = cur;
 
     return(cur);
 }
@@ -319,10 +380,10 @@
     cur->version = xmlStrdup(version); 
     cur->name = NULL;
     cur->root = NULL; 
-    cur->dtd = NULL;
+    cur->intSubset = NULL;
+    cur->extSubset = NULL;
     cur->oldNs = NULL;
     cur->encoding = NULL;
-    cur->entities = NULL;
     cur->standalone = -1;
     cur->compression = xmlCompressMode;
 #ifndef WITHOUT_CORBA
@@ -342,17 +403,18 @@
 void
 xmlFreeDoc(xmlDocPtr cur) {
     if (cur == NULL) {
+#ifdef DEBUG_TREE
         fprintf(stderr, "xmlFreeDoc : document == NULL\n");
+#endif
 	return;
     }
     free((char *) cur->version);
     if (cur->name != NULL) free((char *) cur->name);
     if (cur->encoding != NULL) free((char *) cur->encoding);
     if (cur->root != NULL) xmlFreeNode(cur->root);
-    if (cur->dtd != NULL) xmlFreeDtd(cur->dtd);
+    if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
+    if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
     if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
-    if (cur->entities != NULL)
-        xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
     memset(cur, -1, sizeof(xmlDoc));
     free(cur);
 }
@@ -803,6 +865,7 @@
     cur->next = NULL;
     cur->prev = NULL;
     cur->childs = NULL;
+    cur->last = NULL;
     cur->properties = NULL;
     cur->name = xmlStrdup(name);
     cur->ns = ns;
@@ -834,8 +897,10 @@
     cur = xmlNewNode(ns, name);
     if (cur != NULL) {
         cur->doc = doc;
-	if (content != NULL)
+	if (content != NULL) {
 	    cur->childs = xmlStringGetNodeList(doc, content);
+	    UPDATE_LAST_CHILD(cur);
+	}
     }
     return(cur);
 }
@@ -867,6 +932,7 @@
     cur->next = NULL; 
     cur->prev = NULL; 
     cur->childs = NULL; 
+    cur->last = NULL; 
     cur->properties = NULL; 
     cur->type = XML_TEXT_NODE;
     cur->name = xmlStrdup(xmlStringText);
@@ -907,6 +973,7 @@
     cur->next = NULL; 
     cur->prev = NULL; 
     cur->childs = NULL; 
+    cur->last = NULL; 
     cur->properties = NULL; 
     if (name[0] == '&') {
         int len;
@@ -973,6 +1040,7 @@
     cur->prev = NULL; 
     cur->next = NULL; 
     cur->childs = NULL; 
+    cur->last = NULL; 
     cur->properties = NULL; 
     cur->type = XML_TEXT_NODE;
     cur->name = xmlStrdup(xmlStringText);
@@ -1030,6 +1098,7 @@
     cur->prev = NULL; 
     cur->next = NULL; 
     cur->childs = NULL; 
+    cur->last = NULL; 
     cur->properties = NULL; 
     cur->type = XML_COMMENT_NODE;
     cur->name = xmlStrdup(xmlStringText);
@@ -1104,11 +1173,12 @@
     cur->doc = parent->doc;
     if (parent->childs == NULL) {
         parent->childs = cur;
+	parent->last = cur;
     } else {
-        prev = parent->childs;
-	while (prev->next != NULL) prev = prev->next;
+        prev = parent->last;
 	prev->next = cur;
 	cur->prev = prev;
+	parent->last = cur;
     }
 
     return(cur);
@@ -1146,6 +1216,7 @@
      */
     cur->parent = parent;
     cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
+
     /*
      * Handle the case where parent->content != NULL, in that case it will
      * create a intermediate TEXT node.
@@ -1159,17 +1230,19 @@
 	    if (text->next != NULL)
 		text->next->prev = text;
 	    parent->childs = text;
+	    UPDATE_LAST_CHILD(parent);
 	    free(parent->content);
 	    parent->content = NULL;
 	}
     }
     if (parent->childs == NULL) {
         parent->childs = cur;
+	parent->last = cur;
     } else {
-        prev = parent->childs;
-	while (prev->next != NULL) prev = prev->next;
+        prev = parent->last;
 	prev->next = cur;
 	cur->prev = prev;
+	parent->last = cur;
     }
 
     return(cur);
@@ -1184,23 +1257,11 @@
  */
 xmlNodePtr
 xmlGetLastChild(xmlNodePtr parent) {
-    xmlNodePtr last;
-
     if (parent == NULL) {
         fprintf(stderr, "xmlGetLastChild : parent == NULL\n");
 	return(NULL);
     }
-
-    /*
-     * add the new element at the end of the childs list.
-     */
-    if (parent->childs == NULL) {
-        return(NULL);
-    } else {
-        last = parent->childs;
-	while (last->next != NULL) last = last->next;
-    }
-    return(last);
+    return(parent->last);
 }
 
 /**
@@ -1264,6 +1325,8 @@
     }
     if ((cur->parent != NULL) && (cur->parent->childs == cur))
         cur->parent->childs = cur->next;
+    if ((cur->parent != NULL) && (cur->parent->last == cur))
+        cur->parent->last = cur->prev;
     if (cur->next != NULL)
         cur->next->prev = cur->prev;
     if (cur->prev != NULL)
@@ -1419,6 +1482,7 @@
     ret->next = NULL;
     ret->prev = NULL;
     ret->childs = NULL;
+    ret->last = NULL;
     ret->properties = NULL;
     if (node->name != NULL)
 	ret->name = xmlStrdup(node->name);
@@ -1469,6 +1533,7 @@
     }
     if (node->childs != NULL)
         ret->childs = xmlStaticCopyNodeList(node->childs, doc, ret);
+    UPDATE_LAST_CHILD(ret);
     return(ret);
 }
 
@@ -1601,11 +1666,8 @@
     ret->standalone = doc->standalone;
     if (!recursive) return(ret);
 
-    if (doc->dtd != NULL)
-        ret->dtd = xmlCopyDtd(doc->dtd);
-    if (doc->entities != NULL)
-        ret->entities = (void *) xmlCopyEntitiesTable(
-	                    (xmlEntitiesTablePtr) doc->entities);
+    if (doc->intSubset != NULL)
+        ret->intSubset = xmlCopyDtd(doc->intSubset);
     if (doc->oldNs != NULL)
         ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
     if (doc->root != NULL)
@@ -1677,6 +1739,7 @@
 	    }
 	    if (cur->childs != NULL) xmlFreeNode(cur->childs);
 	    cur->childs = xmlStringGetNodeList(cur->doc, content);
+	    UPDATE_LAST_CHILD(cur);
 	    break;
         case XML_ATTRIBUTE_NODE:
 	    break;
@@ -1688,6 +1751,7 @@
         case XML_COMMENT_NODE:
 	    if (cur->content != NULL) free(cur->content);
 	    if (cur->childs != NULL) xmlFreeNode(cur->childs);
+	    cur->last = cur->childs = NULL;
 	    if (content != NULL)
 		cur->content = xmlStrdup(content);
 	    else 
@@ -1723,6 +1787,7 @@
 	    }
 	    if (cur->childs != NULL) xmlFreeNode(cur->childs);
 	    cur->childs = xmlStringLenGetNodeList(cur->doc, content, len);
+	    UPDATE_LAST_CHILD(cur);
 	    break;
         case XML_ATTRIBUTE_NODE:
 	    break;
@@ -1734,6 +1799,7 @@
         case XML_COMMENT_NODE:
 	    if (cur->content != NULL) free(cur->content);
 	    if (cur->childs != NULL) xmlFreeNode(cur->childs);
+	    cur->childs = cur->last = NULL;
 	    if (content != NULL)
 		cur->content = xmlStrndup(content, len);
 	    else 
@@ -1743,6 +1809,8 @@
 	    break;
         case XML_NOTATION_NODE:
 	    if (cur->content != NULL) free(cur->content);
+	    if (cur->childs != NULL) xmlFreeNode(cur->childs);
+	    cur->childs = cur->last = NULL;
 	    if (content != NULL)
 		cur->content = xmlStrndup(content, len);
 	    else 
@@ -1772,24 +1840,22 @@
 	    xmlNodePtr last = NULL, new;
 
 	    if (cur->childs != NULL) {
-		last = cur->childs;
-		while (last->next != NULL) last = last->next;
+		last = cur->last;
 	    } else {
 	        if (cur->content != NULL) {
 		    cur->childs = xmlStringGetNodeList(cur->doc, cur->content);
+		    UPDATE_LAST_CHILD(cur);
 		    free(cur->content);
 		    cur->content = NULL;
-		    if (cur->childs != NULL) {
-			last = cur->childs;
-			while (last->next != NULL) last = last->next;
-                    }
+		    last = cur->last;
 		}
 	    }
-	    new = xmlStringLenGetNodeList(cur->doc, content, len);
+	    new = xmlNewTextLen(content, len);
 	    if (new != NULL) {
 		xmlAddChild(cur, new);
-	        if ((last != NULL) && (last->next == new))
+	        if ((last != NULL) && (last->next == new)) {
 		    xmlTextMerge(last, new);
+		}
 	    }
 	    break;
 	}
@@ -1936,19 +2002,14 @@
  *
  * Search and get the value of an attribute associated to a node
  * This does the entity substitution.
- *
  * return values: the attribute value or NULL if not found.
  */
-const CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
+CHAR *xmlGetProp(xmlNodePtr node, const CHAR *name) {
     xmlAttrPtr prop = node->properties;
 
     while (prop != NULL) {
-        if (!xmlStrcmp(prop->name, name)) {
-	    if (prop->val != NULL)
-		return(xmlNodeListGetString(node->doc, prop->val, 1));
-	    else
-	        return(xmlStrndup("", 1));
-	}
+        if (!xmlStrcmp(prop->name, name)) 
+	    return(xmlNodeListGetString(node->doc, prop->val, 1));
 	prop = prop->next;
     }
     return(NULL);
@@ -2188,10 +2249,10 @@
  */
 static void
 xmlDtdDump(xmlDocPtr doc) {
-    xmlDtdPtr cur = doc->dtd;
+    xmlDtdPtr cur = doc->intSubset;
 
     if (cur == NULL) {
-        fprintf(stderr, "xmlDtdDump : DTD == NULL\n");
+        fprintf(stderr, "xmlDtdDump : no internal subset\n");
 	return;
     }
     xmlBufferWriteChar("<!DOCTYPE ");
@@ -2207,15 +2268,13 @@
 	xmlBufferWriteCHAR(cur->SystemID);
 	xmlBufferWriteChar("\"");
     }
-    if ((cur->entities == NULL) && (doc->entities == NULL)) {
+    if (cur->entities == NULL) {
 	xmlBufferWriteChar(">\n");
 	return;
     }
     xmlBufferWriteChar(" [\n");
     if (cur->entities != NULL)
 	xmlDumpEntitiesTable((xmlEntitiesTablePtr) cur->entities);
-    if (doc->entities != NULL)
-	xmlDumpEntitiesTable((xmlEntitiesTablePtr) doc->entities);
     xmlBufferWriteChar("]");
 
     /* TODO !!! a lot more things to dump ... */
@@ -2239,13 +2298,13 @@
     }
     xmlBufferWriteChar(" ");
     xmlBufferWriteCHAR(cur->name);
-    xmlBufferWriteChar("=\"");
     value = xmlNodeListGetString(doc, cur->val, 0);
     if (value) {
+	xmlBufferWriteChar("=\"");
 	xmlBufferWriteCHAR(value);
+	xmlBufferWriteChar("\"");
 	free(value);
     }
-    xmlBufferWriteChar("\"");
 }
 
 /**
@@ -2401,7 +2460,7 @@
 	    break;
     }
     xmlBufferWriteChar("?>\n");
-    if ((cur->dtd != NULL) || (cur->entities != NULL))
+    if (cur->intSubset != NULL)
         xmlDtdDump(cur);
     if (cur->root != NULL) {
 	/* global namespace definitions, the old way */
@@ -2425,7 +2484,9 @@
 void
 xmlDocDumpMemory(xmlDocPtr cur, CHAR**mem, int *size) {
     if (cur == NULL) {
-        fprintf(stderr, "xmlDocDump : document == NULL\n");
+#ifdef DEBUG_TREE
+        fprintf(stderr, "xmlDocDumpMemory : document == NULL\n");
+#endif
 	*mem = NULL;
 	*size = 0;
 	return;
@@ -2501,7 +2562,9 @@
 void
 xmlDocDump(FILE *f, xmlDocPtr cur) {
     if (cur == NULL) {
+#ifdef DEBUG_TREE
         fprintf(stderr, "xmlDocDump : document == NULL\n");
+#endif
 	return;
     }
     buffer_index = 0;