starts to look okay, really plugged the new framework, cleaned a lot of

* catalog.c parser.c xmlIO.c xmlcatalog.c xmllint.c
  include/libxml/catalog.h: starts to look okay, really
  plugged the new framework, cleaned a lot of stuff,
  added some APIs, except the PI's support missing this
  should be mostly complete
* result/catalogs/* test/catalogs/*: added new test, enriched
  the existing one with URN ID tests
Daniel
diff --git a/ChangeLog b/ChangeLog
index 43e152f..01b5081 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Wed Aug 22 02:03:31 CEST 2001 Daniel Veillard <daniel@veillard.com>
+
+	* catalog.c parser.c xmlIO.c xmlcatalog.c xmllint.c 
+	  include/libxml/catalog.h: starts to look okay, really
+	  plugged the new framework, cleaned a lot of stuff,
+	  added some APIs, except the PI's support missing this
+	  should be mostly complete
+	* result/catalogs/* test/catalogs/*: added new test, enriched
+	  the existing one with URN ID tests
+
 Tue Aug 21 14:56:18 CEST 2001 Daniel Veillard <daniel@veillard.com>
 
 	* catalog.c: fixed nextCatalog
diff --git a/catalog.c b/catalog.c
index 21270d4..2ea69db 100644
--- a/catalog.c
+++ b/catalog.c
@@ -46,6 +46,8 @@
             __FILE__, __LINE__);
 
 #define XML_URN_PUBID "urn:publicid:"
+#define XML_CATAL_BREAK ((xmlChar *) -1)
+#define XML_DEFAULT_CATALOG "/etc/xml/catalog"
 
 /************************************************************************
  *									*
@@ -54,11 +56,6 @@
  ************************************************************************/
 
 typedef enum {
-    XML_CATA_PREFER_PUBLIC = 1,
-    XML_CATA_PREFER_SYSTEM
-} xmlCatalogPrefer;
-
-typedef enum {
     XML_CATA_NONE = 0,
     XML_CATA_CATALOG,
     XML_CATA_NEXT_CATALOG,
@@ -93,11 +90,14 @@
     xmlCatalogEntryType type;
     xmlChar *name;
     xmlChar *value;
-    /* TODO : 1234 xmlCatalogPrefer prefer */
+    xmlCatalogPrefer prefer;
 };
 
 static xmlHashTablePtr xmlDefaultCatalog;
 static xmlCatalogEntryPtr xmlDefaultXMLCatalogList = NULL;
+static int xmlCatalogInitialized = 0;
+static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_SYSTEM;
+
 
 /* Catalog stack */
 static const char * catalTab[10];  /* stack of catals */
@@ -114,7 +114,7 @@
 
 static xmlCatalogEntryPtr
 xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
-	           const xmlChar *value) {
+	           const xmlChar *value, xmlCatalogPrefer prefer) {
     xmlCatalogEntryPtr ret;
 
     ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry));
@@ -135,6 +135,7 @@
 	ret->value = xmlStrdup(value);
     else
 	ret->value = NULL;
+    ret->prefer = prefer;
     return(ret);
 }
 
@@ -240,6 +241,77 @@
 
 /************************************************************************
  *									*
+ *			Helper function					*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlCatalogUnWrapURN:
+ * @urn:  an "urn:publicid:" to unwrapp
+ *
+ * Expand the URN into the equivalent Public Identifier
+ *
+ * Returns the new identifier or NULL, the string must be deallocated
+ *         by the caller.
+ */
+static xmlChar *
+xmlCatalogUnWrapURN(const xmlChar *urn) {
+    xmlChar result[2000];
+    unsigned int i = 0;
+
+    if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1))
+	return(NULL);
+    urn += sizeof(XML_URN_PUBID) - 1;
+    
+    while (*urn != 0) {
+	if (i > sizeof(result) - 3)
+	    break;
+	if (*urn == '+') {
+	    result[i++] = ' ';
+	    urn++;
+	} else if (*urn == ':') {
+	    result[i++] = '/';
+	    result[i++] = '/';
+	    urn++;
+	} else if (*urn == ';') {
+	    result[i++] = ':';
+	    result[i++] = ':';
+	    urn++;
+	} else if (*urn == '%') {
+	    if ((urn[1] == '2') && (urn[1] == 'B'))
+		result[i++] = '+';
+	    else if ((urn[1] == '3') && (urn[1] == 'A'))
+		result[i++] = ':';
+	    else if ((urn[1] == '2') && (urn[1] == 'F'))
+		result[i++] = '/';
+	    else if ((urn[1] == '3') && (urn[1] == 'B'))
+		result[i++] = ';';
+	    else if ((urn[1] == '2') && (urn[1] == '7'))
+		result[i++] = '\'';
+	    else if ((urn[1] == '3') && (urn[1] == 'F'))
+		result[i++] = '?';
+	    else if ((urn[1] == '2') && (urn[1] == '3'))
+		result[i++] = '#';
+	    else if ((urn[1] == '2') && (urn[1] == '5'))
+		result[i++] = '%';
+	    else {
+		result[i++] = *urn;
+		urn++;
+		continue;
+	    }
+	    urn += 3;
+	} else {
+	    result[i++] = *urn;
+	    urn++;
+	}
+    }
+    result[i] = 0;
+
+    return(xmlStrdup(result));
+}
+
+/************************************************************************
+ *									*
  *			The XML Catalog parser				*
  *									*
  ************************************************************************/
@@ -286,7 +358,7 @@
 static xmlCatalogEntryPtr
 xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type,
 			  const xmlChar *name, const xmlChar *attrName,
-			  const xmlChar *uriAttrName) {
+			  const xmlChar *uriAttrName, xmlCatalogPrefer prefer) {
     int ok = 1;
     xmlChar *uriValue;
     xmlChar *nameValue = NULL;
@@ -319,13 +391,15 @@
     base = xmlNodeGetBase(cur->doc, cur);
     URL = xmlBuildURI(uriValue, base);
     if (URL != NULL) {
-	if (xmlDebugCatalogs) {
+	if (xmlDebugCatalogs > 1) {
 	    if (nameValue != NULL)
-		printf("Found %s: '%s' '%s'\n", name, nameValue, URL);
+		xmlGenericError(xmlGenericErrorContext,
+			"Found %s: '%s' '%s'\n", name, nameValue, URL);
 	    else
-		printf("Found %s: '%s'\n", name, URL);
+		xmlGenericError(xmlGenericErrorContext,
+			"Found %s: '%s'\n", name, URL);
 	}
-	ret = xmlNewCatalogEntry(type, nameValue, URL);
+	ret = xmlNewCatalogEntry(type, nameValue, URL, prefer);
     } else {
 	xmlGenericError(xmlGenericErrorContext,
 		"%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue);
@@ -374,38 +448,38 @@
         xmlParseXMLCatalogNodeList(cur->children, prefer, parent);
     } else if (xmlStrEqual(cur->name, BAD_CAST "public")) {
 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC,
-		BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri");
+		BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer);
     } else if (xmlStrEqual(cur->name, BAD_CAST "system")) {
 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM,
-		BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri");
+		BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer);
     } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) {
 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM,
 		BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString",
-		BAD_CAST "rewritePrefix");
+		BAD_CAST "rewritePrefix", prefer);
     } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) {
 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC,
 		BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString",
-		BAD_CAST "catalog");
+		BAD_CAST "catalog", prefer);
     } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) {
 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM,
 		BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString",
-		BAD_CAST "catalog");
+		BAD_CAST "catalog", prefer);
     } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) {
 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI,
 		BAD_CAST "uri", BAD_CAST "name",
-		BAD_CAST "uri");
+		BAD_CAST "uri", prefer);
     } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) {
 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI,
 		BAD_CAST "rewriteURI", BAD_CAST "uriStartString",
-		BAD_CAST "rewritePrefix");
+		BAD_CAST "rewritePrefix", prefer);
     } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) {
 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI,
 		BAD_CAST "delegateURI", BAD_CAST "uriStartString",
-		BAD_CAST "catalog");
+		BAD_CAST "catalog", prefer);
     } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) {
 	entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG,
 		BAD_CAST "nextCatalog", NULL,
-		BAD_CAST "catalog");
+		BAD_CAST "catalog", prefer);
     }
     if ((entry != NULL) && (parent != NULL)) {
 	entry->parent = parent;
@@ -452,6 +526,10 @@
     if ((value == NULL) || (file == NULL))
         return(NULL);
 
+    if (xmlDebugCatalogs)
+	xmlGenericError(xmlGenericErrorContext,
+		"Parsing catalog %s's content\n", file);
+
     doc = xmlParseDoc((xmlChar *) value);
     if (doc == NULL) 
 	return(NULL);
@@ -462,13 +540,6 @@
 	(cur->ns != NULL) && (cur->ns->href != NULL) &&
 	(xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
 
-	parent = xmlNewCatalogEntry(XML_CATA_CATALOG,
-		                    (const xmlChar *)file, NULL);
-        if (parent == NULL) {
-	    xmlFreeDoc(doc);
-	    return(NULL);
-	}
-
 	prop = xmlGetProp(cur, BAD_CAST "prefer");
 	if (prop != NULL) {
 	    if (xmlStrEqual(prop, BAD_CAST "system")) {
@@ -482,6 +553,13 @@
 	    }
 	    xmlFree(prop);
 	}
+	parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
+		                    (const xmlChar *)file, prefer);
+        if (parent == NULL) {
+	    xmlFreeDoc(doc);
+	    return(NULL);
+	}
+
 	cur = cur->children;
 	xmlParseXMLCatalogNodeList(cur, prefer, parent);
     } else {
@@ -505,16 +583,24 @@
         return(NULL);
 
     doc = xmlParseFile((const char *) filename);
-    if (doc == NULL) 
+    if (doc == NULL) {
+	if (xmlDebugCatalogs)
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Failed to parse catalog %s\n", filename);
 	return(NULL);
+    }
+
+    if (xmlDebugCatalogs)
+	xmlGenericError(xmlGenericErrorContext,
+		"Parsing catalog %s\n", filename);
 
     cur = xmlDocGetRootElement(doc);
     if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) &&
 	(cur->ns != NULL) && (cur->ns->href != NULL) &&
 	(xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) {
 
-	parent = xmlNewCatalogEntry(XML_CATA_CATALOG,
-		                    (const xmlChar *)filename, NULL);
+	parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL,
+		                    (const xmlChar *)filename, prefer);
         if (parent == NULL) {
 	    xmlFreeDoc(doc);
 	    return(NULL);
@@ -569,8 +655,7 @@
     /*
      * Fetch and parse
      */
-    /* TODO : 1234 s/XML_CATA_PREFER_PUBLIC/catal->prefer */
-    children = xmlParseXMLCatalogFile(XML_CATA_PREFER_PUBLIC, catal->value);
+    children = xmlParseXMLCatalogFile(catal->prefer, catal->value);
     if (children == NULL)
 	return(-1);
 
@@ -747,8 +832,12 @@
     if ((catal == NULL) || (catal->type != XML_CATA_CATALOG))
 	return(-1);
     typ = xmlGetXMLCatalogEntryType(type);
-    if (typ == XML_CATA_NONE)
+    if (typ == XML_CATA_NONE) {
+	if (xmlDebugCatalogs)
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Failed to add unknown element %s to catalog\n", type);
 	return(-1);
+    }
 
     cur = catal->children;
     /*
@@ -758,6 +847,9 @@
 	while (cur != NULL) {
 	    if ((orig != NULL) && (cur->type == typ) &&
 		(xmlStrEqual(orig, cur->name))) {
+		if (xmlDebugCatalogs)
+		    xmlGenericError(xmlGenericErrorContext,
+			    "Updating element %s to catalog\n", type);
 		if (cur->value != NULL)
 		    xmlFree(cur->value);
 		cur->value = xmlStrdup(replace);
@@ -768,10 +860,13 @@
 	    cur = cur->next;
 	}
     }
+    if (xmlDebugCatalogs)
+	xmlGenericError(xmlGenericErrorContext,
+		"Adding element %s to catalog\n", type);
     if (cur == NULL)
-	catal->children = xmlNewCatalogEntry(typ, orig, replace);
+	catal->children = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
     else
-	cur->next = xmlNewCatalogEntry(typ, orig, replace);
+	cur->next = xmlNewCatalogEntry(typ, orig, replace, catal->prefer);
     return(0);
 }
 
@@ -803,6 +898,14 @@
     while (cur != NULL) {
 	if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) ||
 	    (xmlStrEqual(value, cur->value))) {
+	    if (xmlDebugCatalogs) {
+		if (cur->name != NULL)
+		    xmlGenericError(xmlGenericErrorContext,
+			    "Removing element %s from catalog\n", cur->name);
+		else
+		    xmlGenericError(xmlGenericErrorContext,
+			    "Removing element %s from catalog\n", cur->value);
+	    }
 	    ret++;
 	    tmp = cur;
 	    cur = tmp->next;
@@ -821,69 +924,6 @@
 }
 
 /**
- * xmlCatalogGetXMLPublic:
- * @catal:  an XML catalog
- * @pubId:  the public ID string
- *
- * Try to lookup the system ID associated to a public ID
- *
- * Returns the system ID if found or NULL otherwise.
- */
-static const xmlChar *
-xmlCatalogGetXMLPublic(xmlCatalogEntryPtr catal, const xmlChar *pubID) {
-    const xmlChar *ret;
-    while (catal != NULL) {
-	switch (catal->type) {
-            case XML_CATA_CATALOG:
-		if (catal->children == NULL) {
-		    if (xmlFetchXMLCatalogFile(catal))
-			break;
-		}
-		ret = xmlCatalogGetXMLPublic(catal->children, pubID);
-		if (ret != NULL)
-		    return(ret);
-		break;
-            case XML_CATA_NEXT_CATALOG:
-		if (catal->children == NULL) {
-		    if (xmlFetchXMLCatalogFile(catal))
-			break;
-		}
-            case XML_CATA_PUBLIC:
-		if (xmlStrEqual(pubID, catal->name))
-		    return(catal->value);
-		break;
-            case XML_CATA_SYSTEM:
-            case XML_CATA_REWRITE_SYSTEM:
-            case XML_CATA_DELEGATE_PUBLIC:
-            case XML_CATA_DELEGATE_SYSTEM:
-            case XML_CATA_URI:
-            case XML_CATA_REWRITE_URI:
-            case XML_CATA_DELEGATE_URI:
-		TODO;
-		break;
-
-            case XML_CATA_NONE:
-            case SGML_CATA_SYSTEM:
-            case SGML_CATA_PUBLIC:
-            case SGML_CATA_ENTITY:
-            case SGML_CATA_PENTITY:
-            case SGML_CATA_DOCTYPE:
-            case SGML_CATA_LINKTYPE:
-            case SGML_CATA_NOTATION:
-            case SGML_CATA_DELEGATE:
-            case SGML_CATA_BASE:
-            case SGML_CATA_CATALOG:
-            case SGML_CATA_DOCUMENT:
-            case SGML_CATA_SGMLDECL:
-		/* Ignored entries */
-		break;
-	}
-	catal = catal->next;
-    }
-    return(NULL);
-}
-
-/**
  * xmlCatalogXMLResolve:
  * @catal:  a catalog list
  * @pubId:  the public ID string
@@ -916,8 +956,12 @@
 	while (cur != NULL) {
 	    switch (cur->type) {
 		case XML_CATA_SYSTEM:
-		    if (xmlStrEqual(sysID, cur->name))
+		    if (xmlStrEqual(sysID, cur->name)) {
+			if (xmlDebugCatalogs)
+			    xmlGenericError(xmlGenericErrorContext,
+				    "Found system match %s\n", cur->name);
 			return(xmlStrdup(cur->value));
+		    }
 		    break;
 		case XML_CATA_REWRITE_SYSTEM:
 		    len = xmlStrlen(cur->name);
@@ -940,6 +984,9 @@
 	    cur = cur->next;
 	}
 	if (rewrite != NULL) {
+	    if (xmlDebugCatalogs)
+		xmlGenericError(xmlGenericErrorContext,
+			"Using rewriting rule %s\n", rewrite->name);
 	    ret = xmlStrdup(rewrite->value);
 	    if (ret != NULL)
 		ret = xmlStrcat(ret, &sysID[lenrewrite]);
@@ -947,7 +994,7 @@
 	}
 	if (haveDelegate) {
 	    /*
-	     * Assume the entries have been sorted by decreasing subscting
+	     * Assume the entries have been sorted by decreasing substring
 	     * matches when the list was produced.
 	     */
 	    cur = catal;
@@ -958,11 +1005,21 @@
 			xmlFetchXMLCatalogFile(cur);
 		    }
 		    if (cur->children != NULL) {
-			TODO /* handle a delegate system entry */
+			if (xmlDebugCatalogs)
+			    xmlGenericError(xmlGenericErrorContext,
+				    "Trying system delegate %s\n", cur->value);
+			ret = xmlCatalogListXMLResolve(cur->children, NULL,
+				                       sysID);
+			if (ret != NULL)
+			    return(ret);
 		    }
 		}
 		cur = cur->next;
 	    }
+	    /*
+	     * Apply the cut algorithm explained in 4/
+	     */
+	    return(XML_CATAL_BREAK);
 	}
     }
     /*
@@ -974,11 +1031,16 @@
 	while (cur != NULL) {
 	    switch (cur->type) {
 		case XML_CATA_PUBLIC:
-		    if (xmlStrEqual(pubID, cur->name))
+		    if (xmlStrEqual(pubID, cur->name)) {
+			if (xmlDebugCatalogs)
+			    xmlGenericError(xmlGenericErrorContext,
+				    "Found public match %s\n", cur->name);
 			return(xmlStrdup(cur->value));
+		    }
 		    break;
 		case XML_CATA_DELEGATE_PUBLIC:
-		    if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))
+		    if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) &&
+			(cur->prefer == XML_CATA_PREFER_PUBLIC))
 			haveDelegate++;
 		    break;
 		case XML_CATA_NEXT_CATALOG:
@@ -992,22 +1054,33 @@
 	}
 	if (haveDelegate) {
 	    /*
-	     * Assume the entries have been sorted by decreasing subscting
+	     * Assume the entries have been sorted by decreasing substring
 	     * matches when the list was produced.
 	     */
 	    cur = catal;
 	    while (cur != NULL) {
 		if ((cur->type == XML_CATA_DELEGATE_PUBLIC) &&
-		    (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) {
+		    (cur->prefer == XML_CATA_PREFER_PUBLIC) &&
+		    (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) {
 		    if (cur->children == NULL) {
 			xmlFetchXMLCatalogFile(cur);
 		    }
 		    if (cur->children != NULL) {
-			TODO /* handle a delegate public entry */
+			if (xmlDebugCatalogs)
+			    xmlGenericError(xmlGenericErrorContext,
+				    "Trying public delegate %s\n", cur->value);
+			ret = xmlCatalogListXMLResolve(cur->children, pubID,
+				                       NULL);
+			if (ret != NULL)
+			    return(ret);
 		    }
 		}
 		cur = cur->next;
 	    }
+	    /*
+	     * Apply the cut algorithm explained in 4/
+	     */
+	    return(XML_CATAL_BREAK);
 	}
     }
     if (haveNext) {
@@ -1048,28 +1121,59 @@
 xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID,
 	              const xmlChar *sysID) {
     xmlChar *ret = NULL;
-    if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID))) {
-	TODO /* convert to PublicId */
+    xmlChar *urnID = NULL;
+    
+    if (catal == NULL)
+        return(NULL);
+    if ((pubID == NULL) && (sysID == NULL))
+	return(NULL);
+
+    if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
+	urnID = xmlCatalogUnWrapURN(pubID);
+	if (xmlDebugCatalogs) {
+	    if (urnID == NULL)
+		xmlGenericError(xmlGenericErrorContext,
+			"Public URN ID %s expanded to NULL\n", pubID);
+	    else
+		xmlGenericError(xmlGenericErrorContext,
+			"Public URN ID expanded to %s\n", urnID);
+	}
+	ret = xmlCatalogListXMLResolve(catal, urnID, sysID);
+	if (urnID != NULL)
+	    xmlFree(urnID);
+	return(ret);
     }
-    if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID))) {
-	TODO /* convert to PublicId and check */
+    if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) {
+	urnID = xmlCatalogUnWrapURN(sysID);
+	if (xmlDebugCatalogs) {
+	    if (urnID == NULL)
+		xmlGenericError(xmlGenericErrorContext,
+			"System URN ID %s expanded to NULL\n", sysID);
+	    else
+		xmlGenericError(xmlGenericErrorContext,
+			"System URN ID expanded to %s\n", urnID);
+	}
+	if (pubID == NULL)
+	    ret = xmlCatalogListXMLResolve(catal, urnID, NULL);
+	else if (xmlStrEqual(pubID, urnID))
+	    ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
+	else {
+	    ret = xmlCatalogListXMLResolve(catal, pubID, NULL);
+	}
+	if (urnID != NULL)
+	    xmlFree(urnID);
+	return(ret);
     }
     while (catal != NULL) {
 	if (catal->type == XML_CATA_CATALOG) {
 	    if (catal->children == NULL) {
-		/*
-		 * Construct the list on the fly, then double check
-		 * in case of threaded program that it hasn't already
-		 * being built by a concurrent thread.
-		xmlCatalogEntryPtr list;
-
-		list = 
-		 */
-		TODO
+		xmlFetchXMLCatalogFile(catal);
 	    }
-	    ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
-	    if (ret != NULL)
-		return(ret);
+	    if (catal->children != NULL) {
+		ret = xmlCatalogXMLResolve(catal->children, pubID, sysID);
+		if (ret != NULL)
+		    return(ret);
+	    }
 	}
 	catal = catal->next;
     }
@@ -1365,7 +1469,8 @@
 		if (filename != NULL) {
 		    xmlCatalogEntryPtr entry;
 
-		    entry = xmlNewCatalogEntry(type, name, filename);
+		    entry = xmlNewCatalogEntry(type, name, filename,
+			                       XML_CATA_PREFER_NONE);
 		    res = xmlHashAddEntry(xmlDefaultCatalog, name, entry);
 		    if (res < 0) {
 			xmlFreeCatalogEntry(entry);
@@ -1423,6 +1528,30 @@
 }
 
 /**
+ * xmlCatalogGetSGMLSystem:
+ * @catal:  an SGML catalog hash
+ * @sysId:  the public ID string
+ *
+ * Try to lookup the catalog local reference for a system ID
+ *
+ * Returns the system ID if found or NULL otherwise.
+ */
+static const xmlChar *
+xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) {
+    xmlCatalogEntryPtr entry;
+
+    if (catal == NULL)
+	return(NULL);
+
+    entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID);
+    if (entry == NULL)
+	return(NULL);
+    if (entry->type == SGML_CATA_SYSTEM)
+	return(entry->value);
+    return(NULL);
+}
+
+/**
  * xmlCatalogSGMLResolve:
  * @pubId:  the public ID string
  * @sysId:  the system ID string
@@ -1444,13 +1573,40 @@
  ************************************************************************/
 
 /**
+ * xmlInitializeCatalog:
+ *
+ * Do the catalog initialization.
+ * TODO: this function is not thread safe, catalog initialization should
+ *       preferably be done once at startup
+ */
+void
+xmlInitializeCatalog(void) {
+    const char *catalogs;
+
+    if (xmlCatalogInitialized != 0)
+	return;
+
+    if (getenv("XML_DEBUG_CATALOG")) 
+	xmlDebugCatalogs = 1;
+    if ((xmlDefaultXMLCatalogList == NULL) && (xmlDefaultCatalog == NULL)) {
+	catalogs = getenv("XML_CATALOG_FILES");
+	if (catalogs == NULL)
+	    catalogs = XML_DEFAULT_CATALOG;
+	xmlDefaultXMLCatalogList = xmlNewCatalogEntry(XML_CATA_CATALOG,
+			   NULL, BAD_CAST catalogs, xmlCatalogDefaultPrefer);
+    }
+
+    xmlCatalogInitialized = 1;
+}
+
+/**
  * xmlLoadCatalog:
  * @filename:  a file path
  *
  * Load the catalog and makes its definitions effective for the default
  * external entity loader. It will recuse in CATALOG entries.
  * TODO: this function is not thread safe, catalog initialization should
- *       be done once at startup
+ *       preferably be done once at startup
  *
  * Returns 0 in case of success -1 in case of error
  */
@@ -1467,9 +1623,17 @@
 	xmlDefaultCatalog = xmlHashCreate(20);
     if (xmlDefaultCatalog == NULL)
 	return(-1);
-    
+
+    /*
+     * Need to be done after ...
+     */
+    if (!xmlCatalogInitialized)
+	xmlInitializeCatalog();
+
+#ifdef HAVE_STAT
     if (stat(filename, &info) < 0) 
 	return(-1);
+#endif
 
     /*
      * Prevent loops
@@ -1545,7 +1709,7 @@
  * Load the catalogs and makes their definitions effective for the default
  * external entity loader.
  * TODO: this function is not thread safe, catalog initialization should
- *       be done once at startup
+ *       preferably be done once at startup
  */
 void
 xmlLoadCatalogs(const char *pathss) {
@@ -1578,33 +1742,93 @@
  */
 void
 xmlCatalogCleanup(void) {
+    if (xmlDebugCatalogs)
+	xmlGenericError(xmlGenericErrorContext,
+		"Catalogs cleanup\n");
     if (xmlDefaultXMLCatalogList != NULL)
 	xmlFreeCatalogEntryList(xmlDefaultXMLCatalogList);
+    xmlDefaultXMLCatalogList = NULL;
     if (xmlDefaultCatalog != NULL)
 	xmlHashFree(xmlDefaultCatalog,
 		    (xmlHashDeallocator) xmlFreeCatalogEntry);
+    xmlDebugCatalogs = 0;
     xmlDefaultCatalog = NULL;
+    xmlCatalogInitialized = 0;
 }
 
 /**
  * xmlCatalogGetSystem:
- * @sysId:  the system ID string
+ * @pubId:  the public ID string
  *
- * Try to lookup the resource associated to a system ID
+ * Try to lookup the system ID associated to a public ID
+ * DEPRECATED, use xmlCatalogResolveSystem()
  *
- * Returns the resource name if found or NULL otherwise.
+ * Returns the system ID if found or NULL otherwise.
  */
 const xmlChar *
 xmlCatalogGetSystem(const xmlChar *sysID) {
-    xmlCatalogEntryPtr entry;
+    xmlChar *ret;
+    static xmlChar result[1000];
 
-    if ((sysID == NULL) || (xmlDefaultCatalog == NULL))
+    if (sysID == NULL)
 	return(NULL);
-    entry = (xmlCatalogEntryPtr) xmlHashLookup(xmlDefaultCatalog, sysID);
-    if (entry == NULL)
+    
+    if (!xmlCatalogInitialized)
+	xmlInitializeCatalog();
+
+    /*
+     * Check first the XML catalogs
+     */
+    if (xmlDefaultXMLCatalogList != NULL) {
+	ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
+	if (ret != NULL) {
+	    snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
+	    result[sizeof(result) - 1] = 0;
+	    return(result);
+	}
+    }
+
+    if (xmlDefaultCatalog != NULL)
+	return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID));
+    return(NULL);
+}
+
+/**
+ * xmlCatalogResolveSystem:
+ * @sysId:  the public ID string
+ *
+ * Try to lookup the catalog resource for a system ID
+ *
+ * Returns the system ID if found or NULL otherwise, the value returned
+ *      must be freed by the caller.
+ */
+xmlChar *
+xmlCatalogResolveSystem(const xmlChar *sysID) {
+    xmlCatalogEntryPtr catal;
+    xmlChar *ret;
+    const xmlChar *sgml;
+
+    if (sysID == NULL)
 	return(NULL);
-    if (entry->type == SGML_CATA_SYSTEM)
-	return(entry->value);
+    
+    if (!xmlCatalogInitialized)
+	xmlInitializeCatalog();
+
+    /*
+     * Check first the XML catalogs
+     */
+    catal = xmlDefaultXMLCatalogList;
+    if (catal != NULL) {
+	ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, NULL, sysID);
+	if ((ret != NULL) && (ret != XML_CATAL_BREAK))
+	    return(ret);
+    }
+
+    if (xmlDefaultCatalog != NULL) {
+	sgml = xmlCatalogGetSGMLSystem(xmlDefaultCatalog, sysID);
+	if (sgml != NULL)
+	    return(xmlStrdup(sgml));
+    }
     return(NULL);
 }
 
@@ -1613,29 +1837,74 @@
  * @pubId:  the public ID string
  *
  * Try to lookup the system ID associated to a public ID
+ * DEPRECATED, use xmlCatalogResolvePublic()
  *
  * Returns the system ID if found or NULL otherwise.
  */
 const xmlChar *
 xmlCatalogGetPublic(const xmlChar *pubID) {
-    xmlCatalogEntryPtr catal;
-    const xmlChar *ret;
+    xmlChar *ret;
+    static xmlChar result[1000];
 
     if (pubID == NULL)
 	return(NULL);
     
+    if (!xmlCatalogInitialized)
+	xmlInitializeCatalog();
+
+    /*
+     * Check first the XML catalogs
+     */
+    if (xmlDefaultXMLCatalogList != NULL) {
+	ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
+	if ((ret != NULL) && (ret != XML_CATAL_BREAK)) {
+	    snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret);
+	    result[sizeof(result) - 1] = 0;
+	    return(result);
+	}
+    }
+
+    if (xmlDefaultCatalog != NULL)
+	return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID));
+    return(NULL);
+}
+
+/**
+ * xmlCatalogResolvePublic:
+ * @pubId:  the public ID string
+ *
+ * Try to lookup the system ID associated to a public ID
+ *
+ * Returns the system ID if found or NULL otherwise, the value returned
+ *      must be freed by the caller.
+ */
+xmlChar *
+xmlCatalogResolvePublic(const xmlChar *pubID) {
+    xmlCatalogEntryPtr catal;
+    xmlChar *ret;
+    const xmlChar *sgml;
+
+    if (pubID == NULL)
+	return(NULL);
+    
+    if (!xmlCatalogInitialized)
+	xmlInitializeCatalog();
+
     /*
      * Check first the XML catalogs
      */
     catal = xmlDefaultXMLCatalogList;
     if (catal != NULL) {
-	ret = xmlCatalogGetXMLPublic(catal, pubID);
-	if (ret != NULL)
+	ret = xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, NULL);
+	if ((ret != NULL) && (ret != XML_CATAL_BREAK))
 	    return(ret);
     }
 
-    if (xmlDefaultCatalog != NULL)
-	return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID));
+    if (xmlDefaultCatalog != NULL) {
+	sgml = xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID);
+	if (sgml != NULL)
+	    return(xmlStrdup(sgml));
+    }
     return(NULL);
 }
 
@@ -1651,11 +1920,19 @@
  */
 xmlChar *
 xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) {
+    if (!xmlCatalogInitialized)
+	xmlInitializeCatalog();
+
     if (xmlDefaultXMLCatalogList != NULL) {
 	return(xmlCatalogListXMLResolve(xmlDefaultXMLCatalogList, pubID, sysID));
     } else {
-	return(xmlCatalogSGMLResolve(pubID, sysID));
+	const xmlChar *ret;
+
+	ret = xmlCatalogSGMLResolve(pubID, sysID);
+	if (ret != NULL)
+	    return(xmlStrdup(ret));
     }
+    return(NULL);
 }
 
 /**
@@ -1692,6 +1969,9 @@
 xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) {
     int res = -1;
 
+    if (!xmlCatalogInitialized)
+	xmlInitializeCatalog();
+
     if (xmlDefaultXMLCatalogList != NULL) {
 	res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace);
     } else if (xmlDefaultCatalog != NULL) {
@@ -1700,7 +1980,7 @@
 	typ = xmlGetSGMLCatalogEntryType(type);
 	if (type != XML_CATA_NONE) {
 	    xmlCatalogEntryPtr entry;
-	    entry = xmlNewCatalogEntry(typ, orig, replace);
+	    entry = xmlNewCatalogEntry(typ, orig, replace, XML_CATA_PREFER_NONE);
 	    res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry);
 	}
     } 
@@ -1719,6 +1999,9 @@
 xmlCatalogRemove(const xmlChar *value) {
     int res = -1;
 
+    if (!xmlCatalogInitialized)
+	xmlInitializeCatalog();
+
     if (xmlDefaultXMLCatalogList != NULL) {
 	res = xmlDelXMLCatalog(xmlDefaultXMLCatalogList, value);
     } else if (xmlDefaultCatalog != NULL) {
@@ -1728,6 +2011,23 @@
 }
 
 /**
+ * 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
+ *
+ * Returns the previous value of the default preference for delegation
+ */
+xmlCatalogPrefer
+xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) {
+    xmlCatalogPrefer ret = xmlCatalogDefaultPrefer;
+
+    xmlCatalogDefaultPrefer = prefer;
+    return(ret);
+}
+
+/**
  * xmlCatalogSetDebug:
  * @level:  the debug level of catalogs required
  *
diff --git a/include/libxml/catalog.h b/include/libxml/catalog.h
index 8651dfd..7693996 100644
--- a/include/libxml/catalog.h
+++ b/include/libxml/catalog.h
@@ -36,19 +36,34 @@
 #define XML_CATALOGS_NAMESPACE		\
     (const xmlChar *) "urn:oasis:names:tc:entity:xmlns:xml:catalog"
 
+/*
+ * The API is voluntarily limited to general cataloging
+ */
+typedef enum {
+    XML_CATA_PREFER_NONE = 0,
+    XML_CATA_PREFER_PUBLIC = 1,
+    XML_CATA_PREFER_SYSTEM
+} xmlCatalogPrefer;
+
+void		xmlInitializeCatalog	(void);
 int		xmlLoadCatalog		(const char *filename);
 void		xmlLoadCatalogs		(const char *paths);
 void		xmlCatalogCleanup	(void);
 void		xmlCatalogDump		(FILE *out);
-const xmlChar *	xmlCatalogGetSystem	(const xmlChar *sysID);
-const xmlChar *	xmlCatalogGetPublic	(const xmlChar *pubID);
 xmlChar *	xmlCatalogResolve	(const xmlChar *pubID,
 	                                 const xmlChar *sysID);
+xmlChar *	xmlCatalogResolveSystem	(const xmlChar *sysID);
+xmlChar *	xmlCatalogResolvePublic	(const xmlChar *pubID);
 int		xmlCatalogAdd		(const xmlChar *type,
 					 const xmlChar *orig,
 					 const xmlChar *replace);
 int		xmlCatalogRemove	(const xmlChar *value);
 int		xmlCatalogSetDebug	(int level);
+xmlCatalogPrefer xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer);
+
+/* DEPRECATED interfaces */
+const xmlChar *	xmlCatalogGetSystem	(const xmlChar *sysID);
+const xmlChar *	xmlCatalogGetPublic	(const xmlChar *pubID);
 
 #ifdef __cplusplus
 }
diff --git a/parser.c b/parser.c
index 64b55b5..ee68b62 100644
--- a/parser.c
+++ b/parser.c
@@ -10100,5 +10100,8 @@
     xmlParserInitialized = 0;
     xmlCleanupCharEncodingHandlers();
     xmlCleanupPredefinedEntities();
+#ifdef LIBXML_CATALOG_ENABLED
+    xmlCatalogCleanup();
+#endif
 }
 
diff --git a/result/catalogs/docbook b/result/catalogs/docbook
index a5ab6a7..804005d 100644
--- a/result/catalogs/docbook
+++ b/result/catalogs/docbook
@@ -1,4 +1,6 @@
 > /usr/share/xml/docbook/xml/4.1.2/dbpoolx.mod
 > http://www.oasis-open.org/docbook/xml/4.1.2/dbcentx.mod
+> http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd
+> http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd
 > file:///usr/share/xml/toto/toto.dtd
 > 
\ No newline at end of file
diff --git a/result/catalogs/registry b/result/catalogs/registry
new file mode 100644
index 0000000..e035c55
--- /dev/null
+++ b/result/catalogs/registry
@@ -0,0 +1,5 @@
+> /usr/share/xml/docbook/xml/4.1.2/dbpoolx.mod
+> http://www.oasis-open.org/docbook/xml/4.1.2/dbcentx.mod
+> /usr/share/xml/docbook/xml/4.1.2/dbpoolx.mod
+> http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd
+> 
\ No newline at end of file
diff --git a/test/catalogs/docbook.script b/test/catalogs/docbook.script
index 1c606c0..faa06b0 100644
--- a/test/catalogs/docbook.script
+++ b/test/catalogs/docbook.script
@@ -1,3 +1,5 @@
 resolve toto http://www.oasis-open.org/docbook/xml/4.1.2/dbpoolx.mod
 public "-//OASIS//ENTITIES DocBook XML Character Entities V4.1.2//EN"
+system urn:publicid:-:OASIS:DTD+DocBook+XML+V4.1.2:EN
+public urn:publicid:-:OASIS:DTD+DocBook+XML+V4.1.2:EN
 resolve toto toto
diff --git a/test/catalogs/registry.script b/test/catalogs/registry.script
new file mode 100644
index 0000000..9bb944c
--- /dev/null
+++ b/test/catalogs/registry.script
@@ -0,0 +1,4 @@
+resolve toto http://www.oasis-open.org/docbook/xml/4.1.2/dbpoolx.mod
+public "-//OASIS//ENTITIES DocBook XML Character Entities V4.1.2//EN"
+system http://www.oasis-open.org/docbook/xml/4.1.2/dbpoolx.mod
+system urn:publicid:-:OASIS:DTD+DocBook+XML+V4.1.2:EN
diff --git a/test/catalogs/registry.xml b/test/catalogs/registry.xml
new file mode 100644
index 0000000..5caccfc
--- /dev/null
+++ b/test/catalogs/registry.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!DOCTYPE catalog PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN" "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+
+<delegatePublic publicIdStartString="-//OASIS//"
+		catalog="oasis.xml"/>
+<delegateSystem systemIdStartString="http://www.oasis-open.org/"
+                catalog="oasis.xml"/>
+<delegateURI uriStartString="http://www.oasis-open.org/"
+                catalog="oasis.xml"/>
+
+<delegatePublic publicIdStartString="-//OASIS//DTD XML Catalog //"
+		catalog="docbook.xml"/>
+<delegatePublic publicIdStartString="-//OASIS//ENTITIES DocBook XML"
+		catalog="docbook.xml"/>
+<delegatePublic publicIdStartString="-//OASIS//DTD DocBook XML"
+		catalog="docbook.xml"/>
+<delegateSystem systemIdStartString="http://www.oasis-open.org/docbook/"
+		catalog="docbook.xml"/>
+<delegateURI uriStartString="http://www.oasis-open.org/docbook/"
+		catalog="docbook.xml"/>
+
+</catalog>
diff --git a/xmlIO.c b/xmlIO.c
index 981528f..1cfefce 100644
--- a/xmlIO.c
+++ b/xmlIO.c
@@ -2371,7 +2371,10 @@
 xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
                                xmlParserCtxtPtr ctxt) {
     xmlParserInputPtr ret = NULL;
-    const xmlChar *resource = NULL;
+    xmlChar *resource = NULL;
+#ifdef LIBXML_CATALOG_ENABLED
+    struct stat info;
+#endif
 
 #ifdef DEBUG_EXTERNAL_ENTITIES
     xmlGenericError(xmlGenericErrorContext,
@@ -2379,16 +2382,18 @@
 #endif
 #ifdef LIBXML_CATALOG_ENABLED
     /*
-     * Try to load it from the resource pointed in the catalog
+     * If the resource doesn't exists as a file,
+     * try to load it from the resource pointed in the catalog
      */
-    if (ID != NULL)
-	resource = xmlCatalogGetPublic((const xmlChar *)ID);
-    if ((resource == NULL) && (URL != NULL))
-	resource = xmlCatalogGetSystem((const xmlChar *)URL);
+#ifdef HAVE_STAT
+    if ((URL == NULL) || (stat(URL, &info) < 0)) 
+#endif
+	resource = xmlCatalogResolve((const xmlChar *)ID,
+		                     (const xmlChar *)URL);
 #endif
 
     if (resource == NULL)
-	resource = (const xmlChar *)URL;
+	resource = (xmlChar *) URL;
 
     if (resource == NULL) {
 	if ((ctxt->validate) && (ctxt->sax != NULL) && 
@@ -2410,6 +2415,8 @@
 	    ctxt->sax->warning(ctxt,
 		    "failed to load external entity \"%s\"\n", resource);
     }
+    if (resource != (xmlChar *) URL)
+	xmlFree(resource);
     return(ret);
 }
 
diff --git a/xmlcatalog.c b/xmlcatalog.c
index 7758519..eb2fa6a 100644
--- a/xmlcatalog.c
+++ b/xmlcatalog.c
@@ -79,7 +79,6 @@
     char arg[400];
     char *argv[20];
     int i, ret;
-    const xmlChar *answer;
     xmlChar *ans;
 
     while (1) {
@@ -172,22 +171,24 @@
 	    if (nbargs != 1) {
 		printf("public requires 1 arguments\n");
 	    } else {
-		answer = xmlCatalogGetPublic((const xmlChar *) argv[0]);
-		if (answer == NULL) {
+		ans = xmlCatalogResolvePublic((const xmlChar *) argv[0]);
+		if (ans == NULL) {
 		    printf("No entry for PUBLIC %s\n", argv[0]);
 		} else {
-		    printf("%s\n", answer);
+		    printf("%s\n", ans);
+		    xmlFree(ans);
 		}
 	    }
 	} else if (!strcmp(command, "system")) {
 	    if (nbargs != 1) {
 		printf("system requires 1 arguments\n");
 	    } else {
-		answer = xmlCatalogGetSystem((const xmlChar *) argv[0]);
-		if (answer == NULL) {
+		ans = xmlCatalogResolveSystem((const xmlChar *) argv[0]);
+		if (ans == NULL) {
 		    printf("No entry for SYSTEM %s\n", argv[0]);
 		} else {
-		    printf("%s\n", answer);
+		    printf("%s\n", ans);
+		    xmlFree(ans);
 		}
 	    }
 	} else if (!strcmp(command, "add")) {
@@ -231,6 +232,21 @@
 	    } else {
 		xmlCatalogDump(stdout);
 	    }
+	} else if (!strcmp(command, "debug")) {
+	    if (nbargs != 0) {
+		printf("debug has no arguments\n");
+	    } else {
+		verbose++;
+		xmlCatalogSetDebug(verbose);
+	    }
+	} else if (!strcmp(command, "quiet")) {
+	    if (nbargs != 0) {
+		printf("quiet has no arguments\n");
+	    } else {
+		if (verbose > 0)
+		    verbose--;
+		xmlCatalogSetDebug(verbose);
+	    }
 	} else {
 	    if (strcmp(command, "help")) {
 		printf("Unrecognized command %s\n", command);
@@ -242,6 +258,8 @@
 	    printf("\tadd 'type' 'orig' 'replace' : add an entry\n");
 	    printf("\tdel 'values' : remove values\n");
 	    printf("\tdump: print the current catalog state\n");
+	    printf("\tdebug: increase the verbosity level\n");
+	    printf("\tquiet: decrease the verbosity level\n");
 	    printf("\texit:  quit the shell\n");
 	} 
 	free(cmdline); /* not xmlFree here ! */
@@ -254,8 +272,8 @@
  * 									*
  ************************************************************************/
 static void usage(const char *name) {
-    printf("Usage : %s [options] catalogfile\n", name);
-    printf("\tParse the catalog file and output the result of the parsing\n");
+    printf("Usage : %s [options] catalogfile entities...\n", name);
+    printf("\tParse the catalog file and query it for the entities\n");
     printf("\t--shell : run a shell allowing interactive queries\n");
     printf("\t--add 'type' 'orig' 'replace' : add an entry\n");
     printf("\t--del 'values' : remove values\n");
@@ -277,7 +295,7 @@
 	    break;
 
 	if (argv[i][0] != '-')
-	    continue;
+	    break;
 	if ((!strcmp(argv[i], "-verbose")) ||
 	    (!strcmp(argv[i], "-v")) ||
 	    (!strcmp(argv[i], "--verbose"))) {
@@ -360,19 +378,38 @@
 		xmlCatalogDump(out);
 	    }
 	}
-    }
-
-    if (shell) {
+    } else if (shell) {
 	usershell();
-    }
-    if (!noout) {
-	xmlCatalogDump(stdout);
+    } else {
+	for (i++; i < argc; i++) {
+	    xmlURIPtr uri;
+	    xmlChar *ans;
+	    
+	    uri = xmlParseURI(argv[i]);
+	    if (uri == NULL) {
+		ans = xmlCatalogResolvePublic((const xmlChar *) argv[i]);
+		if (ans == NULL) {
+		    printf("No entry for PUBLIC %s\n", argv[i]);
+		} else {
+		    printf("%s\n", ans);
+		    xmlFree(ans);
+		}
+	    } else {
+                xmlFreeURI(uri);
+		ans = xmlCatalogResolveSystem((const xmlChar *) argv[i]);
+		if (ans == NULL) {
+		    printf("No entry for SYSTEM %s\n", argv[i]);
+		} else {
+		    printf("%s\n", ans);
+		    xmlFree(ans);
+		}
+	    }
+	}
     }
 
     /*
      * Cleanup and check for memory leaks
      */
-    xmlCatalogCleanup();
     xmlCleanupParser();
     xmlMemoryDump();
     return(0);
diff --git a/xmllint.c b/xmllint.c
index ba3c48e..c04776e 100644
--- a/xmllint.c
+++ b/xmllint.c
@@ -104,6 +104,10 @@
 static int timing = 0;
 static int generate = 0;
 static struct timeval begin, end;
+#ifdef LIBXML_CATALOG_ENABLED
+static int catalogs = 0;
+static int nocatalogs = 0;
+#endif
 
 /************************************************************************
  * 									*
@@ -798,6 +802,8 @@
     printf("\t--encode encoding : output in the given encoding\n");
 #ifdef LIBXML_CATALOG_ENABLED
     printf("\t--catalogs : use the catalogs from $SGML_CATALOG_FILES\n");
+    printf("\t         otherwise /etc/xml/catalog is activated by default\n");
+    printf("\t--nocatalogs: desactivate all catalogs\n");
 #endif
     printf("\t--auto : generate a small doc on the fly\n");
 #ifdef LIBXML_XINCLUDE_ENABLED
@@ -931,14 +937,10 @@
 #ifdef LIBXML_CATALOG_ENABLED
 	else if ((!strcmp(argv[i], "-catalogs")) ||
 		 (!strcmp(argv[i], "--catalogs"))) {
-	    const char *catalogs;
-
-	    catalogs = getenv("SGML_CATALOG_FILES");
-	    if (catalogs == NULL) {
-		fprintf(stderr, "Variable $SGML_CATALOG_FILES not set\n");
-	    } else {
-		xmlLoadCatalogs(catalogs);
-	    }
+	    catalogs++;
+	} else if ((!strcmp(argv[i], "-nocatalogs")) ||
+		 (!strcmp(argv[i], "--nocatalogs"))) {
+	    nocatalogs++;
 	} 
 #endif
 	else if ((!strcmp(argv[i], "-encode")) ||
@@ -966,6 +968,17 @@
 	    return(1);
 	}
     }
+
+#ifdef LIBXML_CATALOG_ENABLED
+    if (nocatalogs == 0) {
+	if (catalogs) {
+	    const char *catal;
+
+	    catal = getenv("SGML_CATALOG_FILES");
+	    xmlLoadCatalogs(catal);
+	}
+    }
+#endif
     xmlLineNumbersDefault(1);
     if (loaddtd != 0)
 	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;