libxml now grok Docbook-3.1.5 and Docbook-4.1.1 DTDs, this
popped out a couple of bugs and 3 speed issues, there is only
on minor speed issue left. Assorted collection of user reported
bugs and fixes:
- doc/encoding.html: added encoding aliases doc
- doc/xml.html: updates
- encoding.[ch]: added EncodingAliases functions
- entities.[ch] valid.[ch] debugXML.c: removed two serious
  bottleneck affecting large DTDs like Docbook
- parser.[ch] xmllint.c: added a pedantic option, will be useful
- SAX.c: redefinition of entities is reported in pedantic mode
- testHTML.c: uninitialized warning from gcc
- uri.c: fixed a couple of bugs
- TODO: added issue raised by Michael
Daniel
diff --git a/valid.c b/valid.c
index 41c04d1..7aa76ab 100644
--- a/valid.c
+++ b/valid.c
@@ -463,6 +463,7 @@
     }
     ret->max_elements = XML_MIN_ELEMENT_TABLE;
     ret->nb_elements = 0;
+    ret->last = 0;
     ret->table = (xmlElementPtr *) 
          xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
     if (ret->table == NULL) {
@@ -978,6 +979,7 @@
  * @tree:  if it's an enumeration, the associated list
  *
  * Register a new attribute declaration
+ * Note that @tree becomes the ownership of the DTD
  *
  * Returns NULL if not new, othervise the attribute decl
  */
@@ -993,14 +995,17 @@
 
     if (dtd == NULL) {
         fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
+	xmlFreeEnumeration(tree);
 	return(NULL);
     }
     if (name == NULL) {
         fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
+	xmlFreeEnumeration(tree);
 	return(NULL);
     }
     if (elem == NULL) {
         fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
+	xmlFreeEnumeration(tree);
 	return(NULL);
     }
     /*
@@ -1029,6 +1034,7 @@
 	    break;
 	default:
 	    fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
+	    xmlFreeEnumeration(tree);
 	    return(NULL);
     }
     if ((defaultValue != NULL) && 
@@ -1054,19 +1060,59 @@
     /*
      * Validity Check:
      * Search the DTD for previous declarations of the ATTLIST
+     * The initial code used to walk the attribute table comparing
+     * all pairs of element/attribute names, and was far too slow
+     * for large DtDs, we now walk the attribute list associated to
+     * the element declaration instead if this declaration is found.
      */
-    for (i = 0;i < table->nb_attributes;i++) {
-        cur = table->table[i];
-	if ((ns != NULL) && (cur->prefix == NULL)) continue;
-	if ((ns == NULL) && (cur->prefix != NULL)) continue;
-	if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem)) &&
-	    ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
-	    /*
-	     * The attribute is already defined in this Dtd.
-	     */
-	    VWARNING(ctxt->userData, "Attribute %s on %s: already defined\n",
-		   elem, name);
-	    return(NULL);
+    elemDef = xmlGetDtdElementDesc(dtd, elem);
+    if (elemDef != NULL) {
+	/*
+	 * follow the attribute list.
+	 */
+	cur = elemDef->attributes;
+	while (cur != NULL) {
+	    if ((ns != NULL) && (cur->prefix == NULL)) {
+		cur = cur->nexth;
+		continue;
+	    }
+	    if ((ns == NULL) && (cur->prefix != NULL)) {
+		cur = cur->nexth;
+		continue;
+	    }
+	    if ((!xmlStrcmp(cur->name, name)) &&
+		((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
+		/*
+		 * The attribute is already defined in this Dtd.
+		 */
+		VWARNING(ctxt->userData,
+			 "Attribute %s on %s: already defined\n",
+		         name, elem);
+		xmlFreeEnumeration(tree);
+		return(NULL);
+	    }
+	    cur = cur->nexth;
+	}
+    } else {
+	/*
+	 * Walk down the attribute table.
+	 */
+	for (i = 0;i < table->nb_attributes;i++) {
+	    cur = table->table[i];
+	    if ((ns != NULL) && (cur->prefix == NULL)) continue;
+	    if ((ns == NULL) && (cur->prefix != NULL)) continue;
+	    if ((!xmlStrcmp(cur->name, name)) &&
+		(!xmlStrcmp(cur->elem, elem)) &&
+		((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
+		/*
+		 * The attribute is already defined in this Dtd.
+		 */
+		VWARNING(ctxt->userData,
+			 "Attribute %s on %s: already defined\n",
+		         elem, name);
+		xmlFreeEnumeration(tree);
+		return(NULL);
+	    }
 	}
     }
 
@@ -1106,7 +1152,6 @@
     ret->tree = tree;
     if (defaultValue != NULL)
 	ret->defaultValue = xmlStrdup(defaultValue);
-    elemDef = xmlGetDtdElementDesc(dtd, elem);
     if (elemDef != NULL) {
         if ((type == XML_ATTRIBUTE_ID) &&
 	    (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
@@ -2166,11 +2211,18 @@
     if (dtd->elements == NULL) return(NULL);
     table = (xmlElementTablePtr) dtd->elements;
 
-    for (i = 0;i < table->nb_elements;i++) {
-        cur = table->table[i];
+    if ((table->last >= 0) && (table->last < table->nb_elements)) {
+	cur = table->table[table->last];
 	if (!xmlStrcmp(cur->name, name))
 	    return(cur);
     }
+    for (i = 0;i < table->nb_elements;i++) {
+        cur = table->table[i];
+	if (!xmlStrcmp(cur->name, name)) {
+	    table->last = i;
+	    return(cur);
+	}
+    }
 
     /*
      * Specific case if name is a QName.