- xinclude.c: fixed XInclude recursive behaviour bug #54678
- result/XInclude/recursive.xml test/XInclude/docs/recursive.xml
  test/XInclude/ents/inc.txt test/XInclude/ents/sub-inc.ent:
  added specific regression test
- parser.h: preparing for the XSLT mode where DTD inherited
  attributes are added to the tree.
Daniel
diff --git a/ChangeLog b/ChangeLog
index 06e3f4b..559ce86 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Wed May 23 15:40:27 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
+
+	* xinclude.c: fixed XInclude recursive behaviour bug #54678
+	* result/XInclude/recursive.xml test/XInclude/docs/recursive.xml
+	  test/XInclude/ents/inc.txt test/XInclude/ents/sub-inc.ent:
+	  added specific regression test
+	* parser.h: preparing for the XSLT mode where DTD inherited
+	  attributes are added to the tree.
+
 Wed May 23 13:59:19 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
 	* xinclude.[ch]: Updated the namespace for the Last Call version
diff --git a/include/libxml/parser.h b/include/libxml/parser.h
index a8f0637..da404e7 100644
--- a/include/libxml/parser.h
+++ b/include/libxml/parser.h
@@ -111,6 +111,23 @@
 } xmlParserInputState;
 
 /**
+ * XML_DETECT_IDS:
+ *
+ * Bit in the loadsubset context field to tell to do ID/REFs lookups
+ * Use it to initialize xmlLoadExtDtdDefaultValue
+ */
+#define XML_DETECT_IDS		2
+
+/**
+ * XML_COMPLETE_ATTRS:
+ *
+ * Bit in the loadsubset context field to tell to do complete the
+ * elements attributes lists with the ones defaulted from the DTDs
+ * Use it to initialize xmlLoadExtDtdDefaultValue
+ */
+#define XML_COMPLETE_ATTRS	4
+
+/**
  * xmlParserCtxt:
  *
  * The parser context.
diff --git a/parser.h b/parser.h
index a8f0637..da404e7 100644
--- a/parser.h
+++ b/parser.h
@@ -111,6 +111,23 @@
 } xmlParserInputState;
 
 /**
+ * XML_DETECT_IDS:
+ *
+ * Bit in the loadsubset context field to tell to do ID/REFs lookups
+ * Use it to initialize xmlLoadExtDtdDefaultValue
+ */
+#define XML_DETECT_IDS		2
+
+/**
+ * XML_COMPLETE_ATTRS:
+ *
+ * Bit in the loadsubset context field to tell to do complete the
+ * elements attributes lists with the ones defaulted from the DTDs
+ * Use it to initialize xmlLoadExtDtdDefaultValue
+ */
+#define XML_COMPLETE_ATTRS	4
+
+/**
  * xmlParserCtxt:
  *
  * The parser context.
diff --git a/result/XInclude/recursive.xml b/result/XInclude/recursive.xml
new file mode 100644
index 0000000..df74d50
--- /dev/null
+++ b/result/XInclude/recursive.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0"?>
+<this><sub-inc>is a test
+</sub-inc></this>
diff --git a/test/XInclude/docs/recursive.xml b/test/XInclude/docs/recursive.xml
new file mode 100644
index 0000000..a9285ac
--- /dev/null
+++ b/test/XInclude/docs/recursive.xml
@@ -0,0 +1,3 @@
+<this><xinc:include href="../ents/sub-inc.ent" parse="xml" 
+         xmlns:xinc="http://www.w3.org/2001/XInclude"/></this>
+
diff --git a/test/XInclude/ents/inc.txt b/test/XInclude/ents/inc.txt
new file mode 100644
index 0000000..d5cdd7c
--- /dev/null
+++ b/test/XInclude/ents/inc.txt
@@ -0,0 +1 @@
+is a test
diff --git a/test/XInclude/ents/sub-inc.ent b/test/XInclude/ents/sub-inc.ent
new file mode 100644
index 0000000..7726c9d
--- /dev/null
+++ b/test/XInclude/ents/sub-inc.ent
@@ -0,0 +1,2 @@
+<sub-inc><xinc:include href="inc.txt" parse="text" 
+         xmlns:xinc="http://www.w3.org/2001/XInclude"/></sub-inc>
diff --git a/xinclude.c b/xinclude.c
index 36811de..3b31001 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -11,6 +11,7 @@
 
 /*
  * TODO: compute XPointers nodesets
+ * TODO: add an node intermediate API and handle recursion at this level
  */
 
 #include "libxml.h"
@@ -67,151 +68,8 @@
     xmlURL         *txturlTab; /* array of unparsed txtuments URLs */
 };
 
-/**
- * xmlXIncludeAddNode:
- * @ctxt:  the XInclude context
- * @node:  the new node
- * 
- * Add a new node to process to an XInclude context
- */
-static void
-xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
-    if (ctxt->incMax == 0) {
-	ctxt->incMax = 4;
-        ctxt->incTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
-		                          sizeof(ctxt->incTab[0]));
-        if (ctxt->incTab == NULL) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "malloc failed !\n");
-	    return;
-	}
-        ctxt->repTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
-		                          sizeof(ctxt->repTab[0]));
-        if (ctxt->repTab == NULL) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "malloc failed !\n");
-	    return;
-	}
-    }
-    if (ctxt->incNr >= ctxt->incMax) {
-	ctxt->incMax *= 2;
-        ctxt->incTab = (xmlNodePtr *) xmlRealloc(ctxt->incTab,
-	             ctxt->incMax * sizeof(ctxt->incTab[0]));
-        if (ctxt->incTab == NULL) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "realloc failed !\n");
-	    return;
-	}
-        ctxt->repTab = (xmlNodePtr *) xmlRealloc(ctxt->repTab,
-	             ctxt->incMax * sizeof(ctxt->repTab[0]));
-        if (ctxt->repTab == NULL) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "realloc failed !\n");
-	    return;
-	}
-    }
-    ctxt->incTab[ctxt->incNr] = node;
-    ctxt->repTab[ctxt->incNr] = NULL;
-    ctxt->incNr++;
-}
-
-/**
- * xmlXIncludeAddDoc:
- * @ctxt:  the XInclude context
- * @doc:  the new document
- * @url:  the associated URL
- * 
- * Add a new document to the list
- */
-static void
-xmlXIncludeAddDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const xmlURL url) {
-    if (ctxt->docMax == 0) {
-	ctxt->docMax = 4;
-        ctxt->docTab = (xmlDocPtr *) xmlMalloc(ctxt->docMax *
-		                          sizeof(ctxt->docTab[0]));
-        if (ctxt->docTab == NULL) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "malloc failed !\n");
-	    return;
-	}
-        ctxt->urlTab = (xmlURL *) xmlMalloc(ctxt->docMax *
-		                          sizeof(ctxt->urlTab[0]));
-        if (ctxt->urlTab == NULL) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "malloc failed !\n");
-	    return;
-	}
-    }
-    if (ctxt->docNr >= ctxt->docMax) {
-	ctxt->docMax *= 2;
-        ctxt->docTab = (xmlDocPtr *) xmlRealloc(ctxt->docTab,
-	             ctxt->docMax * sizeof(ctxt->docTab[0]));
-        if (ctxt->docTab == NULL) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "realloc failed !\n");
-	    return;
-	}
-        ctxt->urlTab = (xmlURL *) xmlRealloc(ctxt->urlTab,
-	             ctxt->docMax * sizeof(ctxt->urlTab[0]));
-        if (ctxt->urlTab == NULL) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "realloc failed !\n");
-	    return;
-	}
-    }
-    ctxt->docTab[ctxt->docNr] = doc;
-    ctxt->urlTab[ctxt->docNr] = xmlStrdup(url);
-    ctxt->docNr++;
-}
-
-/**
- * xmlXIncludeAddTxt:
- * @ctxt:  the XInclude context
- * @txt:  the new text node
- * @url:  the associated URL
- * 
- * Add a new txtument to the list
- */
-static void
-xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
-    if (ctxt->txtMax == 0) {
-	ctxt->txtMax = 4;
-        ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
-		                          sizeof(ctxt->txtTab[0]));
-        if (ctxt->txtTab == NULL) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "malloc failed !\n");
-	    return;
-	}
-        ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
-		                          sizeof(ctxt->txturlTab[0]));
-        if (ctxt->txturlTab == NULL) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "malloc failed !\n");
-	    return;
-	}
-    }
-    if (ctxt->txtNr >= ctxt->txtMax) {
-	ctxt->txtMax *= 2;
-        ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
-	             ctxt->txtMax * sizeof(ctxt->txtTab[0]));
-        if (ctxt->txtTab == NULL) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "realloc failed !\n");
-	    return;
-	}
-        ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
-	             ctxt->txtMax * sizeof(ctxt->urlTab[0]));
-        if (ctxt->txturlTab == NULL) {
-	    xmlGenericError(xmlGenericErrorContext,
-		    "realloc failed !\n");
-	    return;
-	}
-    }
-    ctxt->txtTab[ctxt->txtNr] = txt;
-    ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
-    ctxt->txtNr++;
-}
+static int
+xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc);
 
 /**
  * xmlXIncludeNewContext:
@@ -279,6 +137,196 @@
     xmlFree(ctxt);
 }
 
+/**
+ * xmlXIncludeAddNode:
+ * @ctxt:  the XInclude context
+ * @node:  the new node
+ * 
+ * Add a new node to process to an XInclude context
+ */
+static void
+xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
+    if (ctxt->incMax == 0) {
+	ctxt->incMax = 4;
+        ctxt->incTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
+		                          sizeof(ctxt->incTab[0]));
+        if (ctxt->incTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+        ctxt->repTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
+		                          sizeof(ctxt->repTab[0]));
+        if (ctxt->repTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+    }
+    if (ctxt->incNr >= ctxt->incMax) {
+	ctxt->incMax *= 2;
+        ctxt->incTab = (xmlNodePtr *) xmlRealloc(ctxt->incTab,
+	             ctxt->incMax * sizeof(ctxt->incTab[0]));
+        if (ctxt->incTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+        ctxt->repTab = (xmlNodePtr *) xmlRealloc(ctxt->repTab,
+	             ctxt->incMax * sizeof(ctxt->repTab[0]));
+        if (ctxt->repTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+    }
+    ctxt->incTab[ctxt->incNr] = node;
+    ctxt->repTab[ctxt->incNr] = NULL;
+    ctxt->incNr++;
+}
+
+/**
+ * xmlXIncludeAddDoc:
+ * @ctxt:  the XInclude context
+ * @doc:  the new document
+ * @url:  the associated URL
+ * 
+ * Add a new document to the list. The XInclude recursive nature is handled
+ * at this point.
+ */
+static void
+xmlXIncludeAddDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const xmlURL url) {
+    xmlXIncludeCtxtPtr newctxt;
+    int i;
+
+    if (ctxt->docMax == 0) {
+	ctxt->docMax = 4;
+        ctxt->docTab = (xmlDocPtr *) xmlMalloc(ctxt->docMax *
+		                          sizeof(ctxt->docTab[0]));
+        if (ctxt->docTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+        ctxt->urlTab = (xmlURL *) xmlMalloc(ctxt->docMax *
+		                          sizeof(ctxt->urlTab[0]));
+        if (ctxt->urlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+    }
+    if (ctxt->docNr >= ctxt->docMax) {
+	ctxt->docMax *= 2;
+        ctxt->docTab = (xmlDocPtr *) xmlRealloc(ctxt->docTab,
+	             ctxt->docMax * sizeof(ctxt->docTab[0]));
+        if (ctxt->docTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+        ctxt->urlTab = (xmlURL *) xmlRealloc(ctxt->urlTab,
+	             ctxt->docMax * sizeof(ctxt->urlTab[0]));
+        if (ctxt->urlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+    }
+    ctxt->docTab[ctxt->docNr] = doc;
+    ctxt->urlTab[ctxt->docNr] = xmlStrdup(url);
+    ctxt->docNr++;
+
+    /*
+     * Handle recursion here.
+     */
+
+    newctxt = xmlXIncludeNewContext(doc);
+    if (newctxt != NULL) {
+	/*
+	 * Copy the existing document set
+	 */
+	newctxt->docMax = ctxt->docMax;
+	newctxt->docNr = ctxt->docNr;
+        newctxt->docTab = (xmlDocPtr *) xmlMalloc(newctxt->docMax *
+		                          sizeof(newctxt->docTab[0]));
+        if (newctxt->docTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    xmlFree(newctxt);
+	    return;
+	}
+        newctxt->urlTab = (xmlURL *) xmlMalloc(newctxt->docMax *
+		                          sizeof(newctxt->urlTab[0]));
+        if (ctxt->urlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    xmlFree(newctxt);
+	    return;
+	}
+
+	for (i = 0;i < ctxt->docNr;i++) {
+	    newctxt->docTab[i] = ctxt->docTab[i];
+	    newctxt->urlTab[i] = ctxt->urlTab[i];
+	}
+	xmlXIncludeDoProcess(newctxt, doc);
+	for (i = 0;i < ctxt->docNr;i++) {
+	    newctxt->docTab[i] = NULL;
+	    newctxt->urlTab[i] = NULL;
+	}
+	xmlXIncludeFreeContext(newctxt);
+    }
+}
+
+/**
+ * xmlXIncludeAddTxt:
+ * @ctxt:  the XInclude context
+ * @txt:  the new text node
+ * @url:  the associated URL
+ * 
+ * Add a new txtument to the list
+ */
+static void
+xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
+    if (ctxt->txtMax == 0) {
+	ctxt->txtMax = 4;
+        ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
+		                          sizeof(ctxt->txtTab[0]));
+        if (ctxt->txtTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+        ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
+		                          sizeof(ctxt->txturlTab[0]));
+        if (ctxt->txturlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+    }
+    if (ctxt->txtNr >= ctxt->txtMax) {
+	ctxt->txtMax *= 2;
+        ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
+	             ctxt->txtMax * sizeof(ctxt->txtTab[0]));
+        if (ctxt->txtTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+        ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
+	             ctxt->txtMax * sizeof(ctxt->urlTab[0]));
+        if (ctxt->txturlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+    }
+    ctxt->txtTab[ctxt->txtNr] = txt;
+    ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
+    ctxt->txtNr++;
+}
+
 /************************************************************************
  *									*
  *			XInclude I/O handling				*
@@ -519,7 +567,8 @@
  * @ctxt: an XInclude context
  * @node: an XInclude node
  *
- * Implement the infoset replacement lookup on the XML element @node
+ * Implement the XInclude preprocessing, currently just adding the element
+ * for further processing.
  *
  * Returns the result list or NULL in case of error
  */
@@ -722,7 +771,8 @@
 }
 
 /**
- * xmlXIncludeProcess:
+ * xmlXIncludeDoProcess:
+ * @ctxt: 
  * @doc: an XML document
  *
  * Implement the XInclude substitution on the XML document @doc
@@ -730,16 +780,14 @@
  * Returns 0 if no substition were done, -1 if some processing failed
  *    or the number of substitutions done.
  */
-int
-xmlXIncludeProcess(xmlDocPtr doc) {
-    xmlXIncludeCtxtPtr ctxt;
+static int
+xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
     xmlNodePtr cur;
     int ret = 0;
     int i;
 
     if (doc == NULL)
 	return(-1);
-    ctxt = xmlXIncludeNewContext(doc);
     if (ctxt == NULL)
 	return(-1);
 
@@ -788,9 +836,30 @@
 	xmlXIncludeIncludeNode(ctxt, i);
     }
 
-    /*
-     * Cleanup
-     */
+    return(ret);
+}
+
+/**
+ * xmlXIncludeProcess:
+ * @doc: an XML document
+ *
+ * Implement the XInclude substitution on the XML document @doc
+ *
+ * Returns 0 if no substition were done, -1 if some processing failed
+ *    or the number of substitutions done.
+ */
+int
+xmlXIncludeProcess(xmlDocPtr doc) {
+    xmlXIncludeCtxtPtr ctxt;
+    int ret = 0;
+
+    if (doc == NULL)
+	return(-1);
+    ctxt = xmlXIncludeNewContext(doc);
+    if (ctxt == NULL)
+	return(-1);
+    ret = xmlXIncludeDoProcess(ctxt, doc);
+
     xmlXIncludeFreeContext(ctxt);
     return(ret);
 }