blob: c2cd52fbfcab5cfd11acd995a64a707d3645817e [file] [log] [blame]
Daniel Veillard344cee72001-08-20 00:08:40 +00001/*
2 * xmlcatalog.c : a small utility program to handle XML catalogs
3 *
4 * See Copyright for the status of this software.
5 *
6 * daniel@veillard.com
7 */
8
9#include "libxml.h"
10
11#include <string.h>
12#include <stdio.h>
13#include <stdarg.h>
14
Bjorn Reese45029602001-08-21 09:23:53 +000015#ifdef HAVE_LIBREADLINE
16#include <readline/readline.h>
17#ifdef HAVE_LIBHISTORY
18#include <readline/history.h>
19#endif
20#endif
21
Daniel Veillard344cee72001-08-20 00:08:40 +000022#include <libxml/xmlmemory.h>
23#include <libxml/uri.h>
24#include <libxml/catalog.h>
25#include <libxml/parser.h>
26
27static int shell = 0;
28static int noout = 0;
Daniel Veillarde7ead2d2001-08-22 23:44:09 +000029static int create = 0;
Daniel Veillardcda96922001-08-21 10:56:31 +000030static int add = 0;
31static int del = 0;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000032static int convert = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +000033static int verbose = 0;
Daniel Veillardcda96922001-08-21 10:56:31 +000034static char *filename;
Daniel Veillard344cee72001-08-20 00:08:40 +000035
36#ifdef LIBXML_CATALOG_ENABLED
37/************************************************************************
38 * *
39 * Shell Interface *
40 * *
41 ************************************************************************/
42/**
43 * xmlShellReadline:
44 * @prompt: the prompt value
45 *
46 * Read a string
47 *
48 * Returns a pointer to it or NULL on EOF the caller is expected to
49 * free the returned string.
50 */
51static char *
52xmlShellReadline(const char *prompt) {
53#ifdef HAVE_LIBREADLINE
54 char *line_read;
55
56 /* Get a line from the user. */
57 line_read = readline (prompt);
58
59 /* If the line has any text in it, save it on the history. */
60 if (line_read && *line_read)
61 add_history (line_read);
62
63 return (line_read);
64#else
65 char line_read[501];
66
67 if (prompt != NULL)
68 fprintf(stdout, "%s", prompt);
69 if (!fgets(line_read, 500, stdin))
70 return(NULL);
71 line_read[500] = 0;
72 return(strdup(line_read));
73#endif
74}
75
76
77static void usershell(void) {
78 char *cmdline = NULL, *cur;
79 int nbargs;
80 char command[100];
81 char arg[400];
Daniel Veillardcda96922001-08-21 10:56:31 +000082 char *argv[20];
83 int i, ret;
Daniel Veillardcda96922001-08-21 10:56:31 +000084 xmlChar *ans;
Daniel Veillard344cee72001-08-20 00:08:40 +000085
86 while (1) {
87 cmdline = xmlShellReadline("> ");
88 if (cmdline == NULL)
89 return;
90
91 /*
92 * Parse the command itself
93 */
94 cur = cmdline;
95 nbargs = 0;
96 while ((*cur == ' ') || (*cur == '\t')) cur++;
97 i = 0;
98 while ((*cur != ' ') && (*cur != '\t') &&
99 (*cur != '\n') && (*cur != '\r')) {
100 if (*cur == 0)
101 break;
102 command[i++] = *cur++;
103 }
104 command[i] = 0;
105 if (i == 0) continue;
106 nbargs++;
107
108 /*
Daniel Veillardcda96922001-08-21 10:56:31 +0000109 * Parse the argument string
Daniel Veillard344cee72001-08-20 00:08:40 +0000110 */
Daniel Veillardcda96922001-08-21 10:56:31 +0000111 memset(arg, 0, sizeof(arg));
Daniel Veillard344cee72001-08-20 00:08:40 +0000112 while ((*cur == ' ') || (*cur == '\t')) cur++;
113 i = 0;
114 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
115 if (*cur == 0)
116 break;
117 arg[i++] = *cur++;
118 }
119 arg[i] = 0;
120 if (i != 0)
121 nbargs++;
122
123 /*
Daniel Veillardcda96922001-08-21 10:56:31 +0000124 * Parse the arguments
125 */
126 i = 0;
127 nbargs = 0;
128 cur = arg;
129 memset(argv, 0, sizeof(argv));
130 while (*cur != 0) {
131 while ((*cur == ' ') || (*cur == '\t')) cur++;
132 if (*cur == '\'') {
133 cur++;
134 argv[i] = cur;
135 while ((*cur != 0) && (*cur != '\'')) cur++;
136 if (*cur == '\'') {
137 *cur = 0;
138 nbargs++;
139 i++;
140 cur++;
141 }
142 } else if (*cur == '"') {
143 cur++;
144 argv[i] = cur;
145 while ((*cur != 0) && (*cur != '"')) cur++;
146 if (*cur == '"') {
147 *cur = 0;
148 nbargs++;
149 i++;
150 cur++;
151 }
152 } else {
153 argv[i] = cur;
154 while ((*cur != 0) && (*cur != ' ') && (*cur != '\t'))
155 cur++;
156 *cur = 0;
157 nbargs++;
158 i++;
159 cur++;
160 }
161 }
162
163 /*
Daniel Veillard344cee72001-08-20 00:08:40 +0000164 * start interpreting the command
165 */
166 if (!strcmp(command, "exit"))
167 break;
168 if (!strcmp(command, "quit"))
169 break;
170 if (!strcmp(command, "bye"))
171 break;
172 if (!strcmp(command, "public")) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000173 if (nbargs != 1) {
174 printf("public requires 1 arguments\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000175 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000176 ans = xmlCatalogResolvePublic((const xmlChar *) argv[0]);
177 if (ans == NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000178 printf("No entry for PUBLIC %s\n", argv[0]);
179 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000180 printf("%s\n", ans);
181 xmlFree(ans);
Daniel Veillardcda96922001-08-21 10:56:31 +0000182 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000183 }
184 } else if (!strcmp(command, "system")) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000185 if (nbargs != 1) {
186 printf("system requires 1 arguments\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000187 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000188 ans = xmlCatalogResolveSystem((const xmlChar *) argv[0]);
189 if (ans == NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000190 printf("No entry for SYSTEM %s\n", argv[0]);
191 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000192 printf("%s\n", ans);
193 xmlFree(ans);
Daniel Veillardcda96922001-08-21 10:56:31 +0000194 }
195 }
196 } else if (!strcmp(command, "add")) {
197 if ((nbargs != 3) && (nbargs != 2)) {
198 printf("add requires 2 or 3 arguments\n");
199 } else {
200 if (argv[2] == NULL)
201 ret = xmlCatalogAdd(BAD_CAST argv[0], NULL,
202 BAD_CAST argv[1]);
203 else
204 ret = xmlCatalogAdd(BAD_CAST argv[0], BAD_CAST argv[1],
205 BAD_CAST argv[2]);
206 if (ret != 0)
207 printf("add command failed\n");
208 }
209 } else if (!strcmp(command, "del")) {
210 if (nbargs != 1) {
211 printf("del requires 1\n");
212 } else {
213 ret = xmlCatalogRemove(BAD_CAST argv[0]);
214 if (ret <= 0)
215 printf("del command failed\n");
216
217 }
218 } else if (!strcmp(command, "resolve")) {
219 if (nbargs != 2) {
220 printf("resolve requires 2 arguments\n");
221 } else {
222 ans = xmlCatalogResolve(BAD_CAST argv[0],
223 BAD_CAST argv[1]);
224 if (ans == NULL) {
225 printf("Resolver failed to find an answer\n");
226 } else {
227 printf("%s\n", ans);
228 xmlFree(ans);
229 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000230 }
231 } else if (!strcmp(command, "dump")) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000232 if (nbargs != 0) {
233 printf("dump has no arguments\n");
234 } else {
235 xmlCatalogDump(stdout);
236 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000237 } else if (!strcmp(command, "debug")) {
238 if (nbargs != 0) {
239 printf("debug has no arguments\n");
240 } else {
241 verbose++;
242 xmlCatalogSetDebug(verbose);
243 }
244 } else if (!strcmp(command, "quiet")) {
245 if (nbargs != 0) {
246 printf("quiet has no arguments\n");
247 } else {
248 if (verbose > 0)
249 verbose--;
250 xmlCatalogSetDebug(verbose);
251 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000252 } else {
253 if (strcmp(command, "help")) {
254 printf("Unrecognized command %s\n", command);
255 }
256 printf("Commands available:\n");
257 printf("\tpublic PublicID: make a PUBLIC identifier lookup\n");
258 printf("\tsystem SystemID: make a SYSTEM identifier lookup\n");
Daniel Veillardcda96922001-08-21 10:56:31 +0000259 printf("\tresolve PublicID SystemID: do a full resolver lookup\n");
260 printf("\tadd 'type' 'orig' 'replace' : add an entry\n");
261 printf("\tdel 'values' : remove values\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000262 printf("\tdump: print the current catalog state\n");
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000263 printf("\tdebug: increase the verbosity level\n");
264 printf("\tquiet: decrease the verbosity level\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000265 printf("\texit: quit the shell\n");
266 }
267 free(cmdline); /* not xmlFree here ! */
268 }
269}
270
271/************************************************************************
272 * *
273 * Main *
274 * *
275 ************************************************************************/
276static void usage(const char *name) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000277 printf("Usage : %s [options] catalogfile entities...\n", name);
278 printf("\tParse the catalog file and query it for the entities\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000279 printf("\t--shell : run a shell allowing interactive queries\n");
Daniel Veillarde7ead2d2001-08-22 23:44:09 +0000280 printf("\t--create : create a new catalog\n");
Daniel Veillardcda96922001-08-21 10:56:31 +0000281 printf("\t--add 'type' 'orig' 'replace' : add an entry\n");
282 printf("\t--del 'values' : remove values\n");
283 printf("\t--noout: avoid dumping the result on stdout\n");
284 printf("\t used with add or del, it saves the catalog changes\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000285 printf("\t-v --verbose : provide debug informations\n");
286}
287int main(int argc, char **argv) {
288 int i;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000289 int ret;
290
Daniel Veillard344cee72001-08-20 00:08:40 +0000291
292 if (argc <= 1) {
293 usage(argv[0]);
294 return(1);
295 }
296
297 LIBXML_TEST_VERSION
298 for (i = 1; i < argc ; i++) {
299 if (!strcmp(argv[i], "-"))
300 break;
301
302 if (argv[i][0] != '-')
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000303 break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000304 if ((!strcmp(argv[i], "-verbose")) ||
305 (!strcmp(argv[i], "-v")) ||
306 (!strcmp(argv[i], "--verbose"))) {
307 verbose++;
308 xmlCatalogSetDebug(verbose);
Daniel Veillardcda96922001-08-21 10:56:31 +0000309 } else if ((!strcmp(argv[i], "-noout")) ||
310 (!strcmp(argv[i], "--noout"))) {
311 noout = 1;
Daniel Veillard344cee72001-08-20 00:08:40 +0000312 } else if ((!strcmp(argv[i], "-shell")) ||
313 (!strcmp(argv[i], "--shell"))) {
314 shell++;
315 noout = 1;
Daniel Veillarde7ead2d2001-08-22 23:44:09 +0000316 } else if ((!strcmp(argv[i], "-create")) ||
317 (!strcmp(argv[i], "--create"))) {
318 create++;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000319 } else if ((!strcmp(argv[i], "-convert")) ||
320 (!strcmp(argv[i], "--convert"))) {
321 convert++;
Daniel Veillardcda96922001-08-21 10:56:31 +0000322 } else if ((!strcmp(argv[i], "-add")) ||
323 (!strcmp(argv[i], "--add"))) {
324 i += 3;
325 add++;
326 } else if ((!strcmp(argv[i], "-del")) ||
327 (!strcmp(argv[i], "--del"))) {
328 i += 1;
329 del++;
Daniel Veillard344cee72001-08-20 00:08:40 +0000330 } else {
331 fprintf(stderr, "Unknown option %s\n", argv[i]);
332 usage(argv[0]);
333 return(1);
334 }
335 }
336
337 for (i = 1; i < argc; i++) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000338 if ((!strcmp(argv[i], "-add")) ||
339 (!strcmp(argv[i], "--add"))) {
340 i += 3;
Daniel Veillard344cee72001-08-20 00:08:40 +0000341 continue;
Daniel Veillardcda96922001-08-21 10:56:31 +0000342 } else if ((!strcmp(argv[i], "-del")) ||
343 (!strcmp(argv[i], "--del"))) {
344 i += 1;
345 continue;
346 } else if (argv[i][0] == '-')
347 continue;
348 filename = argv[i];
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000349 ret = xmlLoadCatalog(argv[i]);
350 if ((ret < 0) && (create)) {
Daniel Veillarde7ead2d2001-08-22 23:44:09 +0000351 xmlCatalogAdd(BAD_CAST "catalog", BAD_CAST argv[i], NULL);
352 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000353 break;
354 }
355
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000356 if (convert)
357 ret = xmlCatalogConvert();
Daniel Veillardcda96922001-08-21 10:56:31 +0000358
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000359 if ((add) || (del)) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000360 for (i = 1; i < argc ; i++) {
361 if (!strcmp(argv[i], "-"))
362 break;
363
364 if (argv[i][0] != '-')
365 continue;
366 if ((!strcmp(argv[i], "-add")) ||
367 (!strcmp(argv[i], "--add"))) {
368 if ((argv[i + 3] == NULL) || (argv[i + 3][0] == 0))
369 ret = xmlCatalogAdd(BAD_CAST argv[i + 1], NULL,
370 BAD_CAST argv[i + 2]);
371 else
372 ret = xmlCatalogAdd(BAD_CAST argv[i + 1],
373 BAD_CAST argv[i + 2],
374 BAD_CAST argv[i + 3]);
375 if (ret != 0)
376 printf("add command failed\n");
377 i += 3;
378 } else if ((!strcmp(argv[i], "-del")) ||
379 (!strcmp(argv[i], "--del"))) {
380 ret = xmlCatalogRemove(BAD_CAST argv[i + 1]);
381 i += 1;
382 }
383 }
384
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000385 } else if (shell) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000386 usershell();
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000387 } else {
388 for (i++; i < argc; i++) {
389 xmlURIPtr uri;
390 xmlChar *ans;
391
392 uri = xmlParseURI(argv[i]);
393 if (uri == NULL) {
394 ans = xmlCatalogResolvePublic((const xmlChar *) argv[i]);
395 if (ans == NULL) {
396 printf("No entry for PUBLIC %s\n", argv[i]);
397 } else {
398 printf("%s\n", ans);
399 xmlFree(ans);
400 }
401 } else {
402 xmlFreeURI(uri);
403 ans = xmlCatalogResolveSystem((const xmlChar *) argv[i]);
404 if (ans == NULL) {
405 printf("No entry for SYSTEM %s\n", argv[i]);
406 } else {
407 printf("%s\n", ans);
408 xmlFree(ans);
409 }
410 }
411 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000412 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000413 if ((add) || (del) || (create) || (convert)) {
Daniel Veillarde7ead2d2001-08-22 23:44:09 +0000414 if (noout) {
415 FILE *out;
416
417 out = fopen(filename, "w");
418 if (out == NULL) {
419 fprintf(stderr, "could not open %s for saving\n", filename);
420 noout = 0;
421 } else {
422 xmlCatalogDump(out);
423 }
424 } else {
425 xmlCatalogDump(stdout);
426 }
427 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000428
429 /*
430 * Cleanup and check for memory leaks
431 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000432 xmlCleanupParser();
433 xmlMemoryDump();
434 return(0);
435}
436#else
437int main(int argc, char **argv) {
438 fprintf(stderr, "libxml was not compiled with catalog support\n");
439 return(1);
440}
441#endif