blob: b293ec35f2e34b8aae1f4f6b2018120fca9192db [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>
30
31static int shell = 0;
32static int noout = 0;
Daniel Veillarde7ead2d2001-08-22 23:44:09 +000033static int create = 0;
Daniel Veillardcda96922001-08-21 10:56:31 +000034static int add = 0;
35static int del = 0;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +000036static int convert = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +000037static int verbose = 0;
Daniel Veillardcda96922001-08-21 10:56:31 +000038static char *filename;
Daniel Veillard344cee72001-08-20 00:08:40 +000039
40#ifdef LIBXML_CATALOG_ENABLED
41/************************************************************************
42 * *
43 * Shell Interface *
44 * *
45 ************************************************************************/
46/**
47 * xmlShellReadline:
48 * @prompt: the prompt value
49 *
50 * Read a string
51 *
52 * Returns a pointer to it or NULL on EOF the caller is expected to
53 * free the returned string.
54 */
55static char *
56xmlShellReadline(const char *prompt) {
57#ifdef HAVE_LIBREADLINE
58 char *line_read;
59
60 /* Get a line from the user. */
61 line_read = readline (prompt);
62
63 /* If the line has any text in it, save it on the history. */
64 if (line_read && *line_read)
65 add_history (line_read);
66
67 return (line_read);
68#else
69 char line_read[501];
70
71 if (prompt != NULL)
72 fprintf(stdout, "%s", prompt);
73 if (!fgets(line_read, 500, stdin))
74 return(NULL);
75 line_read[500] = 0;
76 return(strdup(line_read));
77#endif
78}
79
80
81static void usershell(void) {
82 char *cmdline = NULL, *cur;
83 int nbargs;
84 char command[100];
85 char arg[400];
Daniel Veillardcda96922001-08-21 10:56:31 +000086 char *argv[20];
87 int i, ret;
Daniel Veillardcda96922001-08-21 10:56:31 +000088 xmlChar *ans;
Daniel Veillard344cee72001-08-20 00:08:40 +000089
90 while (1) {
91 cmdline = xmlShellReadline("> ");
92 if (cmdline == NULL)
93 return;
94
95 /*
96 * Parse the command itself
97 */
98 cur = cmdline;
99 nbargs = 0;
100 while ((*cur == ' ') || (*cur == '\t')) cur++;
101 i = 0;
102 while ((*cur != ' ') && (*cur != '\t') &&
103 (*cur != '\n') && (*cur != '\r')) {
104 if (*cur == 0)
105 break;
106 command[i++] = *cur++;
107 }
108 command[i] = 0;
109 if (i == 0) continue;
110 nbargs++;
111
112 /*
Daniel Veillardcda96922001-08-21 10:56:31 +0000113 * Parse the argument string
Daniel Veillard344cee72001-08-20 00:08:40 +0000114 */
Daniel Veillardcda96922001-08-21 10:56:31 +0000115 memset(arg, 0, sizeof(arg));
Daniel Veillard344cee72001-08-20 00:08:40 +0000116 while ((*cur == ' ') || (*cur == '\t')) cur++;
117 i = 0;
118 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
119 if (*cur == 0)
120 break;
121 arg[i++] = *cur++;
122 }
123 arg[i] = 0;
124 if (i != 0)
125 nbargs++;
126
127 /*
Daniel Veillardcda96922001-08-21 10:56:31 +0000128 * Parse the arguments
129 */
130 i = 0;
131 nbargs = 0;
132 cur = arg;
133 memset(argv, 0, sizeof(argv));
134 while (*cur != 0) {
135 while ((*cur == ' ') || (*cur == '\t')) cur++;
136 if (*cur == '\'') {
137 cur++;
138 argv[i] = cur;
139 while ((*cur != 0) && (*cur != '\'')) cur++;
140 if (*cur == '\'') {
141 *cur = 0;
142 nbargs++;
143 i++;
144 cur++;
145 }
146 } else if (*cur == '"') {
147 cur++;
148 argv[i] = cur;
149 while ((*cur != 0) && (*cur != '"')) cur++;
150 if (*cur == '"') {
151 *cur = 0;
152 nbargs++;
153 i++;
154 cur++;
155 }
156 } else {
157 argv[i] = cur;
158 while ((*cur != 0) && (*cur != ' ') && (*cur != '\t'))
159 cur++;
160 *cur = 0;
161 nbargs++;
162 i++;
163 cur++;
164 }
165 }
166
167 /*
Daniel Veillard344cee72001-08-20 00:08:40 +0000168 * start interpreting the command
169 */
170 if (!strcmp(command, "exit"))
171 break;
172 if (!strcmp(command, "quit"))
173 break;
174 if (!strcmp(command, "bye"))
175 break;
176 if (!strcmp(command, "public")) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000177 if (nbargs != 1) {
178 printf("public requires 1 arguments\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000179 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000180 ans = xmlCatalogResolvePublic((const xmlChar *) argv[0]);
181 if (ans == NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000182 printf("No entry for PUBLIC %s\n", argv[0]);
183 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000184 printf("%s\n", ans);
185 xmlFree(ans);
Daniel Veillardcda96922001-08-21 10:56:31 +0000186 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000187 }
188 } else if (!strcmp(command, "system")) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000189 if (nbargs != 1) {
190 printf("system requires 1 arguments\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000191 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000192 ans = xmlCatalogResolveSystem((const xmlChar *) argv[0]);
193 if (ans == NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000194 printf("No entry for SYSTEM %s\n", argv[0]);
195 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000196 printf("%s\n", ans);
197 xmlFree(ans);
Daniel Veillardcda96922001-08-21 10:56:31 +0000198 }
199 }
200 } else if (!strcmp(command, "add")) {
201 if ((nbargs != 3) && (nbargs != 2)) {
202 printf("add requires 2 or 3 arguments\n");
203 } else {
204 if (argv[2] == NULL)
205 ret = xmlCatalogAdd(BAD_CAST argv[0], NULL,
206 BAD_CAST argv[1]);
207 else
208 ret = xmlCatalogAdd(BAD_CAST argv[0], BAD_CAST argv[1],
209 BAD_CAST argv[2]);
210 if (ret != 0)
211 printf("add command failed\n");
212 }
213 } else if (!strcmp(command, "del")) {
214 if (nbargs != 1) {
215 printf("del requires 1\n");
216 } else {
217 ret = xmlCatalogRemove(BAD_CAST argv[0]);
218 if (ret <= 0)
219 printf("del command failed\n");
220
221 }
222 } else if (!strcmp(command, "resolve")) {
223 if (nbargs != 2) {
224 printf("resolve requires 2 arguments\n");
225 } else {
226 ans = xmlCatalogResolve(BAD_CAST argv[0],
227 BAD_CAST argv[1]);
228 if (ans == NULL) {
229 printf("Resolver failed to find an answer\n");
230 } else {
231 printf("%s\n", ans);
232 xmlFree(ans);
233 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000234 }
235 } else if (!strcmp(command, "dump")) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000236 if (nbargs != 0) {
237 printf("dump has no arguments\n");
238 } else {
239 xmlCatalogDump(stdout);
240 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000241 } else if (!strcmp(command, "debug")) {
242 if (nbargs != 0) {
243 printf("debug has no arguments\n");
244 } else {
245 verbose++;
246 xmlCatalogSetDebug(verbose);
247 }
248 } else if (!strcmp(command, "quiet")) {
249 if (nbargs != 0) {
250 printf("quiet has no arguments\n");
251 } else {
252 if (verbose > 0)
253 verbose--;
254 xmlCatalogSetDebug(verbose);
255 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000256 } else {
257 if (strcmp(command, "help")) {
258 printf("Unrecognized command %s\n", command);
259 }
260 printf("Commands available:\n");
261 printf("\tpublic PublicID: make a PUBLIC identifier lookup\n");
262 printf("\tsystem SystemID: make a SYSTEM identifier lookup\n");
Daniel Veillardcda96922001-08-21 10:56:31 +0000263 printf("\tresolve PublicID SystemID: do a full resolver lookup\n");
264 printf("\tadd 'type' 'orig' 'replace' : add an entry\n");
265 printf("\tdel 'values' : remove values\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000266 printf("\tdump: print the current catalog state\n");
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000267 printf("\tdebug: increase the verbosity level\n");
268 printf("\tquiet: decrease the verbosity level\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000269 printf("\texit: quit the shell\n");
270 }
271 free(cmdline); /* not xmlFree here ! */
272 }
273}
274
275/************************************************************************
276 * *
277 * Main *
278 * *
279 ************************************************************************/
280static void usage(const char *name) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000281 printf("Usage : %s [options] catalogfile entities...\n", name);
282 printf("\tParse the catalog file and query it for the entities\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000283 printf("\t--shell : run a shell allowing interactive queries\n");
Daniel Veillarde7ead2d2001-08-22 23:44:09 +0000284 printf("\t--create : create a new catalog\n");
Daniel Veillardcda96922001-08-21 10:56:31 +0000285 printf("\t--add 'type' 'orig' 'replace' : add an entry\n");
286 printf("\t--del 'values' : remove values\n");
287 printf("\t--noout: avoid dumping the result on stdout\n");
288 printf("\t used with add or del, it saves the catalog changes\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000289 printf("\t-v --verbose : provide debug informations\n");
290}
291int main(int argc, char **argv) {
292 int i;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000293 int ret;
294
Daniel Veillard344cee72001-08-20 00:08:40 +0000295
296 if (argc <= 1) {
297 usage(argv[0]);
298 return(1);
299 }
300
301 LIBXML_TEST_VERSION
302 for (i = 1; i < argc ; i++) {
303 if (!strcmp(argv[i], "-"))
304 break;
305
306 if (argv[i][0] != '-')
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000307 break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000308 if ((!strcmp(argv[i], "-verbose")) ||
309 (!strcmp(argv[i], "-v")) ||
310 (!strcmp(argv[i], "--verbose"))) {
311 verbose++;
312 xmlCatalogSetDebug(verbose);
Daniel Veillardcda96922001-08-21 10:56:31 +0000313 } else if ((!strcmp(argv[i], "-noout")) ||
314 (!strcmp(argv[i], "--noout"))) {
315 noout = 1;
Daniel Veillard344cee72001-08-20 00:08:40 +0000316 } else if ((!strcmp(argv[i], "-shell")) ||
317 (!strcmp(argv[i], "--shell"))) {
318 shell++;
319 noout = 1;
Daniel Veillarde7ead2d2001-08-22 23:44:09 +0000320 } else if ((!strcmp(argv[i], "-create")) ||
321 (!strcmp(argv[i], "--create"))) {
322 create++;
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000323 } else if ((!strcmp(argv[i], "-convert")) ||
324 (!strcmp(argv[i], "--convert"))) {
325 convert++;
Daniel Veillardcda96922001-08-21 10:56:31 +0000326 } else if ((!strcmp(argv[i], "-add")) ||
327 (!strcmp(argv[i], "--add"))) {
328 i += 3;
329 add++;
330 } else if ((!strcmp(argv[i], "-del")) ||
331 (!strcmp(argv[i], "--del"))) {
332 i += 1;
333 del++;
Daniel Veillard344cee72001-08-20 00:08:40 +0000334 } else {
335 fprintf(stderr, "Unknown option %s\n", argv[i]);
336 usage(argv[0]);
337 return(1);
338 }
339 }
340
341 for (i = 1; i < argc; i++) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000342 if ((!strcmp(argv[i], "-add")) ||
343 (!strcmp(argv[i], "--add"))) {
344 i += 3;
Daniel Veillard344cee72001-08-20 00:08:40 +0000345 continue;
Daniel Veillardcda96922001-08-21 10:56:31 +0000346 } else if ((!strcmp(argv[i], "-del")) ||
347 (!strcmp(argv[i], "--del"))) {
348 i += 1;
349 continue;
350 } else if (argv[i][0] == '-')
351 continue;
352 filename = argv[i];
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000353 ret = xmlLoadCatalog(argv[i]);
354 if ((ret < 0) && (create)) {
Daniel Veillarde7ead2d2001-08-22 23:44:09 +0000355 xmlCatalogAdd(BAD_CAST "catalog", BAD_CAST argv[i], NULL);
356 }
Daniel Veillardcda96922001-08-21 10:56:31 +0000357 break;
358 }
359
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000360 if (convert)
361 ret = xmlCatalogConvert();
Daniel Veillardcda96922001-08-21 10:56:31 +0000362
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000363 if ((add) || (del)) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000364 for (i = 1; i < argc ; i++) {
365 if (!strcmp(argv[i], "-"))
366 break;
367
368 if (argv[i][0] != '-')
369 continue;
370 if ((!strcmp(argv[i], "-add")) ||
371 (!strcmp(argv[i], "--add"))) {
372 if ((argv[i + 3] == NULL) || (argv[i + 3][0] == 0))
373 ret = xmlCatalogAdd(BAD_CAST argv[i + 1], NULL,
374 BAD_CAST argv[i + 2]);
375 else
376 ret = xmlCatalogAdd(BAD_CAST argv[i + 1],
377 BAD_CAST argv[i + 2],
378 BAD_CAST argv[i + 3]);
379 if (ret != 0)
380 printf("add command failed\n");
381 i += 3;
382 } else if ((!strcmp(argv[i], "-del")) ||
383 (!strcmp(argv[i], "--del"))) {
384 ret = xmlCatalogRemove(BAD_CAST argv[i + 1]);
385 i += 1;
386 }
387 }
388
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000389 } else if (shell) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000390 usershell();
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000391 } else {
392 for (i++; i < argc; i++) {
393 xmlURIPtr uri;
394 xmlChar *ans;
395
396 uri = xmlParseURI(argv[i]);
397 if (uri == NULL) {
398 ans = xmlCatalogResolvePublic((const xmlChar *) argv[i]);
399 if (ans == NULL) {
400 printf("No entry for PUBLIC %s\n", argv[i]);
401 } else {
402 printf("%s\n", ans);
403 xmlFree(ans);
404 }
405 } else {
406 xmlFreeURI(uri);
407 ans = xmlCatalogResolveSystem((const xmlChar *) argv[i]);
408 if (ans == NULL) {
409 printf("No entry for SYSTEM %s\n", argv[i]);
410 } else {
411 printf("%s\n", ans);
412 xmlFree(ans);
413 }
414 }
415 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000416 }
Daniel Veillard6c5f9d12001-08-25 13:33:14 +0000417 if ((add) || (del) || (create) || (convert)) {
Daniel Veillarde7ead2d2001-08-22 23:44:09 +0000418 if (noout) {
419 FILE *out;
420
421 out = fopen(filename, "w");
422 if (out == NULL) {
423 fprintf(stderr, "could not open %s for saving\n", filename);
424 noout = 0;
425 } else {
426 xmlCatalogDump(out);
427 }
428 } else {
429 xmlCatalogDump(stdout);
430 }
431 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000432
433 /*
434 * Cleanup and check for memory leaks
435 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000436 xmlCleanupParser();
437 xmlMemoryDump();
438 return(0);
439}
440#else
441int main(int argc, char **argv) {
442 fprintf(stderr, "libxml was not compiled with catalog support\n");
443 return(1);
444}
445#endif