xref: /reactos/sdk/lib/3rdparty/libxml2/xmlcatalog.c (revision 299e4305)
1 /*
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 #include <stdlib.h>
15 
16 #ifdef HAVE_LIBREADLINE
17 #include <readline/readline.h>
18 #ifdef HAVE_LIBHISTORY
19 #include <readline/history.h>
20 #endif
21 #endif
22 
23 #include <libxml/xmlmemory.h>
24 #include <libxml/uri.h>
25 #include <libxml/catalog.h>
26 #include <libxml/parser.h>
27 #include <libxml/globals.h>
28 
29 #if defined(LIBXML_CATALOG_ENABLED) && defined(LIBXML_OUTPUT_ENABLED)
30 static int shell = 0;
31 static int sgml = 0;
32 static int noout = 0;
33 static int create = 0;
34 static int add = 0;
35 static int del = 0;
36 static int convert = 0;
37 static int no_super_update = 0;
38 static int verbose = 0;
39 static char *filename = NULL;
40 
41 
42 #ifndef XML_SGML_DEFAULT_CATALOG
43 #define XML_SGML_DEFAULT_CATALOG SYSCONFDIR "/sgml/catalog"
44 #endif
45 
46 /************************************************************************
47  *									*
48  *			Shell Interface					*
49  *									*
50  ************************************************************************/
51 /**
52  * xmlShellReadline:
53  * @prompt:  the prompt value
54  *
55  * Read a string
56  *
57  * Returns a pointer to it or NULL on EOF the caller is expected to
58  *     free the returned string.
59  */
60 static char *
61 xmlShellReadline(const char *prompt) {
62 #ifdef HAVE_LIBREADLINE
63     char *line_read;
64 
65     /* Get a line from the user. */
66     line_read = readline (prompt);
67 
68     /* If the line has any text in it, save it on the history. */
69     if (line_read && *line_read)
70 	add_history (line_read);
71 
72     return (line_read);
73 #else
74     char line_read[501];
75     char *ret;
76     int len;
77 
78     if (prompt != NULL)
79 	fprintf(stdout, "%s", prompt);
80     fflush(stdout);
81     if (!fgets(line_read, 500, stdin))
82         return(NULL);
83     line_read[500] = 0;
84     len = strlen(line_read);
85     ret = (char *) malloc(len + 1);
86     if (ret != NULL) {
87 	memcpy (ret, line_read, len + 1);
88     }
89     return(ret);
90 #endif
91 }
92 
93 static void usershell(void) {
94     char *cmdline = NULL, *cur;
95     int nbargs;
96     char command[100];
97     char arg[400];
98     char *argv[20];
99     int i, ret;
100     xmlChar *ans;
101 
102     while (1) {
103 	cmdline = xmlShellReadline("> ");
104 	if (cmdline == NULL)
105 	    return;
106 
107 	/*
108 	 * Parse the command itself
109 	 */
110 	cur = cmdline;
111 	nbargs = 0;
112 	while ((*cur == ' ') || (*cur == '\t')) cur++;
113 	i = 0;
114 	while ((*cur != ' ') && (*cur != '\t') &&
115 	       (*cur != '\n') && (*cur != '\r')) {
116 	    if (*cur == 0)
117 		break;
118 	    command[i++] = *cur++;
119 	}
120 	command[i] = 0;
121 	if (i == 0) {
122 	    free(cmdline);
123 	    continue;
124 	}
125 
126 	/*
127 	 * Parse the argument string
128 	 */
129 	memset(arg, 0, sizeof(arg));
130 	while ((*cur == ' ') || (*cur == '\t')) cur++;
131 	i = 0;
132 	while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
133 	    if (*cur == 0)
134 		break;
135 	    arg[i++] = *cur++;
136 	}
137 	arg[i] = 0;
138 
139 	/*
140 	 * Parse the arguments
141 	 */
142 	i = 0;
143 	nbargs = 0;
144 	cur = arg;
145 	memset(argv, 0, sizeof(argv));
146 	while (*cur != 0) {
147 	    while ((*cur == ' ') || (*cur == '\t')) cur++;
148 	    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 if (*cur == '"') {
159 		cur++;
160 		argv[i] = cur;
161 		while ((*cur != 0) && (*cur != '"')) cur++;
162 		if (*cur == '"') {
163 		    *cur = 0;
164 		    nbargs++;
165 		    i++;
166 		    cur++;
167 		}
168 	    } else {
169 		argv[i] = cur;
170 		while ((*cur != 0) && (*cur != ' ') && (*cur != '\t'))
171 		    cur++;
172 		*cur = 0;
173 		nbargs++;
174 		i++;
175 		cur++;
176 	    }
177 	}
178 
179 	/*
180 	 * start interpreting the command
181 	 */
182 	if (!strcmp(command, "exit") ||
183 	    !strcmp(command, "quit") ||
184 	    !strcmp(command, "bye")) {
185 	    free(cmdline);
186 	    break;
187 	}
188 
189 	if (!strcmp(command, "public")) {
190 	    if (nbargs != 1) {
191 		printf("public requires 1 arguments\n");
192 	    } else {
193 		ans = xmlCatalogResolvePublic((const xmlChar *) argv[0]);
194 		if (ans == NULL) {
195 		    printf("No entry for PUBLIC %s\n", argv[0]);
196 		} else {
197 		    printf("%s\n", (char *) ans);
198 		    xmlFree(ans);
199 		}
200 	    }
201 	} else if (!strcmp(command, "system")) {
202 	    if (nbargs != 1) {
203 		printf("system requires 1 arguments\n");
204 	    } else {
205 		ans = xmlCatalogResolveSystem((const xmlChar *) argv[0]);
206 		if (ans == NULL) {
207 		    printf("No entry for SYSTEM %s\n", argv[0]);
208 		} else {
209 		    printf("%s\n", (char *) ans);
210 		    xmlFree(ans);
211 		}
212 	    }
213 	} else if (!strcmp(command, "add")) {
214 	    if ((nbargs != 3) && (nbargs != 2)) {
215 		printf("add requires 2 or 3 arguments\n");
216 	    } else {
217 		if (argv[2] == NULL)
218 		ret = xmlCatalogAdd(BAD_CAST argv[0], NULL,
219 				    BAD_CAST argv[1]);
220 		else
221 		    ret = xmlCatalogAdd(BAD_CAST argv[0], BAD_CAST argv[1],
222 					BAD_CAST argv[2]);
223 		if (ret != 0)
224 		    printf("add command failed\n");
225 	    }
226 	} else if (!strcmp(command, "del")) {
227 	    if (nbargs != 1) {
228 		printf("del requires 1\n");
229 	    } else {
230 		ret = xmlCatalogRemove(BAD_CAST argv[0]);
231 		if (ret <= 0)
232 		    printf("del command failed\n");
233 
234 	    }
235 	} else if (!strcmp(command, "resolve")) {
236 	    if (nbargs != 2) {
237 		printf("resolve requires 2 arguments\n");
238 	    } else {
239 		ans = xmlCatalogResolve(BAD_CAST argv[0],
240 			                BAD_CAST argv[1]);
241 		if (ans == NULL) {
242 		    printf("Resolver failed to find an answer\n");
243 		} else {
244 		    printf("%s\n", (char *) ans);
245 		    xmlFree(ans);
246 		}
247 	    }
248 	} else if (!strcmp(command, "dump")) {
249 	    if (nbargs != 0) {
250 		printf("dump has no arguments\n");
251 	    } else {
252 		xmlCatalogDump(stdout);
253 	    }
254 	} else if (!strcmp(command, "debug")) {
255 	    if (nbargs != 0) {
256 		printf("debug has no arguments\n");
257 	    } else {
258 		verbose++;
259 		xmlCatalogSetDebug(verbose);
260 	    }
261 	} else if (!strcmp(command, "quiet")) {
262 	    if (nbargs != 0) {
263 		printf("quiet has no arguments\n");
264 	    } else {
265 		if (verbose > 0)
266 		    verbose--;
267 		xmlCatalogSetDebug(verbose);
268 	    }
269 	} else {
270 	    if (strcmp(command, "help")) {
271 		printf("Unrecognized command %s\n", command);
272 	    }
273 	    printf("Commands available:\n");
274 	    printf("\tpublic PublicID: make a PUBLIC identifier lookup\n");
275 	    printf("\tsystem SystemID: make a SYSTEM identifier lookup\n");
276 	    printf("\tresolve PublicID SystemID: do a full resolver lookup\n");
277 	    printf("\tadd 'type' 'orig' 'replace' : add an entry\n");
278 	    printf("\tdel 'values' : remove values\n");
279 	    printf("\tdump: print the current catalog state\n");
280 	    printf("\tdebug: increase the verbosity level\n");
281 	    printf("\tquiet: decrease the verbosity level\n");
282 	    printf("\texit:  quit the shell\n");
283 	}
284 	free(cmdline); /* not xmlFree here ! */
285     }
286 }
287 
288 /************************************************************************
289  *									*
290  *			Main						*
291  *									*
292  ************************************************************************/
293 static void usage(const char *name) {
294     /* split into 2 printf's to avoid overly long string (gcc warning) */
295     printf("\
296 Usage : %s [options] catalogfile entities...\n\
297 \tParse the catalog file (void specification possibly expressed as \"\"\n\
298 \tappoints the default system one) and query it for the entities\n\
299 \t--sgml : handle SGML Super catalogs for --add and --del\n\
300 \t--shell : run a shell allowing interactive queries\n\
301 \t--create : create a new catalog\n\
302 \t--add 'type' 'orig' 'replace' : add an XML entry\n\
303 \t--add 'entry' : add an SGML entry\n", name);
304     printf("\
305 \t--del 'values' : remove values\n\
306 \t--noout: avoid dumping the result on stdout\n\
307 \t         used with --add or --del, it saves the catalog changes\n\
308 \t         and with --sgml it automatically updates the super catalog\n\
309 \t--no-super-update: do not update the SGML super catalog\n\
310 \t-v --verbose : provide debug information\n");
311 }
312 int main(int argc, char **argv) {
313     int i;
314     int ret;
315     int exit_value = 0;
316 
317 
318     if (argc <= 1) {
319 	usage(argv[0]);
320 	return(1);
321     }
322 
323     LIBXML_TEST_VERSION
324     for (i = 1; i < argc ; i++) {
325 	if (!strcmp(argv[i], "-"))
326 	    break;
327 
328 	if (argv[i][0] != '-')
329 	    break;
330 	if ((!strcmp(argv[i], "-verbose")) ||
331 	    (!strcmp(argv[i], "-v")) ||
332 	    (!strcmp(argv[i], "--verbose"))) {
333 	    verbose++;
334 	    xmlCatalogSetDebug(verbose);
335 	} else if ((!strcmp(argv[i], "-noout")) ||
336 	    (!strcmp(argv[i], "--noout"))) {
337             noout = 1;
338 	} else if ((!strcmp(argv[i], "-shell")) ||
339 	    (!strcmp(argv[i], "--shell"))) {
340 	    shell++;
341             noout = 1;
342 	} else if ((!strcmp(argv[i], "-sgml")) ||
343 	    (!strcmp(argv[i], "--sgml"))) {
344 	    sgml++;
345 	} else if ((!strcmp(argv[i], "-create")) ||
346 	    (!strcmp(argv[i], "--create"))) {
347 	    create++;
348 	} else if ((!strcmp(argv[i], "-convert")) ||
349 	    (!strcmp(argv[i], "--convert"))) {
350 	    convert++;
351 	} else if ((!strcmp(argv[i], "-no-super-update")) ||
352 	    (!strcmp(argv[i], "--no-super-update"))) {
353 	    no_super_update++;
354 	} else if ((!strcmp(argv[i], "-add")) ||
355 	    (!strcmp(argv[i], "--add"))) {
356 	    if (sgml)
357 		i += 2;
358 	    else
359 		i += 3;
360 	    add++;
361 	} else if ((!strcmp(argv[i], "-del")) ||
362 	    (!strcmp(argv[i], "--del"))) {
363 	    i += 1;
364 	    del++;
365 	} else {
366 	    fprintf(stderr, "Unknown option %s\n", argv[i]);
367 	    usage(argv[0]);
368 	    return(1);
369 	}
370     }
371 
372     for (i = 1; i < argc; i++) {
373 	if ((!strcmp(argv[i], "-add")) ||
374 	    (!strcmp(argv[i], "--add"))) {
375 	    if (sgml)
376 		i += 2;
377 	    else
378 		i += 3;
379 	    continue;
380 	} else if ((!strcmp(argv[i], "-del")) ||
381 	    (!strcmp(argv[i], "--del"))) {
382 	    i += 1;
383 
384 	    /* No catalog entry specified */
385 	    if (i == argc || (sgml && i + 1 == argc)) {
386 		fprintf(stderr, "No catalog entry specified to remove from\n");
387 		usage (argv[0]);
388 		return(1);
389 	    }
390 
391 	    continue;
392 	} else if (argv[i][0] == '-')
393 	    continue;
394 
395 	if (filename == NULL && argv[i][0] == '\0') {
396 	    /* Interpret empty-string catalog specification as
397 	       a shortcut for a default system catalog. */
398 	    xmlInitializeCatalog();
399 	} else {
400 	    filename = argv[i];
401 	    ret = xmlLoadCatalog(argv[i]);
402 	    if ((ret < 0) && (create)) {
403 		xmlCatalogAdd(BAD_CAST "catalog", BAD_CAST argv[i], NULL);
404 	    }
405 	}
406 	break;
407     }
408 
409     if (convert)
410         ret = xmlCatalogConvert();
411 
412     if ((add) || (del)) {
413 	for (i = 1; i < argc ; i++) {
414 	    if (!strcmp(argv[i], "-"))
415 		break;
416 
417 	    if (argv[i][0] != '-')
418 		continue;
419 	    if (strcmp(argv[i], "-add") && strcmp(argv[i], "--add") &&
420 		strcmp(argv[i], "-del") && strcmp(argv[i], "--del"))
421 		continue;
422 
423 	    if (sgml) {
424 		/*
425 		 * Maintenance of SGML catalogs.
426 		 */
427 		xmlCatalogPtr catal = NULL;
428 		xmlCatalogPtr super = NULL;
429 
430 		catal = xmlLoadSGMLSuperCatalog(argv[i + 1]);
431 
432 		if ((!strcmp(argv[i], "-add")) ||
433 		    (!strcmp(argv[i], "--add"))) {
434 		    if (catal == NULL)
435 			catal = xmlNewCatalog(1);
436 		    xmlACatalogAdd(catal, BAD_CAST "CATALOG",
437 					 BAD_CAST argv[i + 2], NULL);
438 
439 		    if (!no_super_update) {
440 			super = xmlLoadSGMLSuperCatalog(XML_SGML_DEFAULT_CATALOG);
441 			if (super == NULL)
442 			    super = xmlNewCatalog(1);
443 
444 			xmlACatalogAdd(super, BAD_CAST "CATALOG",
445 					     BAD_CAST argv[i + 1], NULL);
446 		    }
447 		} else {
448 		    if (catal != NULL)
449 			ret = xmlACatalogRemove(catal, BAD_CAST argv[i + 2]);
450 		    else
451 			ret = -1;
452 		    if (ret < 0) {
453 			fprintf(stderr, "Failed to remove entry from %s\n",
454 				argv[i + 1]);
455 			exit_value = 1;
456 		    }
457 		    if ((!no_super_update) && (noout) && (catal != NULL) &&
458 			(xmlCatalogIsEmpty(catal))) {
459 			super = xmlLoadSGMLSuperCatalog(
460 				   XML_SGML_DEFAULT_CATALOG);
461 			if (super != NULL) {
462 			    ret = xmlACatalogRemove(super,
463 				    BAD_CAST argv[i + 1]);
464 			    if (ret < 0) {
465 				fprintf(stderr,
466 					"Failed to remove entry from %s\n",
467 					XML_SGML_DEFAULT_CATALOG);
468 				exit_value = 1;
469 			    }
470 			}
471 		    }
472 		}
473 		if (noout) {
474 		    FILE *out;
475 
476 		    if (xmlCatalogIsEmpty(catal)) {
477 			remove(argv[i + 1]);
478 		    } else {
479 			out = fopen(argv[i + 1], "w");
480 			if (out == NULL) {
481 			    fprintf(stderr, "could not open %s for saving\n",
482 				    argv[i + 1]);
483 			    exit_value = 2;
484 			    noout = 0;
485 			} else {
486 			    xmlACatalogDump(catal, out);
487 			    fclose(out);
488 			}
489 		    }
490 		    if (!no_super_update && super != NULL) {
491 			if (xmlCatalogIsEmpty(super)) {
492 			    remove(XML_SGML_DEFAULT_CATALOG);
493 			} else {
494 			    out = fopen(XML_SGML_DEFAULT_CATALOG, "w");
495 			    if (out == NULL) {
496 				fprintf(stderr,
497 					"could not open %s for saving\n",
498 					XML_SGML_DEFAULT_CATALOG);
499 				exit_value = 2;
500 				noout = 0;
501 			    } else {
502 
503 				xmlACatalogDump(super, out);
504 				fclose(out);
505 			    }
506 			}
507 		    }
508 		} else {
509 		    xmlACatalogDump(catal, stdout);
510 		}
511 		i += 2;
512 	    } else {
513 		if ((!strcmp(argv[i], "-add")) ||
514 		    (!strcmp(argv[i], "--add"))) {
515 			if ((argv[i + 3] == NULL) || (argv[i + 3][0] == 0))
516 			    ret = xmlCatalogAdd(BAD_CAST argv[i + 1], NULL,
517 						BAD_CAST argv[i + 2]);
518 			else
519 			    ret = xmlCatalogAdd(BAD_CAST argv[i + 1],
520 						BAD_CAST argv[i + 2],
521 						BAD_CAST argv[i + 3]);
522 			if (ret != 0) {
523 			    printf("add command failed\n");
524 			    exit_value = 3;
525 			}
526 			i += 3;
527 		} else if ((!strcmp(argv[i], "-del")) ||
528 		    (!strcmp(argv[i], "--del"))) {
529 		    ret = xmlCatalogRemove(BAD_CAST argv[i + 1]);
530 		    if (ret < 0) {
531 			fprintf(stderr, "Failed to remove entry %s\n",
532 				argv[i + 1]);
533 			exit_value = 1;
534 		    }
535 		    i += 1;
536 		}
537 	    }
538 	}
539 
540     } else if (shell) {
541 	usershell();
542     } else {
543 	for (i++; i < argc; i++) {
544 	    xmlURIPtr uri;
545 	    xmlChar *ans;
546 
547 	    uri = xmlParseURI(argv[i]);
548 	    if (uri == NULL) {
549 		ans = xmlCatalogResolvePublic((const xmlChar *) argv[i]);
550 		if (ans == NULL) {
551 		    printf("No entry for PUBLIC %s\n", argv[i]);
552 		    exit_value = 4;
553 		} else {
554 		    printf("%s\n", (char *) ans);
555 		    xmlFree(ans);
556 		}
557 	    } else {
558                 xmlFreeURI(uri);
559 		ans = xmlCatalogResolveSystem((const xmlChar *) argv[i]);
560 		if (ans == NULL) {
561 		    printf("No entry for SYSTEM %s\n", argv[i]);
562 		    ans = xmlCatalogResolveURI ((const xmlChar *) argv[i]);
563 		    if (ans == NULL) {
564 			printf ("No entry for URI %s\n", argv[i]);
565 		        exit_value = 4;
566 		    } else {
567 		        printf("%s\n", (char *) ans);
568 			xmlFree (ans);
569 		    }
570 		} else {
571 		    printf("%s\n", (char *) ans);
572 		    xmlFree(ans);
573 		}
574 	    }
575 	}
576     }
577     if ((!sgml) && ((add) || (del) || (create) || (convert))) {
578 	if (noout && filename && *filename) {
579 	    FILE *out;
580 
581 	    out = fopen(filename, "w");
582 	    if (out == NULL) {
583 		fprintf(stderr, "could not open %s for saving\n", filename);
584 		exit_value = 2;
585 		noout = 0;
586 	    } else {
587 		xmlCatalogDump(out);
588 	    }
589 	} else {
590 	    xmlCatalogDump(stdout);
591 	}
592     }
593 
594     /*
595      * Cleanup and check for memory leaks
596      */
597     xmlCleanupParser();
598     xmlMemoryDump();
599     return(exit_value);
600 }
601 #else
602 int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
603     fprintf(stderr, "libxml was not compiled with catalog and output support\n");
604     return(1);
605 }
606 #endif
607