diff options
author | Daniel Veillard <veillard@src.gnome.org> | 2001-08-20 00:08:40 +0000 |
---|---|---|
committer | Daniel Veillard <veillard@src.gnome.org> | 2001-08-20 00:08:40 +0000 |
commit | 344cee76a675e83ff159ffc02b009f304569ceda (patch) | |
tree | ccb61b9f5893fe0cabb2b0f19bd9a3ea88a3cf32 | |
parent | b7664f444160425950a2a03a38f1b8256d3705e6 (diff) | |
download | libxml2-344cee76a675e83ff159ffc02b009f304569ceda.tar.gz |
renaming testCatalog as xmlcatalog, making it an installed app adding a
* Makefile.am xmlcatalog.c libxml.spec.in: renaming
testCatalog as xmlcatalog, making it an installed app
adding a shell, and preparing it to be a /etc/xml/catalog
management tool, though not ready yet
* catalog.c include/libxml/catalog.h: adding support for
XML Catalogs http://www.oasis-open.org/committees/entity/
not finished, there is some interesting tradeoffs and a
few open questions left.
Daniel
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | Makefile.am | 12 | ||||
-rw-r--r-- | catalog.c | 932 | ||||
-rw-r--r-- | include/libxml/catalog.h | 7 | ||||
-rw-r--r-- | libxml.spec.in | 1 | ||||
-rw-r--r-- | testCatalog.c | 33 | ||||
-rw-r--r-- | xmlIO.c | 2 | ||||
-rw-r--r-- | xmlcatalog.c | 216 |
8 files changed, 1089 insertions, 125 deletions
@@ -1,3 +1,14 @@ +Mon Aug 20 02:04:13 CEST 2001 Daniel Veillard <daniel@veillard.com> + + * Makefile.am xmlcatalog.c libxml.spec.in: renaming + testCatalog as xmlcatalog, making it an installed app + adding a shell, and preparing it to be a /etc/xml/catalog + management tool, though not ready yet + * catalog.c include/libxml/catalog.h: adding support for + XML Catalogs http://www.oasis-open.org/committees/entity/ + not finished, there is some interesting tradeoffs and a + few open questions left. + Sun Aug 19 14:59:56 CEST 2001 Daniel Veillard <daniel@veillard.com> * xmllint.c: fixed a line formatting problem diff --git a/Makefile.am b/Makefile.am index 4331d65e..2e1d622c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,9 +7,9 @@ SUBDIRS = include . doc example INCLUDES = -I@srcdir@/include -I$(top_builddir)/include @Z_CFLAGS@ -noinst_PROGRAMS=testSAX testHTML testXPath testURI testDocbook testCatalog +noinst_PROGRAMS=testSAX testHTML testXPath testURI testDocbook -bin_PROGRAMS = xmllint +bin_PROGRAMS = xmllint xmlcatalog bin_SCRIPTS=xml2-config @@ -62,10 +62,10 @@ testDocbook_LDFLAGS = testDocbook_DEPENDENCIES = $(DEPS) testDocbook_LDADD= $(LDADDS) -testCatalog_SOURCES=testCatalog.c -testCatalog_LDFLAGS = -testCatalog_DEPENDENCIES = $(DEPS) -testCatalog_LDADD= $(LDADDS) +xmlcatalog_SOURCES=xmlcatalog.c +xmlcatalog_LDFLAGS = +xmlcatalog_DEPENDENCIES = $(DEPS) +xmlcatalog_LDADD= $(LDADDS) testXPath_SOURCES=testXPath.c testXPath_LDFLAGS = @@ -4,6 +4,9 @@ * Reference: SGML Open Technical Resolution TR9401:1997. * http://www.jclark.com/sp/catalog.htm * + * XML Catalogs Working Draft 06 August 2001 + * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html + * * See Copyright for the status of this software. * * Daniel.Veillard@imag.fr @@ -32,6 +35,17 @@ #include <libxml/catalog.h> #include <libxml/xmlerror.h> +/** + * TODO: + * + * macro to flag unimplemented blocks + */ +#define TODO \ + xmlGenericError(xmlGenericErrorContext, \ + "Unimplemented block at %s:%d\n", \ + __FILE__, __LINE__); + + /************************************************************************ * * * Types, all private * @@ -39,36 +53,57 @@ ************************************************************************/ typedef enum { + XML_CATA_PREFER_PUBLIC = 1, + XML_CATA_PREFER_SYSTEM +} xmlCatalogPrefer; + +typedef enum { XML_CATA_NONE = 0, - XML_CATA_SYSTEM, - XML_CATA_PUBLIC, - XML_CATA_ENTITY, - XML_CATA_PENTITY, - XML_CATA_DOCTYPE, - XML_CATA_LINKTYPE, - XML_CATA_NOTATION, - XML_CATA_DELEGATE, - XML_CATA_BASE, XML_CATA_CATALOG, - XML_CATA_DOCUMENT, - XML_CATA_SGMLDECL + XML_CATA_NEXT_CATALOG, + XML_CATA_PUBLIC, + XML_CATA_SYSTEM, + XML_CATA_REWRITE_SYSTEM, + XML_CATA_DELEGATE_PUBLIC, + XML_CATA_DELEGATE_SYSTEM, + XML_CATA_URI, + XML_CATA_REWRITE_URI, + XML_CATA_DELEGATE_URI, + SGML_CATA_SYSTEM, + SGML_CATA_PUBLIC, + SGML_CATA_ENTITY, + SGML_CATA_PENTITY, + SGML_CATA_DOCTYPE, + SGML_CATA_LINKTYPE, + SGML_CATA_NOTATION, + SGML_CATA_DELEGATE, + SGML_CATA_BASE, + SGML_CATA_CATALOG, + SGML_CATA_DOCUMENT, + SGML_CATA_SGMLDECL } xmlCatalogEntryType; typedef struct _xmlCatalogEntry xmlCatalogEntry; typedef xmlCatalogEntry *xmlCatalogEntryPtr; struct _xmlCatalogEntry { + struct _xmlCatalogEntry *next; + struct _xmlCatalogEntry *parent; + struct _xmlCatalogEntry *children; xmlCatalogEntryType type; xmlChar *name; xmlChar *value; }; static xmlHashTablePtr xmlDefaultCatalog; +static xmlCatalogEntryPtr xmlDefaultXMLCatalogList = NULL; /* Catalog stack */ static const char * catalTab[10]; /* stack of catals */ static int catalNr = 0; /* Number of current catal streams */ static int catalMax = 10; /* Max number of catal streams */ +static int xmlDebugCatalogs = 0; /* used for debugging */ + /************************************************************************ * * * alloc or dealloc * @@ -76,7 +111,8 @@ static int catalMax = 10; /* Max number of catal streams */ ************************************************************************/ static xmlCatalogEntryPtr -xmlNewCatalogEntry(int type, xmlChar *name, xmlChar *value) { +xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name, + const xmlChar *value) { xmlCatalogEntryPtr ret; ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry)); @@ -85,16 +121,30 @@ xmlNewCatalogEntry(int type, xmlChar *name, xmlChar *value) { "malloc of %d byte failed\n", sizeof(xmlCatalogEntry)); return(NULL); } + ret->next = NULL; + ret->parent = NULL; + ret->children = NULL; ret->type = type; - ret->name = xmlStrdup(name); - ret->value = xmlStrdup(value); + if (name != NULL) + ret->name = xmlStrdup(name); + else + ret->name = NULL; + if (value != NULL) + ret->value = xmlStrdup(value); + else + ret->value = NULL; return(ret); } static void +xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret); + +static void xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) { if (ret == NULL) return; + if (ret->children != NULL) + xmlFreeCatalogEntryList(ret->children); if (ret->name != NULL) xmlFree(ret->name); if (ret->value != NULL) @@ -102,6 +152,17 @@ xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) { xmlFree(ret); } +static void +xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) { + xmlCatalogEntryPtr next; + + while (ret != NULL) { + next = ret->next; + xmlFreeCatalogEntry(ret); + ret = next; + } +} + /** * xmlCatalogDumpEntry: * @entry: the @@ -114,60 +175,60 @@ xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) { if ((entry == NULL) || (out == NULL)) return; switch (entry->type) { - case XML_CATA_ENTITY: + case SGML_CATA_ENTITY: fprintf(out, "ENTITY "); break; - case XML_CATA_PENTITY: + case SGML_CATA_PENTITY: fprintf(out, "ENTITY %%"); break; - case XML_CATA_DOCTYPE: + case SGML_CATA_DOCTYPE: fprintf(out, "DOCTYPE "); break; - case XML_CATA_LINKTYPE: + case SGML_CATA_LINKTYPE: fprintf(out, "LINKTYPE "); break; - case XML_CATA_NOTATION: + case SGML_CATA_NOTATION: fprintf(out, "NOTATION "); break; - case XML_CATA_PUBLIC: + case SGML_CATA_PUBLIC: fprintf(out, "PUBLIC "); break; - case XML_CATA_SYSTEM: + case SGML_CATA_SYSTEM: fprintf(out, "SYSTEM "); break; - case XML_CATA_DELEGATE: + case SGML_CATA_DELEGATE: fprintf(out, "DELEGATE "); break; - case XML_CATA_BASE: + case SGML_CATA_BASE: fprintf(out, "BASE "); break; - case XML_CATA_CATALOG: + case SGML_CATA_CATALOG: fprintf(out, "CATALOG "); break; - case XML_CATA_DOCUMENT: + case SGML_CATA_DOCUMENT: fprintf(out, "DOCUMENT "); break; - case XML_CATA_SGMLDECL: + case SGML_CATA_SGMLDECL: fprintf(out, "SGMLDECL "); break; default: return; } switch (entry->type) { - case XML_CATA_ENTITY: - case XML_CATA_PENTITY: - case XML_CATA_DOCTYPE: - case XML_CATA_LINKTYPE: - case XML_CATA_NOTATION: + case SGML_CATA_ENTITY: + case SGML_CATA_PENTITY: + case SGML_CATA_DOCTYPE: + case SGML_CATA_LINKTYPE: + case SGML_CATA_NOTATION: fprintf(out, "%s", entry->name); break; - case XML_CATA_PUBLIC: - case XML_CATA_SYSTEM: - case XML_CATA_SGMLDECL: - case XML_CATA_DOCUMENT: - case XML_CATA_CATALOG: - case XML_CATA_BASE: - case XML_CATA_DELEGATE: + case SGML_CATA_PUBLIC: + case SGML_CATA_SYSTEM: + case SGML_CATA_SGMLDECL: + case SGML_CATA_DOCUMENT: + case SGML_CATA_CATALOG: + case SGML_CATA_BASE: + case SGML_CATA_DELEGATE: fprintf(out, "\"%s\"", entry->name); break; default: break; } switch (entry->type) { - case XML_CATA_ENTITY: - case XML_CATA_PENTITY: - case XML_CATA_DOCTYPE: - case XML_CATA_LINKTYPE: - case XML_CATA_NOTATION: - case XML_CATA_PUBLIC: - case XML_CATA_SYSTEM: - case XML_CATA_DELEGATE: + case SGML_CATA_ENTITY: + case SGML_CATA_PENTITY: + case SGML_CATA_DOCTYPE: + case SGML_CATA_LINKTYPE: + case SGML_CATA_NOTATION: + case SGML_CATA_PUBLIC: + case SGML_CATA_SYSTEM: + case SGML_CATA_DELEGATE: fprintf(out, " \"%s\"", entry->value); break; default: break; @@ -177,7 +238,498 @@ xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) { /************************************************************************ * * - * The parser * + * The XML Catalog parser * + * * + ************************************************************************/ + +static xmlCatalogEntryPtr +xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename); + +static xmlCatalogEntryPtr +xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer, + const char *file); +static void +xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer, + xmlCatalogEntryPtr parent); + +static xmlCatalogEntryType +xmlGetXMLCatalogEntryType(const xmlChar *name) { + xmlCatalogEntryType type = XML_CATA_NONE; + if (xmlStrEqual(name, (const xmlChar *) "system")) + type = XML_CATA_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "public")) + type = XML_CATA_PUBLIC; + else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem")) + type = XML_CATA_REWRITE_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic")) + type = XML_CATA_DELEGATE_PUBLIC; + else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem")) + type = XML_CATA_DELEGATE_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "uri")) + type = XML_CATA_URI; + else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI")) + type = XML_CATA_REWRITE_URI; + else if (xmlStrEqual(name, (const xmlChar *) "delegateURI")) + type = XML_CATA_DELEGATE_URI; + else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog")) + type = XML_CATA_NEXT_CATALOG; + else if (xmlStrEqual(name, (const xmlChar *) "catalog")) + type = XML_CATA_CATALOG; + return(type); +} + +static xmlCatalogEntryPtr +xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type, + const xmlChar *name, const xmlChar *attrName, + const xmlChar *uriAttrName) { + int ok = 1; + xmlChar *uriValue; + xmlChar *nameValue = NULL; + xmlChar *base = NULL; + xmlChar *URL = NULL; + xmlCatalogEntryPtr ret = NULL; + + if (attrName != NULL) { + nameValue = xmlGetProp(cur, attrName); + if (nameValue == NULL) { + xmlGenericError(xmlGenericErrorContext, + "%s entry lacks '%s'\n", name, attrName); + ok = 0; + } + } + uriValue = xmlGetProp(cur, uriAttrName); + if (uriValue == NULL) { + xmlGenericError(xmlGenericErrorContext, + "%s entry lacks '%s'\n", name, uriAttrName); + ok = 0; + } + if (!ok) { + if (nameValue != NULL) + xmlFree(nameValue); + if (uriValue != NULL) + xmlFree(uriValue); + return(NULL); + } + + base = xmlNodeGetBase(cur->doc, cur); + URL = xmlBuildURI(uriValue, base); + if (URL != NULL) { + if (xmlDebugCatalogs) { + if (nameValue != NULL) + printf("Found %s: '%s' '%s'\n", name, nameValue, URL); + else + printf("Found %s: '%s'\n", name, URL); + } + ret = xmlNewCatalogEntry(type, nameValue, URL); + } else { + xmlGenericError(xmlGenericErrorContext, + "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue); + } + if (nameValue != NULL) + xmlFree(nameValue); + if (uriValue != NULL) + xmlFree(uriValue); + if (base != NULL) + xmlFree(base); + if (URL != NULL) + xmlFree(URL); + return(ret); +} + +static void +xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer, + xmlCatalogEntryPtr parent) +{ + xmlChar *uri = NULL; + xmlChar *URL = NULL; + xmlChar *base = NULL; + xmlCatalogEntryPtr entry = NULL; + + if (cur == NULL) + return; + if (xmlStrEqual(cur->name, BAD_CAST "group")) { + xmlChar *prop; + + prop = xmlGetProp(cur, BAD_CAST "prefer"); + if (prop != NULL) { + if (xmlStrEqual(prop, BAD_CAST "system")) { + prefer = XML_CATA_PREFER_SYSTEM; + } else if (xmlStrEqual(prop, BAD_CAST "public")) { + prefer = XML_CATA_PREFER_PUBLIC; + } else { + xmlGenericError(xmlGenericErrorContext, + "Invalid value for prefer: '%s'\n", prop); + } + xmlFree(prop); + } + /* + * Recurse to propagate prefer to the subtree + * (xml:base handling is automated) + */ + 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"); + } else if (xmlStrEqual(cur->name, BAD_CAST "system")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM, + BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri"); + } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM, + BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString", + BAD_CAST "rewritePrefix"); + } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC, + BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString", + BAD_CAST "catalog"); + } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM, + BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString", + BAD_CAST "catalog"); + } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI, + BAD_CAST "uri", BAD_CAST "name", + BAD_CAST "uri"); + } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI, + BAD_CAST "rewriteURI", BAD_CAST "uriStartString", + BAD_CAST "rewritePrefix"); + } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI, + BAD_CAST "delegateURI", BAD_CAST "uriStartString", + BAD_CAST "catalog"); + } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG, + BAD_CAST "nextCatalog", NULL, + BAD_CAST "catalog"); + } + if ((entry != NULL) && (parent != NULL)) { + entry->parent = parent; + if (parent->children == NULL) + parent->children = entry; + else { + xmlCatalogEntryPtr prev; + + prev = parent->children; + while (prev->next != NULL) + prev = prev->next; + prev->next = entry; + } + } + if (base != NULL) + xmlFree(base); + if (uri != NULL) + xmlFree(uri); + if (URL != NULL) + xmlFree(URL); +} + +static void +xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer, + xmlCatalogEntryPtr parent) { + while (cur != NULL) { + if ((cur->ns != NULL) && (cur->ns->href != NULL) && + (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) { + xmlParseXMLCatalogNode(cur, prefer, parent); + } + cur = cur->next; + } + /* TODO: sort the list according to REWRITE lengths and prefer value */ +} + +static xmlCatalogEntryPtr +xmlParseXMLCatalog(const xmlChar *value, xmlCatalogPrefer prefer, + const char *file) { + xmlDocPtr doc; + xmlNodePtr cur; + xmlChar *prop; + xmlCatalogEntryPtr parent = NULL; + + if ((value == NULL) || (file == NULL)) + return(NULL); + + doc = xmlParseDoc((xmlChar *) value); + if (doc == NULL) + return(NULL); + doc->URL = xmlStrdup((const xmlChar *) file); + + 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 *)file, NULL); + if (parent == NULL) { + xmlFreeDoc(doc); + return(NULL); + } + + prop = xmlGetProp(cur, BAD_CAST "prefer"); + if (prop != NULL) { + if (xmlStrEqual(prop, BAD_CAST "system")) { + prefer = XML_CATA_PREFER_SYSTEM; + } else if (xmlStrEqual(prop, BAD_CAST "public")) { + prefer = XML_CATA_PREFER_PUBLIC; + } else { + xmlGenericError(xmlGenericErrorContext, + "Invalid value for prefer: '%s'\n", + prop); + } + xmlFree(prop); + } + cur = cur->children; + xmlParseXMLCatalogNodeList(cur, prefer, parent); + } else { + xmlGenericError(xmlGenericErrorContext, + "File %s is not an XML Catalog\n", file); + xmlFreeDoc(doc); + return(NULL); + } + xmlFreeDoc(doc); + return(parent); +} + +static xmlCatalogEntryPtr +xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) { + xmlDocPtr doc; + xmlNodePtr cur; + xmlChar *prop; + xmlCatalogEntryPtr parent = NULL; + + if (filename == NULL) + return(NULL); + + doc = xmlParseFile((const char *) filename); + if (doc == NULL) + return(NULL); + + 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); + if (parent == NULL) { + xmlFreeDoc(doc); + return(NULL); + } + + prop = xmlGetProp(cur, BAD_CAST "prefer"); + if (prop != NULL) { + if (xmlStrEqual(prop, BAD_CAST "system")) { + prefer = XML_CATA_PREFER_SYSTEM; + } else if (xmlStrEqual(prop, BAD_CAST "public")) { + prefer = XML_CATA_PREFER_PUBLIC; + } else { + xmlGenericError(xmlGenericErrorContext, + "Invalid value for prefer: '%s'\n", + prop); + } + xmlFree(prop); + } + cur = cur->children; + xmlParseXMLCatalogNodeList(cur, prefer, parent); + } else { + xmlGenericError(xmlGenericErrorContext, + "File %s is not an XML Catalog\n", filename); + xmlFreeDoc(doc); + return(NULL); + } + xmlFreeDoc(doc); + return(parent); +} + +static int +xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) { + int ret; + xmlDocPtr doc; + xmlNsPtr ns; + xmlDtdPtr dtd; + xmlNodePtr node, catalog; + xmlOutputBufferPtr buf; + xmlCatalogEntryPtr cur; + + /* + * Rebuild a catalog + */ + doc = xmlNewDoc(NULL); + if (doc == NULL) + return(-1); + dtd = xmlNewDtd(doc, BAD_CAST "catalog", + BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN", +BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd"); + + xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd); + + ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL); + if (ns == NULL) { + xmlFreeDoc(doc); + return(-1); + } + catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL); + if (catalog == NULL) { + xmlFreeNs(ns); + xmlFreeDoc(doc); + return(-1); + } + catalog->nsDef = ns; + xmlAddChild((xmlNodePtr) doc, catalog); + + /* + * add all the catalog entries + */ + cur = catal; + while (cur != NULL) { + switch (cur->type) { + case XML_CATA_CATALOG: + if (cur == catal) { + cur = cur->children; + continue; + } + break; + case XML_CATA_NEXT_CATALOG: + node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL); + xmlSetProp(node, BAD_CAST "catalog", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_NONE: + break; + case XML_CATA_PUBLIC: + node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL); + xmlSetProp(node, BAD_CAST "publicId", cur->name); + xmlSetProp(node, BAD_CAST "uri", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_SYSTEM: + node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL); + xmlSetProp(node, BAD_CAST "systemId", cur->name); + xmlSetProp(node, BAD_CAST "uri", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_REWRITE_SYSTEM: + node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL); + xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name); + xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_DELEGATE_PUBLIC: + node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL); + xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name); + xmlSetProp(node, BAD_CAST "catalog", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_DELEGATE_SYSTEM: + node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL); + xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name); + xmlSetProp(node, BAD_CAST "catalog", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_URI: + node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL); + xmlSetProp(node, BAD_CAST "name", cur->name); + xmlSetProp(node, BAD_CAST "uri", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_REWRITE_URI: + node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL); + xmlSetProp(node, BAD_CAST "uriStartString", cur->name); + xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_DELEGATE_URI: + node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL); + xmlSetProp(node, BAD_CAST "uriStartString", cur->name); + xmlSetProp(node, BAD_CAST "catalog", cur->value); + xmlAddChild(catalog, node); + break; + 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: + break; + } + cur = cur->next; + } + + /* + * reserialize it + */ + buf = xmlOutputBufferCreateFile(out, NULL); + if (buf == NULL) { + xmlFreeDoc(doc); + return(-1); + } + ret = xmlSaveFormatFileTo(buf, doc, NULL, 1); + + /* + * Free it + */ + xmlFreeDoc(doc); + + return(ret); +} + +/** + * xmlAddXMLCatalog: + * @catal: top of an XML catalog + * @type: the type of record to add to the catalog + * @orig: the system, public or prefix to match + * @replace: the replacement value for the match + * + * Add an entry in the XML catalog, it may overwrite existing but + * different entries. + * + * Returns 0 if successful, -1 otherwise + */ +static int +xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type, + const xmlChar *orig, const xmlChar *replace) { + xmlCatalogEntryPtr cur; + xmlCatalogEntryType typ; + + if ((catal == NULL) || (catal->type != XML_CATA_CATALOG)) + return(-1); + typ = xmlGetXMLCatalogEntryType(type); + if (typ == XML_CATA_NONE) + return(-1); + + cur = catal->children; + /* + * Might be a simple "update in place" + */ + if (cur != NULL) { + while (cur != NULL) { + cur = cur->next; + if ((cur->type == typ) && (xmlStrEqual(orig, cur->name))) { + if (cur->value != NULL) + xmlFree(cur->value); + cur->value = xmlStrdup(replace); + return(1); + } + if (cur->next == NULL) + break; + cur = cur->next; + } + } + if (cur == NULL) + catal->children = xmlNewCatalogEntry(typ, orig, replace); + else + cur->next = xmlNewCatalogEntry(typ, orig, replace); + return(1); +} + +/************************************************************************ + * * + * The SGML Catalog parser * * * ************************************************************************/ @@ -290,6 +842,36 @@ xmlParseCatalogName(const xmlChar *cur, xmlChar **name) { return(cur); } +static xmlCatalogEntryType +xmlGetCatalogEntryType(const xmlChar *name) { + xmlCatalogEntryType type = XML_CATA_NONE; + if (xmlStrEqual(name, (const xmlChar *) "SYSTEM")) + type = SGML_CATA_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC")) + type = SGML_CATA_PUBLIC; + else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) + type = SGML_CATA_DELEGATE; + else if (xmlStrEqual(name, (const xmlChar *) "ENTITY")) + type = SGML_CATA_ENTITY; + else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE")) + type = SGML_CATA_DOCTYPE; + else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE")) + type = SGML_CATA_LINKTYPE; + else if (xmlStrEqual(name, (const xmlChar *) "NOTATION")) + type = SGML_CATA_NOTATION; + else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL")) + type = SGML_CATA_SGMLDECL; + else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT")) + type = SGML_CATA_DOCUMENT; + else if (xmlStrEqual(name, (const xmlChar *) "CATALOG")) + type = SGML_CATA_CATALOG; + else if (xmlStrEqual(name, (const xmlChar *) "BASE")) + type = SGML_CATA_BASE; + else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) + type = SGML_CATA_DELEGATE; + return(type); +} + static int xmlParseCatalog(const xmlChar *value, const char *file) { const xmlChar *cur = value; @@ -324,29 +906,29 @@ xmlParseCatalog(const xmlChar *value, const char *file) { } SKIP_BLANKS; if (xmlStrEqual(name, (const xmlChar *) "SYSTEM")) - type = XML_CATA_SYSTEM; + type = SGML_CATA_SYSTEM; else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC")) - type = XML_CATA_PUBLIC; + type = SGML_CATA_PUBLIC; else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) - type = XML_CATA_DELEGATE; + type = SGML_CATA_DELEGATE; else if (xmlStrEqual(name, (const xmlChar *) "ENTITY")) - type = XML_CATA_ENTITY; + type = SGML_CATA_ENTITY; else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE")) - type = XML_CATA_DOCTYPE; + type = SGML_CATA_DOCTYPE; else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE")) - type = XML_CATA_LINKTYPE; + type = SGML_CATA_LINKTYPE; else if (xmlStrEqual(name, (const xmlChar *) "NOTATION")) - type = XML_CATA_NOTATION; + type = SGML_CATA_NOTATION; else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL")) - type = XML_CATA_SGMLDECL; + type = SGML_CATA_SGMLDECL; else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT")) - type = XML_CATA_DOCUMENT; + type = SGML_CATA_DOCUMENT; else if (xmlStrEqual(name, (const xmlChar *) "CATALOG")) - type = XML_CATA_CATALOG; + type = SGML_CATA_CATALOG; else if (xmlStrEqual(name, (const xmlChar *) "BASE")) - type = XML_CATA_BASE; + type = SGML_CATA_BASE; else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) - type = XML_CATA_DELEGATE; + type = SGML_CATA_DELEGATE; else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) { xmlFree(name); cur = xmlParseCatalogName(cur, &name); @@ -361,13 +943,13 @@ xmlParseCatalog(const xmlChar *value, const char *file) { name = NULL; switch(type) { - case XML_CATA_ENTITY: + case SGML_CATA_ENTITY: if (*cur == '%') - type = XML_CATA_PENTITY; - case XML_CATA_PENTITY: - case XML_CATA_DOCTYPE: - case XML_CATA_LINKTYPE: - case XML_CATA_NOTATION: + type = SGML_CATA_PENTITY; + case SGML_CATA_PENTITY: + case SGML_CATA_DOCTYPE: + case SGML_CATA_LINKTYPE: + case SGML_CATA_NOTATION: cur = xmlParseCatalogName(cur, &name); if (cur == NULL) { /* error */ @@ -384,9 +966,9 @@ xmlParseCatalog(const xmlChar *value, const char *file) { break; } break; - case XML_CATA_PUBLIC: - case XML_CATA_SYSTEM: - case XML_CATA_DELEGATE: + case SGML_CATA_PUBLIC: + case SGML_CATA_SYSTEM: + case SGML_CATA_DELEGATE: cur = xmlParseCatalogPubid(cur, &name); if (cur == NULL) { /* error */ @@ -403,10 +985,10 @@ xmlParseCatalog(const xmlChar *value, const char *file) { break; } break; - case XML_CATA_BASE: - case XML_CATA_CATALOG: - case XML_CATA_DOCUMENT: - case XML_CATA_SGMLDECL: + case SGML_CATA_BASE: + case SGML_CATA_CATALOG: + case SGML_CATA_DOCUMENT: + case SGML_CATA_SGMLDECL: cur = xmlParseCatalogPubid(cur, &sysid); if (cur == NULL) { /* error */ @@ -422,12 +1004,12 @@ xmlParseCatalog(const xmlChar *value, const char *file) { if (sysid != NULL) xmlFree(sysid); break; - } else if (type == XML_CATA_BASE) { + } else if (type == SGML_CATA_BASE) { if (base != NULL) xmlFree(base); base = xmlStrdup(sysid); - } else if ((type == XML_CATA_PUBLIC) || - (type == XML_CATA_SYSTEM)) { + } else if ((type == SGML_CATA_PUBLIC) || + (type == SGML_CATA_SYSTEM)) { xmlChar *filename; filename = xmlBuildURI(sysid, base); @@ -442,7 +1024,7 @@ xmlParseCatalog(const xmlChar *value, const char *file) { xmlFree(filename); } - } else if (type == XML_CATA_CATALOG) { + } else if (type == SGML_CATA_CATALOG) { xmlChar *filename; filename = xmlBuildURI(sysid, base); @@ -542,7 +1124,27 @@ xmlLoadCatalog(const char *filename) { content[len] = 0; close(fd); - ret = xmlParseCatalog(content, filename); + if ((content[0] == ' ') || (content[0] == '-') || + ((content[0] >= 'A') && (content[0] <= 'Z')) || + ((content[0] >= 'a') && (content[0] <= 'z'))) + ret = xmlParseCatalog(content, filename); + else { + xmlCatalogEntryPtr catal, tmp; + /* TODO: allow to switch the default preference */ + catal = xmlParseXMLCatalog(content, XML_CATA_PREFER_PUBLIC, filename); + if (catal != NULL) { + if (xmlDefaultXMLCatalogList == NULL) + xmlDefaultXMLCatalogList = catal; + else { + tmp = xmlDefaultXMLCatalogList; + while (tmp->next != NULL) + tmp = tmp->next; + tmp->next = catal; + } + ret = 0; + } else + ret = -1; + } xmlFree(content); catalNr--; return(ret); @@ -611,13 +1213,14 @@ xmlCatalogGetSystem(const xmlChar *sysID) { entry = (xmlCatalogEntryPtr) xmlHashLookup(xmlDefaultCatalog, sysID); if (entry == NULL) return(NULL); - if (entry->type == XML_CATA_SYSTEM) + if (entry->type == SGML_CATA_SYSTEM) return(entry->value); return(NULL); } /** - * xmlCatalogGetPublic: + * xmlCatalogGetXMLPublic: + * @catal: an XML catalog * @pubId: the public ID string * * Try to lookup the system ID associated to a public ID @@ -625,18 +1228,112 @@ xmlCatalogGetSystem(const xmlChar *sysID) { * Returns the system ID if found or NULL otherwise. */ const xmlChar * -xmlCatalogGetPublic(const xmlChar *pubID) { +xmlCatalogGetXMLPublic(xmlCatalogEntryPtr catal, const xmlChar *pubID) { + const xmlChar *ret; + while (catal != NULL) { + switch (catal->type) { + case XML_CATA_CATALOG: + if (catal->children == NULL) { + TODO /* fetch and fill */ + } + ret = xmlCatalogGetXMLPublic(catal->children, pubID); + if (ret != NULL) + return(ret); + break; + case XML_CATA_NEXT_CATALOG: + if (catal->children == NULL) { + TODO /* fetch and fill */ + } + 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); +} + +/** + * xmlCatalogGetSGMLPublic: + * @catal: an SGML catalog hash + * @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 * +xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) { xmlCatalogEntryPtr entry; - if ((pubID == NULL) || (xmlDefaultCatalog == NULL)) + if (catal == NULL) return(NULL); - entry = (xmlCatalogEntryPtr) xmlHashLookup(xmlDefaultCatalog, pubID); + + entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID); if (entry == NULL) return(NULL); - if (entry->type == XML_CATA_PUBLIC) + if (entry->type == SGML_CATA_PUBLIC) return(entry->value); return(NULL); } + +/** + * xmlCatalogGetPublic: + * @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. + */ +const xmlChar * +xmlCatalogGetPublic(const xmlChar *pubID) { + xmlCatalogEntryPtr catal; + const xmlChar *ret; + + if (pubID == NULL) + return(NULL); + + /* + * Check first the XML catalogs + */ + catal = xmlDefaultXMLCatalogList; + if (catal != NULL) { + ret = xmlCatalogGetXMLPublic(catal, pubID); + if (ret != NULL) + return(ret); + } + + if (xmlDefaultCatalog != NULL) + return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog, pubID)); + return(NULL); +} + /** * xmlCatalogDump: * @out: the file. @@ -647,9 +1344,74 @@ void xmlCatalogDump(FILE *out) { if (out == NULL) return; - if (xmlDefaultCatalog != NULL) { + + if (xmlDefaultXMLCatalogList != NULL) { + xmlDumpXMLCatalog(out, xmlDefaultXMLCatalogList); + } else if (xmlDefaultCatalog != NULL) { xmlHashScan(xmlDefaultCatalog, (xmlHashScanner) xmlCatalogDumpEntry, out); - } + } +} + +/** + * xmlCatalogAdd: + * @type: the type of record to add to the catalog + * @orig: the system, public or prefix to match + * @replace: the replacement value for the match + * + * Add an entry in the catalog, it may overwrite existing but + * different entries. + * + * Returns 0 if successful, -1 otherwise + */ +int +xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) { + int res = -1; + + if (xmlDefaultXMLCatalogList != NULL) { + res = xmlAddXMLCatalog(xmlDefaultXMLCatalogList, type, orig, replace); + } else if (xmlDefaultCatalog != NULL) { + xmlCatalogEntryType typ; + + typ = xmlGetCatalogEntryType(type); + if (type != XML_CATA_NONE) { + xmlCatalogEntryPtr entry; + entry = xmlNewCatalogEntry(typ, orig, replace); + res = xmlHashAddEntry(xmlDefaultCatalog, orig, entry); + } + } + return(res); +} + +/** + * xmlCatalogRemove: + * @value: the value to remove + * + * Remove an entry from the catalog + * + * Returns 0 if successful, -1 otherwise + */ +int +xmlCatalogRemove(const xmlChar *value) { +} + +/** + * xmlCatalogSetDebug: + * @level: the debug level of catalogs required + * + * Used to set the debug level for catalog operation, 0 disable + * debugging, 1 enable it + * + * Returns the previous value of the catalog debugging level + */ +int +xmlCatalogSetDebug(int level) { + int ret = xmlDebugCatalogs; + + if (level <= 0) + xmlDebugCatalogs = 0; + else + xmlDebugCatalogs = level; + return(ret); } #endif /* LIBXML_CATALOG_ENABLED */ diff --git a/include/libxml/catalog.h b/include/libxml/catalog.h index 504b2e6c..1a62bb2a 100644 --- a/include/libxml/catalog.h +++ b/include/libxml/catalog.h @@ -42,6 +42,13 @@ void xmlCatalogCleanup (void); void xmlCatalogDump (FILE *out); const xmlChar * xmlCatalogGetSystem (const xmlChar *sysID); const xmlChar * xmlCatalogGetPublic (const xmlChar *pubID); +const xmlChar * xmlCatalogResolve (const xmlChar *pubID, + const xmlChar *sysID); +int xmlCatalogAdd (const xmlChar *type, + const xmlChar *orig, + const xmlChar *replace); +int xmlCatalogRemove (const xmlChar *value); +int xmlCatalogSetDebug (int level); #ifdef __cplusplus } diff --git a/libxml.spec.in b/libxml.spec.in index 56aadadf..efef779b 100644 --- a/libxml.spec.in +++ b/libxml.spec.in @@ -122,6 +122,7 @@ rm -rf $RPM_BUILD_ROOT %{prefix}/lib/lib*.so.* %{prefix}/bin/xmllint +%{prefix}/bin/xmlcatalog %files devel %defattr(-, root, root) diff --git a/testCatalog.c b/testCatalog.c deleted file mode 100644 index d7bc4c72..00000000 --- a/testCatalog.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * testCatalog.c : a small tester program for Catalog loading - * - * See Copyright for the status of this software. - * - * daniel@veillard.com - */ - -#include "libxml.h" - -#include <string.h> -#include <stdio.h> -#include <stdarg.h> - -#include <libxml/xmlmemory.h> -#include <libxml/uri.h> -#include <libxml/catalog.h> -#include <libxml/parser.h> - -int main(int argc, char **argv) { -#ifdef LIBXML_CATALOG_ENABLED - int i; - - for (i = 1; i < argc; i++) - xmlLoadCatalog(argv[i]); - - xmlCatalogDump(stdout); - xmlCatalogCleanup(); - xmlCleanupParser(); - xmlMemoryDump(); -#endif - return(0); -} @@ -3,7 +3,7 @@ * * See Copyright for the status of this software. * - * Daniel.Veillard@w3.org + * daniel@veillard.com * * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char */ diff --git a/xmlcatalog.c b/xmlcatalog.c new file mode 100644 index 00000000..0063bcab --- /dev/null +++ b/xmlcatalog.c @@ -0,0 +1,216 @@ +/* + * xmlcatalog.c : a small utility program to handle XML catalogs + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#include "libxml.h" + +#include <string.h> +#include <stdio.h> +#include <stdarg.h> + +#include <libxml/xmlmemory.h> +#include <libxml/uri.h> +#include <libxml/catalog.h> +#include <libxml/parser.h> + +static int shell = 0; +static int noout = 0; +static int verbose = 0; + +#ifdef LIBXML_CATALOG_ENABLED +/************************************************************************ + * * + * Shell Interface * + * * + ************************************************************************/ +/** + * xmlShellReadline: + * @prompt: the prompt value + * + * Read a string + * + * Returns a pointer to it or NULL on EOF the caller is expected to + * free the returned string. + */ +static char * +xmlShellReadline(const char *prompt) { +#ifdef HAVE_LIBREADLINE + char *line_read; + + /* Get a line from the user. */ + line_read = readline (prompt); + + /* If the line has any text in it, save it on the history. */ + if (line_read && *line_read) + add_history (line_read); + + return (line_read); +#else + char line_read[501]; + + if (prompt != NULL) + fprintf(stdout, "%s", prompt); + if (!fgets(line_read, 500, stdin)) + return(NULL); + line_read[500] = 0; + return(strdup(line_read)); +#endif +} + + +static void usershell(void) { + char *cmdline = NULL, *cur; + int nbargs; + char command[100]; + char arg[400]; + int i; + const xmlChar *answer; + + while (1) { + cmdline = xmlShellReadline("> "); + if (cmdline == NULL) + return; + + /* + * Parse the command itself + */ + cur = cmdline; + nbargs = 0; + while ((*cur == ' ') || (*cur == '\t')) cur++; + i = 0; + while ((*cur != ' ') && (*cur != '\t') && + (*cur != '\n') && (*cur != '\r')) { + if (*cur == 0) + break; + command[i++] = *cur++; + } + command[i] = 0; + if (i == 0) continue; + nbargs++; + + /* + * Parse the argument + */ + while ((*cur == ' ') || (*cur == '\t')) cur++; + i = 0; + while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) { + if (*cur == 0) + break; + arg[i++] = *cur++; + } + arg[i] = 0; + if (i != 0) + nbargs++; + + /* + * start interpreting the command + */ + if (!strcmp(command, "exit")) + break; + if (!strcmp(command, "quit")) + break; + if (!strcmp(command, "bye")) + break; + if (!strcmp(command, "public")) { + answer = xmlCatalogGetPublic((const xmlChar *) arg); + if (answer == NULL) { + printf("No entry for PUBLIC %s\n", arg); + } else { + printf("%s\n", answer); + } + } else if (!strcmp(command, "system")) { + answer = xmlCatalogGetSystem((const xmlChar *) arg); + if (answer == NULL) { + printf("No entry for SYSTEM %s\n", arg); + } else { + printf("%s\n", answer); + } + } else if (!strcmp(command, "dump")) { + xmlCatalogDump(stdout); + } else { + if (strcmp(command, "help")) { + printf("Unrecognized command %s\n", command); + } + printf("Commands available:\n"); + printf("\tpublic PublicID: make a PUBLIC identifier lookup\n"); + printf("\tsystem SystemID: make a SYSTEM identifier lookup\n"); + printf("\tdump: print the current catalog state\n"); + printf("\texit: quit the shell\n"); + } + free(cmdline); /* not xmlFree here ! */ + } +} + +/************************************************************************ + * * + * Main * + * * + ************************************************************************/ +static void usage(const char *name) { + printf("Usage : %s [options] catalogfile ...\n", name); + printf("\tParse the catalog file(s) and output the result of the parsing\n"); + printf("\t--shell : run a shell allowing interactive queries\n"); + printf("\t-v --verbose : provide debug informations\n"); +} +int main(int argc, char **argv) { + int i; + + if (argc <= 1) { + usage(argv[0]); + return(1); + } + + LIBXML_TEST_VERSION + for (i = 1; i < argc ; i++) { + if (!strcmp(argv[i], "-")) + break; + + if (argv[i][0] != '-') + continue; + if ((!strcmp(argv[i], "-verbose")) || + (!strcmp(argv[i], "-v")) || + (!strcmp(argv[i], "--verbose"))) { + verbose++; + xmlCatalogSetDebug(verbose); + } else if ((!strcmp(argv[i], "-shell")) || + (!strcmp(argv[i], "--shell"))) { + shell++; + noout = 1; + } else { + fprintf(stderr, "Unknown option %s\n", argv[i]); + usage(argv[0]); + return(1); + } + } + + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') + continue; + xmlLoadCatalog(argv[i]); + } + + if (shell) { + usershell(); + } + if (!noout) { + xmlCatalogDump(stdout); + } + + /* + * Cleanup and check for memory leaks + */ + xmlCatalogCleanup(); + xmlCleanupParser(); + xmlMemoryDump(); + return(0); +} +#else +int main(int argc, char **argv) { + fprintf(stderr, "libxml was not compiled with catalog support\n"); + return(1); +} +#endif |