blob: e9238a471c6ca34d96e62fc811cd03b9c50c0844 [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
Daniel Veillardc0631a62001-09-20 13:56:06 +000015#ifdef HAVE_STDLIB_H
16#include <stdlib.h>
17#endif
18
Bjorn Reese45029602001-08-21 09:23:53 +000019#ifdef HAVE_LIBREADLINE
20#include <readline/readline.h>
21#ifdef HAVE_LIBHISTORY
22#include <readline/history.h>
23#endif
24#endif
25
Daniel Veillard344cee72001-08-20 00:08:40 +000026#include <libxml/xmlmemory.h>
27#include <libxml/uri.h>
28#include <libxml/catalog.h>
29#include <libxml/parser.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000030#include <libxml/globals.h>
Daniel Veillard344cee72001-08-20 00:08:40 +000031
32static int shell = 0;
Daniel Veillard82d75332001-10-08 15:01:59 +000033static int sgml = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +000034static int noout = 0;
Daniel Veillarde7ead2d2001-08-22 23:44:09 +000035static int create = 0;
Daniel Veillardcda96922001-08-21 10:56:31 +000036static int add = 0;
37static int del = 0;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000038static int convert = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +000039static int verbose = 0;
Daniel Veillardcda96922001-08-21 10:56:31 +000040static char *filename;
Daniel Veillard344cee72001-08-20 00:08:40 +000041
42#ifdef LIBXML_CATALOG_ENABLED
43/************************************************************************
44 * *
45 * Shell Interface *
46 * *
47 ************************************************************************/
48/**
49 * xmlShellReadline:
50 * @prompt: the prompt value
51 *
52 * Read a string
53 *
54 * Returns a pointer to it or NULL on EOF the caller is expected to
55 * free the returned string.
56 */
57static char *
58xmlShellReadline(const char *prompt) {
59#ifdef HAVE_LIBREADLINE
60 char *line_read;
61
62 /* Get a line from the user. */
63 line_read = readline (prompt);
64
65 /* If the line has any text in it, save it on the history. */
66 if (line_read && *line_read)
67 add_history (line_read);
68
69 return (line_read);
70#else
71 char line_read[501];
72
73 if (prompt != NULL)
74 fprintf(stdout, "%s", prompt);
75 if (!fgets(line_read, 500, stdin))
76 return(NULL);
77 line_read[500] = 0;
78 return(strdup(line_read));
79#endif
80}
81
82
83static void usershell(void) {
84 char *cmdline = NULL, *cur;
85 int nbargs;
86 char command[100];
87 char arg[400];
Daniel Veillardcda96922001-08-21 10:56:31 +000088 char *argv[20];
89 int i, ret;
Daniel Veillardcda96922001-08-21 10:56:31 +000090 xmlChar *ans;
Daniel Veillard344cee72001-08-20 00:08:40 +000091
92 while (1) {
93 cmdline = xmlShellReadline("> ");
94 if (cmdline == NULL)
95 return;
96
97 /*
98 * Parse the command itself
99 */
100 cur = cmdline;
101 nbargs = 0;
102 while ((*cur == ' ') || (*cur == '\t')) cur++;
103 i = 0;
104 while ((*cur != ' ') && (*cur != '\t') &&
105 (*cur != '\n') && (*cur != '\r')) {
106 if (*cur == 0)
107 break;
108 command[i++] = *cur++;
109 }
110 command[i] = 0;
111 if (i == 0) continue;
112 nbargs++;
113
114 /*
Daniel Veillardcda96922001-08-21 10:56:31 +0000115 * Parse the argument string
Daniel Veillard344cee72001-08-20 00:08:40 +0000116 */
Daniel Veillardcda96922001-08-21 10:56:31 +0000117 memset(arg, 0, sizeof(arg));
Daniel Veillard344cee72001-08-20 00:08:40 +0000118 while ((*cur == ' ') || (*cur == '\t')) cur++;
119 i = 0;
120 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
121 if (*cur == 0)
122 break;
123 arg[i++] = *cur++;
124 }
125 arg[i] = 0;
126 if (i != 0)
127 nbargs++;
128
129 /*
Daniel Veillardcda96922001-08-21 10:56:31 +0000130 * Parse the arguments
131 */
132 i = 0;
133 nbargs = 0;
134 cur = arg;
135 memset(argv, 0, sizeof(argv));
136 while (*cur != 0) {
137 while ((*cur == ' ') || (*cur == '\t')) cur++;
138 if (*cur == '\'') {
139 cur++;
140 argv[i] = cur;
141 while ((*cur != 0) && (*cur != '\'')) cur++;
142 if (*cur == '\'') {
143 *cur = 0;
144 nbargs++;
145 i++;
146 cur++;
147 }
148 } else if (*cur == '"') {
149 cur++;
150 argv[i] = cur;
151 while ((*cur != 0) && (*cur != '"')) cur++;
152 if (*cur == '"') {
153 *cur = 0;
154 nbargs++;
155 i++;
156 cur++;
157 }
158 } else {
159 argv[i] = cur;
160 while ((*cur != 0) && (*cur != ' ') && (*cur != '\t'))
161 cur++;
162 *cur = 0;
163 nbargs++;
164 i++;
165 cur++;
166 }
167 }
168
169 /*
Daniel Veillard344cee72001-08-20 00:08:40 +0000170 * start interpreting the command
171 */
172 if (!strcmp(command, "exit"))
173 break;
174 if (!strcmp(command, "quit"))
175 break;
176 if (!strcmp(command, "bye"))
177 break;
178 if (!strcmp(command, "public")) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000179 if (nbargs != 1) {
180 printf("public requires 1 arguments\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000181 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000182 ans = xmlCatalogResolvePublic((const xmlChar *) argv[0]);
183 if (ans == NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000184 printf("No entry for PUBLIC %s\n", argv[0]);
185 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000186 printf("%s\n", ans);
187 xmlFree(ans);
Daniel Veillardcda96922001-08-21 10:56:31 +0000188 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000189 }
190 } else if (!strcmp(command, "system")) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000191 if (nbargs != 1) {
192 printf("system requires 1 arguments\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000193 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000194 ans = xmlCatalogResolveSystem((const xmlChar *) argv[0]);
195 if (ans == NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000196 printf("No entry for SYSTEM %s\n", argv[0]);
197 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000198 printf("%s\n", ans);
199 xmlFree(ans);
Daniel Veillardcda96922001-08-21 10:56:31 +0000200 }
201 }
202 } else if (!strcmp(command, "add")) {
Daniel Veillard82d75332001-10-08 15:01:59 +0000203 if (sgml) {
204 if (nbargs != 1) {
205 printf("add requires 1 argument\n");
206 } else {
207 ret = xmlCatalogAdd(BAD_CAST "sgmlcatalog", NULL,
208 BAD_CAST argv[0]);
209 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000210 } else {
Daniel Veillard82d75332001-10-08 15:01:59 +0000211 if ((nbargs != 3) && (nbargs != 2)) {
212 printf("add requires 2 or 3 arguments\n");
213 } else {
214 if (argv[2] == NULL)
215 ret = xmlCatalogAdd(BAD_CAST argv[0], NULL,
216 BAD_CAST argv[1]);
217 else
218 ret = xmlCatalogAdd(BAD_CAST argv[0], BAD_CAST argv[1],
219 BAD_CAST argv[2]);
220 if (ret != 0)
221 printf("add command failed\n");
222 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000223 }
224 } else if (!strcmp(command, "del")) {
225 if (nbargs != 1) {
226 printf("del requires 1\n");
227 } else {
228 ret = xmlCatalogRemove(BAD_CAST argv[0]);
229 if (ret <= 0)
230 printf("del command failed\n");
231
232 }
233 } else if (!strcmp(command, "resolve")) {
234 if (nbargs != 2) {
235 printf("resolve requires 2 arguments\n");
236 } else {
237 ans = xmlCatalogResolve(BAD_CAST argv[0],
238 BAD_CAST argv[1]);
239 if (ans == NULL) {
240 printf("Resolver failed to find an answer\n");
241 } else {
242 printf("%s\n", ans);
243 xmlFree(ans);
244 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000245 }
246 } else if (!strcmp(command, "dump")) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000247 if (nbargs != 0) {
248 printf("dump has no arguments\n");
249 } else {
250 xmlCatalogDump(stdout);
251 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000252 } else if (!strcmp(command, "debug")) {
253 if (nbargs != 0) {
254 printf("debug has no arguments\n");
255 } else {
256 verbose++;
257 xmlCatalogSetDebug(verbose);
258 }
259 } else if (!strcmp(command, "quiet")) {
260 if (nbargs != 0) {
261 printf("quiet has no arguments\n");
262 } else {
263 if (verbose > 0)
264 verbose--;
265 xmlCatalogSetDebug(verbose);
266 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000267 } else {
268 if (strcmp(command, "help")) {
269 printf("Unrecognized command %s\n", command);
270 }
271 printf("Commands available:\n");
272 printf("\tpublic PublicID: make a PUBLIC identifier lookup\n");
273 printf("\tsystem SystemID: make a SYSTEM identifier lookup\n");
Daniel Veillardcda96922001-08-21 10:56:31 +0000274 printf("\tresolve PublicID SystemID: do a full resolver lookup\n");
275 printf("\tadd 'type' 'orig' 'replace' : add an entry\n");
276 printf("\tdel 'values' : remove values\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000277 printf("\tdump: print the current catalog state\n");
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000278 printf("\tdebug: increase the verbosity level\n");
279 printf("\tquiet: decrease the verbosity level\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000280 printf("\texit: quit the shell\n");
281 }
282 free(cmdline); /* not xmlFree here ! */
283 }
284}
285
286/************************************************************************
287 * *
288 * Main *
289 * *
290 ************************************************************************/
291static void usage(const char *name) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000292 printf("Usage : %s [options] catalogfile entities...\n", name);
293 printf("\tParse the catalog file and query it for the entities\n");
Daniel Veillard82d75332001-10-08 15:01:59 +0000294 printf("\t--sgml : handle an SGML Super catalog\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000295 printf("\t--shell : run a shell allowing interactive queries\n");
Daniel Veillarde7ead2d2001-08-22 23:44:09 +0000296 printf("\t--create : create a new catalog\n");
Daniel Veillardcda96922001-08-21 10:56:31 +0000297 printf("\t--add 'type' 'orig' 'replace' : add an entry\n");
298 printf("\t--del 'values' : remove values\n");
299 printf("\t--noout: avoid dumping the result on stdout\n");
300 printf("\t used with add or del, it saves the catalog changes\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000301 printf("\t-v --verbose : provide debug informations\n");
302}
303int main(int argc, char **argv) {
304 int i;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000305 int ret;
306
Daniel Veillard344cee72001-08-20 00:08:40 +0000307
308 if (argc <= 1) {
309 usage(argv[0]);
310 return(1);
311 }
312
313 LIBXML_TEST_VERSION
314 for (i = 1; i < argc ; i++) {
315 if (!strcmp(argv[i], "-"))
316 break;
317
318 if (argv[i][0] != '-')
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000319 break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000320 if ((!strcmp(argv[i], "-verbose")) ||
321 (!strcmp(argv[i], "-v")) ||
322 (!strcmp(argv[i], "--verbose"))) {
323 verbose++;
324 xmlCatalogSetDebug(verbose);
Daniel Veillardcda96922001-08-21 10:56:31 +0000325 } else if ((!strcmp(argv[i], "-noout")) ||
326 (!strcmp(argv[i], "--noout"))) {
327 noout = 1;
Daniel Veillard344cee72001-08-20 00:08:40 +0000328 } else if ((!strcmp(argv[i], "-shell")) ||
329 (!strcmp(argv[i], "--shell"))) {
330 shell++;
331 noout = 1;
Daniel Veillard82d75332001-10-08 15:01:59 +0000332 } else if ((!strcmp(argv[i], "-sgml")) ||
333 (!strcmp(argv[i], "--sgml"))) {
334 sgml++;
Daniel Veillarde7ead2d2001-08-22 23:44:09 +0000335 } else if ((!strcmp(argv[i], "-create")) ||
336 (!strcmp(argv[i], "--create"))) {
337 create++;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000338 } else if ((!strcmp(argv[i], "-convert")) ||
339 (!strcmp(argv[i], "--convert"))) {
340 convert++;
Daniel Veillardcda96922001-08-21 10:56:31 +0000341 } else if ((!strcmp(argv[i], "-add")) ||
342 (!strcmp(argv[i], "--add"))) {
Daniel Veillard82d75332001-10-08 15:01:59 +0000343 if (sgml)
344 i += 1;
345 else
346 i += 3;
Daniel Veillardcda96922001-08-21 10:56:31 +0000347 add++;
348 } else if ((!strcmp(argv[i], "-del")) ||
349 (!strcmp(argv[i], "--del"))) {
350 i += 1;
351 del++;
Daniel Veillard344cee72001-08-20 00:08:40 +0000352 } else {
353 fprintf(stderr, "Unknown option %s\n", argv[i]);
354 usage(argv[0]);
355 return(1);
356 }
357 }
358
359 for (i = 1; i < argc; i++) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000360 if ((!strcmp(argv[i], "-add")) ||
361 (!strcmp(argv[i], "--add"))) {
Daniel Veillard82d75332001-10-08 15:01:59 +0000362 if (sgml)
363 i += 1;
364 else
365 i += 3;
Daniel Veillard344cee72001-08-20 00:08:40 +0000366 continue;
Daniel Veillardcda96922001-08-21 10:56:31 +0000367 } else if ((!strcmp(argv[i], "-del")) ||
368 (!strcmp(argv[i], "--del"))) {
369 i += 1;
370 continue;
371 } else if (argv[i][0] == '-')
372 continue;
373 filename = argv[i];
Daniel Veillardb8478642001-10-12 17:29:10 +0000374 /* !!!!!!!!!!!!!!!!!! TODO !!!!
Daniel Veillard82d75332001-10-08 15:01:59 +0000375 if (sgml)
376 ret = xmlLoadSGMLSuperCatalog(argv[i]);
377 else
Daniel Veillardb8478642001-10-12 17:29:10 +0000378 !!!!!!!!! */
Daniel Veillard82d75332001-10-08 15:01:59 +0000379 ret = xmlLoadCatalog(argv[i]);
380 if ((!sgml) && (ret < 0) && (create)) {
Daniel Veillarde7ead2d2001-08-22 23:44:09 +0000381 xmlCatalogAdd(BAD_CAST "catalog", BAD_CAST argv[i], NULL);
382 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000383 break;
384 }
385
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000386 if (convert)
387 ret = xmlCatalogConvert();
Daniel Veillardcda96922001-08-21 10:56:31 +0000388
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000389 if ((add) || (del)) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000390 for (i = 1; i < argc ; i++) {
391 if (!strcmp(argv[i], "-"))
392 break;
393
394 if (argv[i][0] != '-')
395 continue;
396 if ((!strcmp(argv[i], "-add")) ||
397 (!strcmp(argv[i], "--add"))) {
Daniel Veillard82d75332001-10-08 15:01:59 +0000398 if (sgml) {
399 ret = xmlCatalogAdd(BAD_CAST "sgmlcatalog", NULL,
400 BAD_CAST argv[i + 1]);
401 i += 1;
402 } else {
403 if ((argv[i + 3] == NULL) || (argv[i + 3][0] == 0))
404 ret = xmlCatalogAdd(BAD_CAST argv[i + 1], NULL,
405 BAD_CAST argv[i + 2]);
406 else
407 ret = xmlCatalogAdd(BAD_CAST argv[i + 1],
408 BAD_CAST argv[i + 2],
409 BAD_CAST argv[i + 3]);
410 if (ret != 0)
411 printf("add command failed\n");
412 i += 3;
413 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000414 } else if ((!strcmp(argv[i], "-del")) ||
415 (!strcmp(argv[i], "--del"))) {
416 ret = xmlCatalogRemove(BAD_CAST argv[i + 1]);
417 i += 1;
418 }
419 }
420
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000421 } else if (shell) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000422 usershell();
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000423 } else {
424 for (i++; i < argc; i++) {
425 xmlURIPtr uri;
426 xmlChar *ans;
427
428 uri = xmlParseURI(argv[i]);
429 if (uri == NULL) {
430 ans = xmlCatalogResolvePublic((const xmlChar *) argv[i]);
431 if (ans == NULL) {
432 printf("No entry for PUBLIC %s\n", argv[i]);
433 } else {
434 printf("%s\n", ans);
435 xmlFree(ans);
436 }
437 } else {
438 xmlFreeURI(uri);
439 ans = xmlCatalogResolveSystem((const xmlChar *) argv[i]);
440 if (ans == NULL) {
441 printf("No entry for SYSTEM %s\n", argv[i]);
442 } else {
443 printf("%s\n", ans);
444 xmlFree(ans);
445 }
446 }
447 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000448 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000449 if ((add) || (del) || (create) || (convert)) {
Daniel Veillarde7ead2d2001-08-22 23:44:09 +0000450 if (noout) {
451 FILE *out;
452
453 out = fopen(filename, "w");
454 if (out == NULL) {
455 fprintf(stderr, "could not open %s for saving\n", filename);
456 noout = 0;
457 } else {
458 xmlCatalogDump(out);
459 }
460 } else {
461 xmlCatalogDump(stdout);
462 }
463 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000464
465 /*
466 * Cleanup and check for memory leaks
467 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000468 xmlCleanupParser();
469 xmlMemoryDump();
470 return(0);
471}
472#else
473int main(int argc, char **argv) {
474 fprintf(stderr, "libxml was not compiled with catalog support\n");
475 return(1);
476}
477#endif