adding repeated parsing and validating tests make the new DOM tree

* Makefile.am: adding repeated parsing and validating tests
* SAX2.c parser.c tree.c include/libxml/parser.h: make the new
  DOM tree building interfaces use the dictionary from the
  parsing context to build the element and attributes names
  as well as formatting spaces and short text nodes
* include/libxml/dict.h dict.c: added some reference counting
  for xmlDictPtr because they can be shared by documents and
  a parser context.
* xmlreader.c: a bit of cleanup, remove the specific tree freeing
  functions and use the standard ones now.
* xmllint.c: add --nodict
* python/libxml.c: fix a stupid bug so that ns() works on
  attribute nodes.
Daniel
diff --git a/ChangeLog b/ChangeLog
index 173a0c5..178fe83 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+Wed Sep 24 23:17:59 CEST 2003 Daniel Veillard <daniel@veillard.com>
+
+	* Makefile.am: adding repeated parsing and validating tests
+	* SAX2.c parser.c tree.c include/libxml/parser.h: make the new
+	  DOM tree building interfaces use the dictionary from the 
+	  parsing context to build the element and attributes names
+	  as well as formatting spaces and short text nodes
+	* include/libxml/dict.h dict.c: added some reference counting
+	  for xmlDictPtr because they can be shared by documents and
+	  a parser context.
+	* xmlreader.c: a bit of cleanup, remove the specific tree freeing
+	  functions and use the standard ones now.
+	* xmllint.c: add --nodict
+	* python/libxml.c: fix a stupid bug so that ns() works on 
+	  attribute nodes.
+
 Tue Sep 23 23:07:45 CEST 2003 Daniel Veillard <daniel@veillard.com>
 
 	* parser.c include/libxml/parser.h: adding a new set of
diff --git a/Makefile.am b/Makefile.am
index 84f5fe9..fd6fdf3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -724,8 +724,10 @@
 	@echo "##"
 	@echo "## Timing tests to try to detect performance"
 	@echo "## as well a memory usage breakage when streaming"
-	@echo "## first when using the file interface"
-	@echo "## then when using the memory interface"
+	@echo "## 1/ using the file interface"
+	@echo "## 2/ using the memory interface"
+	@echo "## 3/ repeated DOM parsing"
+	@echo "## 4/ repeated DOM validation"
 	@echo "##"
 	-@(xmllint --stream --timing $(srcdir)/dba100000.xml; \
 	   MEM=`cat .memdump | grep "MEMORY ALLOCATED" | awk '{ print $$7}'`;\
@@ -737,6 +739,16 @@
 	   if [ "$$MEM" != "" ] ; then echo Using $$MEM bytes ; fi ; \
 	   grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0";\
 	   exit 0)
+	-@(xmllint --noout --timing --repeat $(srcdir)/test/valid/REC-xml-19980210.xml; \
+	   MEM=`cat .memdump | grep "MEMORY ALLOCATED" | awk '{ print $$7}'`;\
+	   if [ "$$MEM" != "" ] ; then echo Using $$MEM bytes ; fi ; \
+	   grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0";\
+	   exit 0)
+	-@(xmllint --noout --timing --valid --repeat $(srcdir)/test/valid/REC-xml-19980210.xml; \
+	   MEM=`cat .memdump | grep "MEMORY ALLOCATED" | awk '{ print $$7}'`;\
+	   if [ "$$MEM" != "" ] ; then echo Using $$MEM bytes ; fi ; \
+	   grep "MORY ALLO" .memdump  | grep -v "MEMORY ALLOCATED : 0";\
+	   exit 0)
 
 C14Ntests : testC14N$(EXEEXT)
 	@echo "##"
diff --git a/SAX2.c b/SAX2.c
index d0c1854..f305158 100644
--- a/SAX2.c
+++ b/SAX2.c
@@ -802,6 +802,8 @@
 	    ctxt->disableSAX = 1;
 	    return;
 	}
+	if ((ctxt->dictNames) && (doc != NULL))
+	    doc->dict = ctxt->dict;
     }
     if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) &&
 	(ctxt->input != NULL) && (ctxt->input->filename != NULL)) {
@@ -1564,6 +1566,7 @@
     nodePop(ctxt);
 }
 
+int nb_interned = 0;
 /*
  * xmlSAX2TextNode:
  * @ctxt:  the parser context
@@ -1577,21 +1580,17 @@
 static xmlNodePtr
 xmlSAX2TextNode(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) {
     xmlNodePtr ret;
+    const xmlChar *intern = NULL;
 
+    /*
+     * Allocate
+     */
     if (ctxt->freeElems != NULL) {
 	ret = ctxt->freeElems;
 	ctxt->freeElems = ret->next;
 	ctxt->freeElemsNr--;
-	memset(ret, 0, sizeof(xmlNode));
-	ret->type = XML_TEXT_NODE;
-
-	ret->name = xmlStringText;
-	ret->content = xmlStrndup(str, len);
-
-	if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
-	    xmlRegisterNodeDefaultValue(ret);
     } else {
-	ret = xmlNewTextLen(str, len);
+	ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
     }
     if (ret == NULL) {
 	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
@@ -1602,6 +1601,36 @@
 	ctxt->disableSAX = 1;
 	return(NULL);
     }
+    /*
+     * intern the formatting blanks found between tags, or the
+     * very short strings
+     */
+    if (ctxt->dictNames) {
+        xmlChar cur = str[len];
+
+	if ((len <= 3) && ((cur == '"') || (cur == '\'') || (cur == '<'))) {
+	    intern = xmlDictLookup(ctxt->dict, str, len);
+	} else if (IS_BLANK(*str) && (len < 60) && (cur == '<')) {
+	    int i;
+
+	    for (i = 1;i < len;i++) {
+		if (!IS_BLANK(*str)) goto skip;
+	    }
+	    intern = xmlDictLookup(ctxt->dict, str, len);
+	}
+    }
+skip:
+    memset(ret, 0, sizeof(xmlNode));
+    ret->type = XML_TEXT_NODE;
+
+    ret->name = xmlStringText;
+    if (intern == NULL)
+	ret->content = xmlStrndup(str, len);
+    else
+	ret->content = (xmlChar *) intern;
+
+    if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))
+	xmlRegisterNodeDefaultValue(ret);
     return(ret);
 }
 
diff --git a/dict.c b/dict.c
index 93c8b8e..b56cef2 100644
--- a/dict.c
+++ b/dict.c
@@ -59,6 +59,8 @@
  * The entire dictionnary
  */
 struct _xmlDict {
+    int ref_counter;
+
     struct _xmlDictEntry *dict;
     int size;
     int nbElems;
@@ -277,6 +279,8 @@
   
     dict = xmlMalloc(sizeof(xmlDict));
     if (dict) {
+        dict->ref_counter = 1;
+
         dict->size = MIN_DICT_SIZE;
 	dict->nbElems = 0;
         dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry));
@@ -291,6 +295,21 @@
 }
 
 /**
+ * xmlDictReference:
+ * @dict: the dictionnary
+ *
+ * Increment the reference counter of a dictionary
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+int
+xmlDictReference(xmlDictPtr dict) {
+    if (dict == NULL) return -1;
+    dict->ref_counter++;
+    return(0);
+}
+
+/**
  * xmlDictGrow:
  * @dict: the dictionnary
  * @size: the new size of the dictionnary
@@ -401,6 +420,11 @@
 
     if (dict == NULL)
 	return;
+
+    /* decrement the counter, it may be shared by a parser and docs */
+    dict->ref_counter--;
+    if (dict->ref_counter > 0) return;
+
     if (dict->dict) {
 	for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) {
 	    iter = &(dict->dict[i]);
@@ -595,6 +619,7 @@
     }
     return(0);
 }
+
 /**
  * xmlDictSize:
  * @dict: the dictionnary
diff --git a/include/libxml/dict.h b/include/libxml/dict.h
index 56e8565..d04a973 100644
--- a/include/libxml/dict.h
+++ b/include/libxml/dict.h
@@ -37,6 +37,8 @@
  */
 XMLPUBFUN xmlDictPtr XMLCALL
 			xmlDictCreate	(void);
+XMLPUBFUN int XMLCALL
+			xmlDictReference(xmlDictPtr dict);
 XMLPUBFUN void XMLCALL			
 			xmlDictFree	(xmlDictPtr dict);
 
diff --git a/include/libxml/parser.h b/include/libxml/parser.h
index 4ddaa69..965fbc4 100644
--- a/include/libxml/parser.h
+++ b/include/libxml/parser.h
@@ -1044,7 +1044,8 @@
     XML_PARSE_NOBLANKS	= 1<<8,	/* remove blank nodes */
     XML_PARSE_SAX1	= 1<<9,	/* use the SAX1 interface internally */
     XML_PARSE_XINCLUDE	= 1<<10,/* Implement XInclude substitition  */
-    XML_PARSE_NONET	= 1<<11 /* Forbid network access */
+    XML_PARSE_NONET	= 1<<11,/* Forbid network access */
+    XML_PARSE_NODICT	= 1<<12 /* Do not reuse the context dictionnary */
 } xmlParserOption;
 
 XMLPUBFUN void XMLCALL
diff --git a/parser.c b/parser.c
index deace02..eb3a8a0 100644
--- a/parser.c
+++ b/parser.c
@@ -11926,6 +11926,18 @@
  ************************************************************************/
 
 /**
+ * DICT_FREE:
+ * @str:  a string
+ *
+ * Free a string if it is not owned by the "dict" dictionnary in the
+ * current scope
+ */
+#define DICT_FREE(str)						\
+	if ((str) && ((!dict) || 				\
+	    (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))	\
+	    xmlFree((char *)(str));
+
+/**
  * xmlCtxtReset:
  * @ctxt: an XML parser context
  *
@@ -11935,6 +11947,7 @@
 xmlCtxtReset(xmlParserCtxtPtr ctxt)
 {
     xmlParserInputPtr input;
+    xmlDictPtr dict = ctxt->dict;
 
     while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */
         xmlFreeInputStream(input);
@@ -11953,8 +11966,20 @@
     ctxt->nameNr = 0;
     ctxt->name = NULL;
 
+    DICT_FREE(ctxt->version);
     ctxt->version = NULL;
+    DICT_FREE(ctxt->encoding);
     ctxt->encoding = NULL;
+    DICT_FREE(ctxt->directory);
+    ctxt->directory = NULL;
+    DICT_FREE(ctxt->extSubURI);
+    ctxt->extSubURI = NULL;
+    DICT_FREE(ctxt->extSubSystem);
+    ctxt->extSubSystem = NULL;
+    if (ctxt->myDoc != NULL)
+        xmlFreeDoc(ctxt->myDoc);
+    ctxt->myDoc = NULL;
+
     ctxt->standalone = -1;
     ctxt->hasExternalSubset = 0;
     ctxt->hasPErefs = 0;
@@ -11962,9 +11987,7 @@
     ctxt->external = 0;
     ctxt->instate = XML_PARSER_START;
     ctxt->token = 0;
-    ctxt->directory = NULL;
 
-    ctxt->myDoc = NULL;
     ctxt->wellFormed = 1;
     ctxt->nsWellFormed = 1;
     ctxt->valid = 1;
@@ -12064,6 +12087,12 @@
         ctxt->sax->initialized = 1;
         options -= XML_PARSE_SAX1;
     }
+    if (options & XML_PARSE_NODICT) {
+        ctxt->dictNames = 0;
+        options -= XML_PARSE_NODICT;
+    } else {
+        ctxt->dictNames = 1;
+    }
     return (options);
 }
 
@@ -12096,11 +12125,25 @@
         ret = ctxt->myDoc;
     else {
         ret = NULL;
-        xmlFreeDoc(ctxt->myDoc);
-        ctxt->myDoc = NULL;
+	if (ctxt->myDoc != NULL) {
+	    ctxt->myDoc->dict = NULL;
+	    xmlFreeDoc(ctxt->myDoc);
+	}
     }
-    if (!reuse)
+    ctxt->myDoc = NULL;
+    if (!reuse) {
+        if ((ctxt->dictNames) &&
+	    (ret != NULL) &&
+	    (ret->dict == ctxt->dict))
+	    ctxt->dict = NULL;
 	xmlFreeParserCtxt(ctxt);
+    } else {
+        /* Must duplicate the reference to the dictionary */
+        if ((ctxt->dictNames) &&
+	    (ret != NULL) &&
+	    (ret->dict == ctxt->dict))
+	    xmlDictReference(ctxt->dict);
+    }
 
     return (ret);
 }
diff --git a/python/libxml.c b/python/libxml.c
index f323d81..cd71ff1 100644
--- a/python/libxml.c
+++ b/python/libxml.c
@@ -2288,7 +2288,9 @@
         return (NULL);
     node = (xmlNodePtr) PyxmlNode_Get(pyobj_node);
 
-    if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) {
+    if ((node == NULL) ||
+        ((node->type != XML_ELEMENT_NODE) &&
+	 (node->type != XML_ATTRIBUTE_NODE))) {
         Py_INCREF(Py_None);
         return (Py_None);
     }
diff --git a/tree.c b/tree.c
index 0fcfedf..4eed575 100644
--- a/tree.c
+++ b/tree.c
@@ -914,6 +914,18 @@
 }
 
 /**
+ * DICT_FREE:
+ * @str:  a string
+ *
+ * Free a string if it is not owned by the "dict" dictionnary in the
+ * current scope
+ */
+#define DICT_FREE(str)						\
+	if ((str) && ((!dict) || 				\
+	    (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))	\
+	    xmlFree((char *)(str));
+
+/**
  * xmlFreeDtd:
  * @cur:  the DTD structure to free up
  *
@@ -921,13 +933,12 @@
  */
 void
 xmlFreeDtd(xmlDtdPtr cur) {
+    xmlDictPtr dict = NULL;
+
     if (cur == NULL) {
-#ifdef DEBUG_TREE
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlFreeDtd : DTD == NULL\n");
-#endif
 	return;
     }
+    if (cur->doc != NULL) dict = cur->doc->dict;
 
     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
 	xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
@@ -948,9 +959,9 @@
 	    c = next;
 	}
     }
-    if (cur->name != NULL) xmlFree((char *) cur->name);
-    if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
-    if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
+    DICT_FREE(cur->name)
+    DICT_FREE(cur->SystemID)
+    DICT_FREE(cur->ExternalID)
     /* TODO !!! */
     if (cur->notations != NULL)
         xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
@@ -1019,6 +1030,7 @@
 void
 xmlFreeDoc(xmlDocPtr cur) {
     xmlDtdPtr extSubset, intSubset;
+    xmlDictPtr dict = NULL;
 
     if (cur == NULL) {
 #ifdef DEBUG_TREE
@@ -1027,6 +1039,7 @@
 #endif
 	return;
     }
+    if (cur != NULL) dict = cur->dict;
 
     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
 	xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
@@ -1054,13 +1067,14 @@
     }
 
     if (cur->children != NULL) xmlFreeNodeList(cur->children);
-
-    if (cur->version != NULL) xmlFree((char *) cur->version);
-    if (cur->name != NULL) xmlFree((char *) cur->name);
-    if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
     if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
-    if (cur->URL != NULL) xmlFree((char *) cur->URL);
+
+    DICT_FREE(cur->version)
+    DICT_FREE(cur->name)
+    DICT_FREE(cur->encoding)
+    DICT_FREE(cur->URL)
     xmlFree(cur);
+    if (dict) xmlDictFree(dict);
 }
 
 /**
@@ -1915,13 +1929,7 @@
 void
 xmlFreePropList(xmlAttrPtr cur) {
     xmlAttrPtr next;
-    if (cur == NULL) {
-#ifdef DEBUG_TREE
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlFreePropList : property == NULL\n");
-#endif
-	return;
-    }
+    if (cur == NULL) return;
     while (cur != NULL) {
         next = cur->next;
         xmlFreeProp(cur);
@@ -1937,13 +1945,10 @@
  */
 void
 xmlFreeProp(xmlAttrPtr cur) {
-    if (cur == NULL) {
-#ifdef DEBUG_TREE
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlFreeProp : property == NULL\n");
-#endif
-	return;
-    }
+    xmlDictPtr dict = NULL;
+    if (cur == NULL) return;
+
+    if (cur->doc != NULL) dict = cur->doc->dict;
 
     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
 	xmlDeregisterNodeDefaultValue((xmlNodePtr)cur);
@@ -1955,8 +1960,8 @@
         if (xmlIsID(cur->parent->doc, cur->parent, cur))
 	    xmlRemoveID(cur->parent->doc, cur);
     }
-    if (cur->name != NULL) xmlFree((char *) cur->name);
     if (cur->children != NULL) xmlFreeNodeList(cur->children);
+    DICT_FREE(cur->name)
     xmlFree(cur);
 }
 
@@ -3187,13 +3192,9 @@
 void
 xmlFreeNodeList(xmlNodePtr cur) {
     xmlNodePtr next;
-    if (cur == NULL) {
-#ifdef DEBUG_TREE
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlFreeNodeList : node == NULL\n");
-#endif
-	return;
-    }
+    xmlDictPtr dict = NULL;
+
+    if (cur == NULL) return;
     if (cur->type == XML_NAMESPACE_DECL) {
 	xmlFreeNsList((xmlNsPtr) cur);
 	return;
@@ -3206,9 +3207,9 @@
 	xmlFreeDoc((xmlDocPtr) cur);
 	return;
     }
+    if (cur->doc != NULL) dict = cur->doc->dict;
     while (cur != NULL) {
         next = cur->next;
-	/* unroll to speed up freeing the document */
 	if (cur->type != XML_DTD_NODE) {
 
 	    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
@@ -3226,7 +3227,7 @@
 		(cur->type != XML_XINCLUDE_START) &&
 		(cur->type != XML_XINCLUDE_END) &&
 		(cur->type != XML_ENTITY_REF_NODE)) {
-		if (cur->content != NULL) xmlFree(cur->content);
+		DICT_FREE(cur->content)
 	    }
 	    if (((cur->type == XML_ELEMENT_NODE) ||
 	         (cur->type == XML_XINCLUDE_START) ||
@@ -3237,28 +3238,13 @@
 	    /*
 	     * When a node is a text node or a comment, it uses a global static
 	     * variable for the name of the node.
-	     *
-	     * The xmlStrEqual comparisons need to be done when (happened with
-	     * XML::libXML and XML::libXSLT) the library is included twice
-	     * statically in the binary and a tree allocated by one occurrence
-	     * of the lib gets freed by the other occurrence, in this case
-	     * the string addresses compare are not sufficient.
+	     * Otherwise the node name might come from the document's
+	     * dictionnary
 	     */
 	    if ((cur->name != NULL) &&
-		(cur->name != xmlStringText) &&
-		(cur->name != xmlStringTextNoenc) &&
-		(cur->name != xmlStringComment)) {
-		if (cur->type == XML_TEXT_NODE) {
-		    if ((!xmlStrEqual(cur->name, xmlStringText)) &&
-			(!xmlStrEqual(cur->name, xmlStringTextNoenc)))
-			xmlFree((char *) cur->name);
-		} else if (cur->type == XML_COMMENT_NODE) {
-		    if (!xmlStrEqual(cur->name, xmlStringComment))
-			xmlFree((char *) cur->name);
-		} else
-		    xmlFree((char *) cur->name);
-	    }
-	    /* TODO : derecursivate this function */
+		(cur->type != XML_TEXT_NODE) &&
+		(cur->type != XML_COMMENT_NODE))
+		DICT_FREE(cur->name)
 	    xmlFree(cur);
 	}
 	cur = next;
@@ -3274,13 +3260,9 @@
  */
 void
 xmlFreeNode(xmlNodePtr cur) {
-    if (cur == NULL) {
-#ifdef DEBUG_TREE
-        xmlGenericError(xmlGenericErrorContext,
-		"xmlFreeNode : node == NULL\n");
-#endif
-	return;
-    }
+    xmlDictPtr dict = NULL;
+
+    if (cur == NULL) return;
 
     /* use xmlFreeDtd for DTD nodes */
     if (cur->type == XML_DTD_NODE) {
@@ -3299,6 +3281,8 @@
     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
 	xmlDeregisterNodeDefaultValue(cur);
 
+    if (cur->doc != NULL) dict = cur->doc->dict;
+
     if ((cur->children != NULL) &&
 	(cur->type != XML_ENTITY_REF_NODE))
 	xmlFreeNodeList(cur->children);
@@ -3312,33 +3296,18 @@
 	(cur->type != XML_ENTITY_REF_NODE) &&
 	(cur->type != XML_XINCLUDE_END) &&
 	(cur->type != XML_XINCLUDE_START)) {
-	xmlFree(cur->content);
+	DICT_FREE(cur->content)
     }
 
     /*
      * When a node is a text node or a comment, it uses a global static
      * variable for the name of the node.
-     *
-     * The xmlStrEqual comparisons need to be done when (happened with
-     * XML::libXML and XML::libXSLT) the library is included twice statically
-     * in the binary and a tree allocated by one occurence of the lib gets
-     * freed by the other occurrence, in this case the string addresses compare
-     * are not sufficient.
+     * Otherwise the node name might come from the document's dictionnary
      */
     if ((cur->name != NULL) &&
-	(cur->name != xmlStringText) &&
-	(cur->name != xmlStringTextNoenc) &&
-	(cur->name != xmlStringComment)) {
-	if (cur->type == XML_TEXT_NODE) {
-            if ((!xmlStrEqual(cur->name, xmlStringText)) &&
-		(!xmlStrEqual(cur->name, xmlStringTextNoenc)))
-		xmlFree((char *) cur->name);
-	} else if (cur->type == XML_COMMENT_NODE) {
-            if (!xmlStrEqual(cur->name, xmlStringComment))
-		xmlFree((char *) cur->name);
-	} else
-	    xmlFree((char *) cur->name);
-    }
+        (cur->type != XML_TEXT_NODE) &&
+        (cur->type != XML_COMMENT_NODE))
+	DICT_FREE(cur->name)
 
     if (((cur->type == XML_ELEMENT_NODE) ||
 	 (cur->type == XML_XINCLUDE_START) ||
diff --git a/xmllint.c b/xmllint.c
index 5f6893b..bdc198c 100644
--- a/xmllint.c
+++ b/xmllint.c
@@ -720,7 +720,7 @@
  * 			Tree Test processing				*
  * 									*
  ************************************************************************/
-static void parseAndPrintFile(char *filename) {
+static void parseAndPrintFile(char *filename, xmlParserCtxtPtr rectxt) {
     xmlDocPtr doc = NULL, tmp;
 
     if ((timing) && (!repeat))
@@ -811,17 +811,26 @@
 	        FILE *f;
 
 		f = fopen(filename, "r");
-		if (f != NULL)
-		    doc = xmlReadIO((xmlInputReadCallback) myRead,
-		                    (xmlInputCloseCallback) myClose, f,
-				    NULL, options);
-		else
+		if (f != NULL) {
+		    if (rectxt == NULL)
+			doc = xmlReadIO((xmlInputReadCallback) myRead,
+					(xmlInputCloseCallback) myClose, f,
+					NULL, options);
+		    else
+			doc = xmlCtxtReadIO(rectxt,
+			                (xmlInputReadCallback) myRead,
+					(xmlInputCloseCallback) myClose, f,
+					NULL, options);
+		} else
 		    doc = NULL;
 	    }
 	} else if (htmlout) {
 	    xmlParserCtxtPtr ctxt;
 
-	    ctxt = xmlNewParserCtxt();
+	    if (rectxt == NULL)
+		ctxt = xmlNewParserCtxt();
+	    else
+	        ctxt = rectxt;
 	    if (ctxt == NULL) {	      
 	        doc = NULL;
 	    } else {
@@ -832,7 +841,8 @@
 
 		doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
 
-	        xmlFreeParserCtxt(ctxt);
+		if (rectxt == NULL)
+		    xmlFreeParserCtxt(ctxt);
 	    }
 #ifdef HAVE_SYS_MMAN_H
 	} else if (memory) {
@@ -847,13 +857,21 @@
 	    if (base == (void *) MAP_FAILED)
 	        return;
 
-	    doc = xmlReadMemory((char *) base, info.st_size, NULL, options);
+	    if (rectxt == NULL)
+		doc = xmlReadMemory((char *) base, info.st_size, NULL, options);
+	    else
+		doc = xmlCtxtReadMemory(rectxt,
+			       (char *) base, info.st_size, NULL, options);
+	        
 	    munmap((char *) base, info.st_size);
 #endif
 	} else if (valid) {
-	    xmlParserCtxtPtr ctxt;
+	    xmlParserCtxtPtr ctxt = NULL;
 
-	    ctxt = xmlNewParserCtxt();
+	    if (rectxt == NULL)
+		ctxt = xmlNewParserCtxt();
+	    else
+	        ctxt = rectxt;
 	    if (ctxt == NULL) {	      
 	        doc = NULL;
 	    } else {
@@ -861,10 +879,14 @@
 
 		if (ctxt->valid == 0)
 		    progresult = 4;
-	        xmlFreeParserCtxt(ctxt);
+		if (rectxt == NULL)
+		    xmlFreeParserCtxt(ctxt);
 	    }
 	} else {
-	    doc = xmlReadFile(filename, NULL, options);
+	    if (rectxt != NULL)
+	        doc = xmlCtxtReadFile(rectxt, filename, NULL, options);
+	    else
+		doc = xmlReadFile(filename, NULL, options);
 	}
     }
 
@@ -1347,6 +1369,9 @@
 	         (!strcmp(argv[i], "--noent"))) {
 	    noent++;
 	    options |= XML_PARSE_NOENT;
+	} else if ((!strcmp(argv[i], "-nodict")) ||
+	         (!strcmp(argv[i], "--nodict"))) {
+	    options |= XML_PARSE_NODICT;
 	} else if ((!strcmp(argv[i], "-version")) ||
 	         (!strcmp(argv[i], "--version"))) {
 	    showVersion(argv[0]);
@@ -1660,16 +1685,24 @@
 	/* Remember file names.  "-" means stdin.  <sven@zen.org> */
 	if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) {
 	    if (repeat) {
-		for (acount = 0;acount < repeat;acount++)
+		xmlParserCtxtPtr ctxt = NULL;
+
+		for (acount = 0;acount < repeat;acount++) {
 		    if (stream != 0)
 			streamFile(argv[i]);
-		    else
-			parseAndPrintFile(argv[i]);
+		    else {
+		        if (ctxt == NULL)
+			    ctxt = xmlNewParserCtxt();
+			parseAndPrintFile(argv[i], ctxt);
+		    }
+		}
+		if (ctxt != NULL)
+		    xmlFreeParserCtxt(ctxt);
 	    } else {
 		if (stream != 0)
 		    streamFile(argv[i]);
 		else
-		    parseAndPrintFile(argv[i]);
+		    parseAndPrintFile(argv[i], NULL);
 	    }
 	    files ++;
 	    if ((timing) && (repeat)) {
@@ -1678,7 +1711,7 @@
 	}
     }
     if (generate) 
-	parseAndPrintFile(NULL);
+	parseAndPrintFile(NULL, NULL);
     if ((htmlout) && (!nowrap)) {
 	xmlGenericError(xmlGenericErrorContext, "</body></html>\n");
     }
diff --git a/xmlreader.c b/xmlreader.c
index 8109cf8..4c02a03 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -1246,7 +1246,7 @@
             (reader->node->prev->type != XML_DTD_NODE)) {
 	    xmlNodePtr tmp = reader->node->prev;
 	    xmlUnlinkNode(tmp);
-	    xmlTextReaderFreeNode(reader, tmp);
+	    xmlFreeNode(tmp);
 	}
 
 	goto node_found;
@@ -1279,7 +1279,7 @@
 	 */
 	if (oldnode->type != XML_DTD_NODE) {
 	    xmlUnlinkNode(oldnode);
-	    xmlTextReaderFreeNode(reader, oldnode);
+	    xmlFreeNode(oldnode);
 	}
 
 	goto node_end;
@@ -1677,16 +1677,17 @@
     }
 #endif
     if (reader->ctxt != NULL) {
-	if (reader->ctxt->myDoc != NULL) {
-	    xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
-	    reader->ctxt->myDoc = NULL;
-	}
 	if ((reader->ctxt->vctxt.vstateTab != NULL) &&
 	    (reader->ctxt->vctxt.vstateMax > 0)){
 	    xmlFree(reader->ctxt->vctxt.vstateTab);
 	    reader->ctxt->vctxt.vstateTab = 0;
 	    reader->ctxt->vctxt.vstateMax = 0;
 	}
+	if (reader->ctxt->myDoc != NULL) {
+	    xmlFreeDoc(reader->ctxt->myDoc);
+	    reader->ctxt->myDoc = NULL;
+	}
+	reader->ctxt->dict = NULL;
 	if (reader->allocs & XML_TEXTREADER_CTXT)
 	    xmlFreeParserCtxt(reader->ctxt);
     }