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