added support and APIs needed for the catalog PI cleanup Daniel

* include/libxml/catalog.h include/libxml/parser.h
  include/libxml/xmlerror.h catalog.c parser.c parserInternals.c
  xmlIO.c: added support and APIs needed for the catalog PI
* include/libxml/xmlIO.h: cleanup
Daniel
diff --git a/ChangeLog b/ChangeLog
index 01b5081..cbc24aa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Wed Aug 22 16:27:03 CEST 2001 Daniel Veillard <daniel@veillard.com>
+
+	* include/libxml/catalog.h include/libxml/parser.h
+	  include/libxml/xmlerror.h catalog.c parser.c parserInternals.c
+	  xmlIO.c: added support and APIs needed for the catalog PI
+	* include/libxml/xmlIO.h: cleanup
+
 Wed Aug 22 02:03:31 CEST 2001 Daniel Veillard <daniel@veillard.com>
 
 	* catalog.c parser.c xmlIO.c xmlcatalog.c xmllint.c 
diff --git a/catalog.c b/catalog.c
index 2ea69db..06b2b53 100644
--- a/catalog.c
+++ b/catalog.c
@@ -93,10 +93,11 @@
     xmlCatalogPrefer prefer;
 };
 
+static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL;
+static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_SYSTEM;
 static xmlHashTablePtr xmlDefaultCatalog;
 static xmlCatalogEntryPtr xmlDefaultXMLCatalogList = NULL;
 static int xmlCatalogInitialized = 0;
-static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_SYSTEM;
 
 
 /* Catalog stack */
@@ -1562,7 +1563,17 @@
  */
 static const xmlChar *
 xmlCatalogSGMLResolve(const xmlChar *pubID, const xmlChar *sysID) {
-    TODO
+    const xmlChar *ret = NULL;
+
+    if (xmlDefaultCatalog == NULL)
+	return(NULL);
+
+    if (pubID != NULL)
+	ret = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
+    if (ret != NULL)
+	return(ret);
+    if (sysID != NULL)
+	ret = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
     return(NULL);
 }
 
@@ -2011,11 +2022,58 @@
 }
 
 /**
+ * xmlCatalogGetDefaults:
+ *
+ * Used to get the user preference w.r.t. to what catalogs should
+ * be accepted
+ *
+ * Returns the current xmlCatalogAllow value
+ */
+xmlCatalogAllow
+xmlCatalogGetDefaults(void) {
+    return(xmlCatalogDefaultAllow);
+}
+
+/**
+ * xmlCatalogSetDefaults:
+ *
+ * Used to set the user preference w.r.t. to what catalogs should
+ * be accepted
+ */
+void
+xmlCatalogSetDefaults(xmlCatalogAllow allow) {
+    if (!xmlCatalogInitialized)
+	xmlInitializeCatalog();
+    if (xmlDebugCatalogs) {
+	switch (allow) {
+	    case XML_CATA_ALLOW_NONE:
+		xmlGenericError(xmlGenericErrorContext,
+			"Disabling catalog usage\n");
+		break;
+	    case XML_CATA_ALLOW_GLOBAL:
+		xmlGenericError(xmlGenericErrorContext,
+			"Allowing only global catalogs\n");
+		break;
+	    case XML_CATA_ALLOW_DOCUMENT:
+		xmlGenericError(xmlGenericErrorContext,
+			"Allowing only catalogs from the document\n");
+		break;
+	    case XML_CATA_ALLOW_ALL:
+		xmlGenericError(xmlGenericErrorContext,
+			"Allowing all catalogs\n");
+		break;
+	}
+    }
+    xmlCatalogDefaultAllow = allow;
+}
+
+/**
  * xmlCatalogSetDefaultPrefer:
  * @prefer:  the default preference for delegation
  *
  * Allows to set the preference between public and system for deletion
  * in XML Catalog resolution. C.f. section 4.1.1 of the spec
+ * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM
  *
  * Returns the previous value of the default preference for delegation
  */
@@ -2023,6 +2081,25 @@
 xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
     xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
 
+    if (!xmlCatalogInitialized)
+	xmlInitializeCatalog();
+    if (prefer == XML_CATA_PREFER_NONE)
+	return(ret);
+
+    if (xmlDebugCatalogs) {
+	switch (prefer) {
+	    case XML_CATA_PREFER_PUBLIC:
+		xmlGenericError(xmlGenericErrorContext,
+			"Setting catalog preference to PUBLIC\n");
+		break;
+	    case XML_CATA_PREFER_SYSTEM:
+		xmlGenericError(xmlGenericErrorContext,
+			"Setting catalog preference to SYSTEM\n");
+		break;
+	    case XML_CATA_PREFER_NONE:
+		break;
+	}
+    }
     xmlCatalogDefaultPrefer = prefer;
     return(ret);
 }
@@ -2046,4 +2123,83 @@
 	xmlDebugCatalogs = level;
     return(ret);
 }
+
+/**
+ * xmlCatalogFreeLocal:
+ * @catalogs:  a document's list of catalogs
+ *
+ * Free up the memory associated to the catalog list
+ */
+void
+xmlCatalogFreeLocal(void *catalogs) {
+    xmlCatalogEntryPtr catal;
+
+    catal = (xmlCatalogEntryPtr) catalogs;
+    if (catal != NULL)
+	xmlFreeCatalogEntryList(catal);
+}
+
+
+/**
+ * xmlCatalogAddLocal:
+ * @catalogs:  a document's list of catalogs
+ * @URL:  the URL to a new local catalog
+ *
+ * Add the new entry to the catalog list
+ *
+ * Returns the updated list
+ */
+void *	
+xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) {
+    xmlCatalogEntryPtr catal, add;
+
+    if (!xmlCatalogInitialized)
+	xmlInitializeCatalog();
+    if (URL == NULL)
+	return(catalogs);
+
+    if (xmlDebugCatalogs)
+	xmlGenericError(xmlGenericErrorContext,
+		"Adding document catalog %s\n", URL);
+
+    add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL,
+	                     xmlCatalogDefaultPrefer);
+    if (add == NULL)
+	return(catalogs);
+
+    catal = (xmlCatalogEntryPtr) catalogs;
+    if (catal == NULL) 
+	return((void *) add);
+
+    while (catal->next != NULL)
+	catal = catal->next;
+    catal->next = add;
+    return(catalogs);
+}
+
+/**
+ * xmlCatalogLocalResolve:
+ * @catalogs:  a document's list of catalogs
+ * @pubId:  the public ID string
+ * @sysId:  the system ID string
+ *
+ * Do a complete resolution lookup of an External Identifier using a 
+ * document's private catalog list
+ *
+ * Returns the URI of the resource or NULL if not found, it must be freed
+ *      by the caller.
+ */
+xmlChar *
+xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
+	               const xmlChar *sysID) {
+    xmlCatalogEntryPtr catal;
+
+    if (!xmlCatalogInitialized)
+	xmlInitializeCatalog();
+    catal = (xmlCatalogEntryPtr) catalogs;
+    if (catal == NULL)
+	return(NULL);
+    return(xmlCatalogListXMLResolve(catal, pubID, sysID));
+}
+
 #endif /* LIBXML_CATALOG_ENABLED */
diff --git a/include/libxml/catalog.h b/include/libxml/catalog.h
index 7693996..d39fb60 100644
--- a/include/libxml/catalog.h
+++ b/include/libxml/catalog.h
@@ -33,8 +33,10 @@
  *
  * The namespace for the XML Catalogs elements
  */
-#define XML_CATALOGS_NAMESPACE		\
+#define XML_CATALOGS_NAMESPACE					\
     (const xmlChar *) "urn:oasis:names:tc:entity:xmlns:xml:catalog"
+#define XML_CATALOG_PI						\
+    (const xmlChar *) "oasis-xml-catalog"
 
 /*
  * The API is voluntarily limited to general cataloging
@@ -45,6 +47,13 @@
     XML_CATA_PREFER_SYSTEM
 } xmlCatalogPrefer;
 
+typedef enum {
+    XML_CATA_ALLOW_NONE = 0,
+    XML_CATA_ALLOW_GLOBAL = 1,
+    XML_CATA_ALLOW_DOCUMENT = 2,
+    XML_CATA_ALLOW_ALL = 3
+} xmlCatalogAllow;
+
 void		xmlInitializeCatalog	(void);
 int		xmlLoadCatalog		(const char *filename);
 void		xmlLoadCatalogs		(const char *paths);
@@ -58,8 +67,24 @@
 					 const xmlChar *orig,
 					 const xmlChar *replace);
 int		xmlCatalogRemove	(const xmlChar *value);
+
+/*
+ * Strictly minimal interfaces for per-document catalogs used
+ * by the parser.
+ */
+void		xmlCatalogFreeLocal	(void *catalogs);
+void *		xmlCatalogAddLocal	(void *catalogs,
+					 const xmlChar *URL);
+xmlChar *	xmlCatalogLocalResolve	(void *catalogs,
+					 const xmlChar *pubID,
+	                                 const xmlChar *sysID);
+/*
+ * Preference settings
+ */
 int		xmlCatalogSetDebug	(int level);
 xmlCatalogPrefer xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer);
+void		xmlCatalogSetDefaults	(xmlCatalogAllow allow);
+xmlCatalogAllow	xmlCatalogGetDefaults	(void);
 
 /* DEPRECATED interfaces */
 const xmlChar *	xmlCatalogGetSystem	(const xmlChar *sysID);
diff --git a/include/libxml/parser.h b/include/libxml/parser.h
index de0bebb..1cf7f52 100644
--- a/include/libxml/parser.h
+++ b/include/libxml/parser.h
@@ -217,6 +217,7 @@
 
     int                loadsubset;    /* should the external subset be loaded */
     int                linenumbers;   /* set line number in element content */
+    void              *catalogs;       /* document's own catalog */
 };
 
 /**
diff --git a/include/libxml/xmlIO.h b/include/libxml/xmlIO.h
index 9f248d1..0bdf6a5 100644
--- a/include/libxml/xmlIO.h
+++ b/include/libxml/xmlIO.h
@@ -165,7 +165,7 @@
 #ifdef LIBXML_HTTP_ENABLED
 void *	xmlIOHTTPOpenW			(const char * post_uri,
 					 int   compression );
-void	xmlRegisterHTTPPostCallbacksI	(void );
+void	xmlRegisterHTTPPostCallbacks	(void );
 #endif
 
 /*
diff --git a/include/libxml/xmlerror.h b/include/libxml/xmlerror.h
index 53c5751..88daeff 100644
--- a/include/libxml/xmlerror.h
+++ b/include/libxml/xmlerror.h
@@ -132,7 +132,8 @@
     XML_ERR_ENTITY_LOOP, /* 89 */
     XML_ERR_ENTITY_BOUNDARY, /* 90 */
     XML_ERR_INVALID_URI, /* 91 */
-    XML_ERR_URI_FRAGMENT /* 92 */
+    XML_ERR_URI_FRAGMENT, /* 92 */
+    XML_WAR_CATALOG_PI  /* 93 */
 }xmlParserErrors;
 
 /*
diff --git a/parser.c b/parser.c
index ee68b62..ca96696 100644
--- a/parser.c
+++ b/parser.c
@@ -50,6 +50,9 @@
 #include <libxml/encoding.h>
 #include <libxml/xmlIO.h>
 #include <libxml/uri.h>
+#ifdef LIBXML_CATALOG_ENABLED
+#include <libxml/catalog.h>
+#endif
 
 #ifdef HAVE_CTYPE_H
 #include <ctype.h>
@@ -2941,6 +2944,69 @@
     return(name);
 }
 
+#ifdef LIBXML_CATALOG_ENABLED
+/**
+ * xmlParseCatalogPI:
+ * @ctxt:  an XML parser context
+ * @catalog:  the PI value string
+ * 
+ * parse an XML Catalog Processing Instruction.
+ *
+ * <?oasis-xml-catalog catalog="http://example.com/catalog.xml"?>
+ *
+ * Occurs only if allowed by the user and if happening in the Misc
+ * part of the document before any doctype informations
+ * This will add the given catalog to the parsing context in order
+ * to be used if there is a resolution need further down in the document
+ */
+
+static void
+xmlParseCatalogPI(xmlParserCtxtPtr ctxt, const xmlChar *catalog) {
+    xmlChar *URL = NULL;
+    const xmlChar *tmp, *base;
+    xmlChar marker;
+
+    tmp = catalog;
+    while (IS_BLANK(*tmp)) tmp++;
+    if (xmlStrncmp(tmp, BAD_CAST"catalog", 7))
+	goto error;
+    tmp += 7;
+    while (IS_BLANK(*tmp)) tmp++;
+    if (*tmp != '=') {
+	return;
+    }
+    tmp++;
+    while (IS_BLANK(*tmp)) tmp++;
+    marker = *tmp;
+    if ((marker != '\'') && (marker != '"'))
+	goto error;
+    tmp++;
+    base = tmp;
+    while ((*tmp != 0) && (*tmp != marker)) tmp++;
+    if (*tmp == 0)
+	goto error;
+    URL = xmlStrndup(base, tmp - base);
+    tmp++;
+    while (IS_BLANK(*tmp)) tmp++;
+    if (*tmp != 0)
+	goto error;
+
+    if (URL != NULL) {
+	ctxt->catalogs = xmlCatalogAddLocal(ctxt->catalogs, URL);
+	xmlFree(URL);
+    }
+    return;
+
+error:
+    ctxt->errNo = XML_WAR_CATALOG_PI;
+    if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+	ctxt->sax->warning(ctxt->userData, 
+	     "Catalog PI syntax error: %s\n", catalog);
+    if (URL != NULL)
+	xmlFree(URL);
+}
+#endif
+
 /**
  * xmlParsePI:
  * @ctxt:  an XML parser context
@@ -3063,6 +3129,18 @@
 		}
 		SKIP(2);
 
+#ifdef LIBXML_CATALOG_ENABLED
+		if (((state == XML_PARSER_MISC) ||
+	             (state == XML_PARSER_START)) &&
+		    (xmlStrEqual(target, XML_CATALOG_PI))) {
+		    xmlCatalogAllow allow = xmlCatalogGetDefaults();
+		    if ((allow == XML_CATA_ALLOW_DOCUMENT) ||
+			(allow == XML_CATA_ALLOW_ALL))
+			xmlParseCatalogPI(ctxt, buf);
+		}
+#endif
+
+
 		/*
 		 * SAX: PI detected.
 		 */
@@ -5324,7 +5402,7 @@
 			ctxt->disableSAX = 1;
 		    } else {
 			ctxt->errNo = XML_WAR_UNDECLARED_ENTITY;
-			if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
 			    ctxt->sax->error(ctxt->userData, 
 				 "Entity '%s' not defined\n", name);
 		    }
diff --git a/parserInternals.c b/parserInternals.c
index e31e6f2..8e652b3 100644
--- a/parserInternals.c
+++ b/parserInternals.c
@@ -46,6 +46,9 @@
 #include <libxml/valid.h>
 #include <libxml/xmlIO.h>
 #include <libxml/uri.h>
+#ifdef LIBXML_CATALOG_ENABLED
+#include <libxml/catalog.h>
+#endif
 
 void xmlUpgradeOldNs(xmlDocPtr doc);
 
@@ -2270,6 +2273,7 @@
     ctxt->errNo = XML_ERR_OK;
     ctxt->depth = 0;
     ctxt->charset = XML_CHAR_ENCODING_UTF8;
+    ctxt->catalogs = NULL;
     xmlInitNodeInfoSeq(&ctxt->node_seq);
 }
 
@@ -2308,6 +2312,10 @@
         xmlFree(ctxt->sax);
     if (ctxt->directory != NULL) xmlFree((char *) ctxt->directory);
     if (ctxt->vctxt.nodeTab != NULL) xmlFree(ctxt->vctxt.nodeTab);
+#ifdef LIBXML_CATALOG_ENABLED
+    if (ctxt->catalogs != NULL)
+	xmlCatalogFreeLocal(ctxt->catalogs);
+#endif
     xmlFree(ctxt);
 }
 
diff --git a/xmlIO.c b/xmlIO.c
index 1cfefce..bff4479 100644
--- a/xmlIO.c
+++ b/xmlIO.c
@@ -2374,6 +2374,7 @@
     xmlChar *resource = NULL;
 #ifdef LIBXML_CATALOG_ENABLED
     struct stat info;
+    xmlCatalogAllow pref;
 #endif
 
 #ifdef DEBUG_EXTERNAL_ENTITIES
@@ -2385,11 +2386,40 @@
      * If the resource doesn't exists as a file,
      * try to load it from the resource pointed in the catalog
      */
+    pref = xmlCatalogGetDefaults();
+
+    if ((pref != XML_CATA_ALLOW_NONE)
 #ifdef HAVE_STAT
-    if ((URL == NULL) || (stat(URL, &info) < 0)) 
+        && ((URL == NULL) || (stat(URL, &info) < 0))
 #endif
-	resource = xmlCatalogResolve((const xmlChar *)ID,
-		                     (const xmlChar *)URL);
+	) {
+	/*
+	 * Do a local lookup
+	 */
+	if ((ctxt->catalogs != NULL) &&
+	    ((pref == XML_CATA_ALLOW_ALL) ||
+	     (pref == XML_CATA_ALLOW_DOCUMENT))) {
+	    resource = xmlCatalogLocalResolve(ctxt->catalogs,
+					      (const xmlChar *)ID,
+					      (const xmlChar *)URL);
+        }
+	/*
+	 * Do a global lookup
+	 */
+	if (((resource == NULL)
+#ifdef HAVE_STAT
+            || (stat((const char *) resource, &info) < 0)
+#endif
+	    ) && ((pref == XML_CATA_ALLOW_ALL) ||
+		  (pref == XML_CATA_ALLOW_GLOBAL))) {
+
+	    resource = xmlCatalogResolve((const xmlChar *)ID,
+					 (const xmlChar *)URL);
+	}
+	/*
+	 * TODO: do an URI lookup on the reference
+	 */
+    }
 #endif
 
     if (resource == NULL)