blob: eb2fa6a048fb9510468cd7aa5cdb2f82f2dd42bd [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 Veillardcda96922001-08-21 10:56:31 +000029static int add = 0;
30static int del = 0;
Daniel Veillard344cee72001-08-20 00:08:40 +000031static int verbose = 0;
Daniel Veillardcda96922001-08-21 10:56:31 +000032static char *filename;
Daniel Veillard344cee72001-08-20 00:08:40 +000033
34#ifdef LIBXML_CATALOG_ENABLED
35/************************************************************************
36 * *
37 * Shell Interface *
38 * *
39 ************************************************************************/
40/**
41 * xmlShellReadline:
42 * @prompt: the prompt value
43 *
44 * Read a string
45 *
46 * Returns a pointer to it or NULL on EOF the caller is expected to
47 * free the returned string.
48 */
49static char *
50xmlShellReadline(const char *prompt) {
51#ifdef HAVE_LIBREADLINE
52 char *line_read;
53
54 /* Get a line from the user. */
55 line_read = readline (prompt);
56
57 /* If the line has any text in it, save it on the history. */
58 if (line_read && *line_read)
59 add_history (line_read);
60
61 return (line_read);
62#else
63 char line_read[501];
64
65 if (prompt != NULL)
66 fprintf(stdout, "%s", prompt);
67 if (!fgets(line_read, 500, stdin))
68 return(NULL);
69 line_read[500] = 0;
70 return(strdup(line_read));
71#endif
72}
73
74
75static void usershell(void) {
76 char *cmdline = NULL, *cur;
77 int nbargs;
78 char command[100];
79 char arg[400];
Daniel Veillardcda96922001-08-21 10:56:31 +000080 char *argv[20];
81 int i, ret;
Daniel Veillardcda96922001-08-21 10:56:31 +000082 xmlChar *ans;
Daniel Veillard344cee72001-08-20 00:08:40 +000083
84 while (1) {
85 cmdline = xmlShellReadline("> ");
86 if (cmdline == NULL)
87 return;
88
89 /*
90 * Parse the command itself
91 */
92 cur = cmdline;
93 nbargs = 0;
94 while ((*cur == ' ') || (*cur == '\t')) cur++;
95 i = 0;
96 while ((*cur != ' ') && (*cur != '\t') &&
97 (*cur != '\n') && (*cur != '\r')) {
98 if (*cur == 0)
99 break;
100 command[i++] = *cur++;
101 }
102 command[i] = 0;
103 if (i == 0) continue;
104 nbargs++;
105
106 /*
Daniel Veillardcda96922001-08-21 10:56:31 +0000107 * Parse the argument string
Daniel Veillard344cee72001-08-20 00:08:40 +0000108 */
Daniel Veillardcda96922001-08-21 10:56:31 +0000109 memset(arg, 0, sizeof(arg));
Daniel Veillard344cee72001-08-20 00:08:40 +0000110 while ((*cur == ' ') || (*cur == '\t')) cur++;
111 i = 0;
112 while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
113 if (*cur == 0)
114 break;
115 arg[i++] = *cur++;
116 }
117 arg[i] = 0;
118 if (i != 0)
119 nbargs++;
120
121 /*
Daniel Veillardcda96922001-08-21 10:56:31 +0000122 * Parse the arguments
123 */
124 i = 0;
125 nbargs = 0;
126 cur = arg;
127 memset(argv, 0, sizeof(argv));
128 while (*cur != 0) {
129 while ((*cur == ' ') || (*cur == '\t')) cur++;
130 if (*cur == '\'') {
131 cur++;
132 argv[i] = cur;
133 while ((*cur != 0) && (*cur != '\'')) cur++;
134 if (*cur == '\'') {
135 *cur = 0;
136 nbargs++;
137 i++;
138 cur++;
139 }
140 } else if (*cur == '"') {
141 cur++;
142 argv[i] = cur;
143 while ((*cur != 0) && (*cur != '"')) cur++;
144 if (*cur == '"') {
145 *cur = 0;
146 nbargs++;
147 i++;
148 cur++;
149 }
150 } else {
151 argv[i] = cur;
152 while ((*cur != 0) && (*cur != ' ') && (*cur != '\t'))
153 cur++;
154 *cur = 0;
155 nbargs++;
156 i++;
157 cur++;
158 }
159 }
160
161 /*
Daniel Veillard344cee72001-08-20 00:08:40 +0000162 * start interpreting the command
163 */
164 if (!strcmp(command, "exit"))
165 break;
166 if (!strcmp(command, "quit"))
167 break;
168 if (!strcmp(command, "bye"))
169 break;
170 if (!strcmp(command, "public")) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000171 if (nbargs != 1) {
172 printf("public requires 1 arguments\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000173 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000174 ans = xmlCatalogResolvePublic((const xmlChar *) argv[0]);
175 if (ans == NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000176 printf("No entry for PUBLIC %s\n", argv[0]);
177 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000178 printf("%s\n", ans);
179 xmlFree(ans);
Daniel Veillardcda96922001-08-21 10:56:31 +0000180 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000181 }
182 } else if (!strcmp(command, "system")) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000183 if (nbargs != 1) {
184 printf("system requires 1 arguments\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000185 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000186 ans = xmlCatalogResolveSystem((const xmlChar *) argv[0]);
187 if (ans == NULL) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000188 printf("No entry for SYSTEM %s\n", argv[0]);
189 } else {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000190 printf("%s\n", ans);
191 xmlFree(ans);
Daniel Veillardcda96922001-08-21 10:56:31 +0000192 }
193 }
194 } else if (!strcmp(command, "add")) {
195 if ((nbargs != 3) && (nbargs != 2)) {
196 printf("add requires 2 or 3 arguments\n");
197 } else {
198 if (argv[2] == NULL)
199 ret = xmlCatalogAdd(BAD_CAST argv[0], NULL,
200 BAD_CAST argv[1]);
201 else
202 ret = xmlCatalogAdd(BAD_CAST argv[0], BAD_CAST argv[1],
203 BAD_CAST argv[2]);
204 if (ret != 0)
205 printf("add command failed\n");
206 }
207 } else if (!strcmp(command, "del")) {
208 if (nbargs != 1) {
209 printf("del requires 1\n");
210 } else {
211 ret = xmlCatalogRemove(BAD_CAST argv[0]);
212 if (ret <= 0)
213 printf("del command failed\n");
214
215 }
216 } else if (!strcmp(command, "resolve")) {
217 if (nbargs != 2) {
218 printf("resolve requires 2 arguments\n");
219 } else {
220 ans = xmlCatalogResolve(BAD_CAST argv[0],
221 BAD_CAST argv[1]);
222 if (ans == NULL) {
223 printf("Resolver failed to find an answer\n");
224 } else {
225 printf("%s\n", ans);
226 xmlFree(ans);
227 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000228 }
229 } else if (!strcmp(command, "dump")) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000230 if (nbargs != 0) {
231 printf("dump has no arguments\n");
232 } else {
233 xmlCatalogDump(stdout);
234 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000235 } else if (!strcmp(command, "debug")) {
236 if (nbargs != 0) {
237 printf("debug has no arguments\n");
238 } else {
239 verbose++;
240 xmlCatalogSetDebug(verbose);
241 }
242 } else if (!strcmp(command, "quiet")) {
243 if (nbargs != 0) {
244 printf("quiet has no arguments\n");
245 } else {
246 if (verbose > 0)
247 verbose--;
248 xmlCatalogSetDebug(verbose);
249 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000250 } else {
251 if (strcmp(command, "help")) {
252 printf("Unrecognized command %s\n", command);
253 }
254 printf("Commands available:\n");
255 printf("\tpublic PublicID: make a PUBLIC identifier lookup\n");
256 printf("\tsystem SystemID: make a SYSTEM identifier lookup\n");
Daniel Veillardcda96922001-08-21 10:56:31 +0000257 printf("\tresolve PublicID SystemID: do a full resolver lookup\n");
258 printf("\tadd 'type' 'orig' 'replace' : add an entry\n");
259 printf("\tdel 'values' : remove values\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000260 printf("\tdump: print the current catalog state\n");
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000261 printf("\tdebug: increase the verbosity level\n");
262 printf("\tquiet: decrease the verbosity level\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000263 printf("\texit: quit the shell\n");
264 }
265 free(cmdline); /* not xmlFree here ! */
266 }
267}
268
269/************************************************************************
270 * *
271 * Main *
272 * *
273 ************************************************************************/
274static void usage(const char *name) {
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000275 printf("Usage : %s [options] catalogfile entities...\n", name);
276 printf("\tParse the catalog file and query it for the entities\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000277 printf("\t--shell : run a shell allowing interactive queries\n");
Daniel Veillardcda96922001-08-21 10:56:31 +0000278 printf("\t--add 'type' 'orig' 'replace' : add an entry\n");
279 printf("\t--del 'values' : remove values\n");
280 printf("\t--noout: avoid dumping the result on stdout\n");
281 printf("\t used with add or del, it saves the catalog changes\n");
Daniel Veillard344cee72001-08-20 00:08:40 +0000282 printf("\t-v --verbose : provide debug informations\n");
283}
284int main(int argc, char **argv) {
285 int i;
286
287 if (argc <= 1) {
288 usage(argv[0]);
289 return(1);
290 }
291
292 LIBXML_TEST_VERSION
293 for (i = 1; i < argc ; i++) {
294 if (!strcmp(argv[i], "-"))
295 break;
296
297 if (argv[i][0] != '-')
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000298 break;
Daniel Veillard344cee72001-08-20 00:08:40 +0000299 if ((!strcmp(argv[i], "-verbose")) ||
300 (!strcmp(argv[i], "-v")) ||
301 (!strcmp(argv[i], "--verbose"))) {
302 verbose++;
303 xmlCatalogSetDebug(verbose);
Daniel Veillardcda96922001-08-21 10:56:31 +0000304 } else if ((!strcmp(argv[i], "-noout")) ||
305 (!strcmp(argv[i], "--noout"))) {
306 noout = 1;
Daniel Veillard344cee72001-08-20 00:08:40 +0000307 } else if ((!strcmp(argv[i], "-shell")) ||
308 (!strcmp(argv[i], "--shell"))) {
309 shell++;
310 noout = 1;
Daniel Veillardcda96922001-08-21 10:56:31 +0000311 } else if ((!strcmp(argv[i], "-add")) ||
312 (!strcmp(argv[i], "--add"))) {
313 i += 3;
314 add++;
315 } else if ((!strcmp(argv[i], "-del")) ||
316 (!strcmp(argv[i], "--del"))) {
317 i += 1;
318 del++;
Daniel Veillard344cee72001-08-20 00:08:40 +0000319 } else {
320 fprintf(stderr, "Unknown option %s\n", argv[i]);
321 usage(argv[0]);
322 return(1);
323 }
324 }
325
326 for (i = 1; i < argc; i++) {
Daniel Veillardcda96922001-08-21 10:56:31 +0000327 if ((!strcmp(argv[i], "-add")) ||
328 (!strcmp(argv[i], "--add"))) {
329 i += 3;
Daniel Veillard344cee72001-08-20 00:08:40 +0000330 continue;
Daniel Veillardcda96922001-08-21 10:56:31 +0000331 } else if ((!strcmp(argv[i], "-del")) ||
332 (!strcmp(argv[i], "--del"))) {
333 i += 1;
334 continue;
335 } else if (argv[i][0] == '-')
336 continue;
337 filename = argv[i];
Daniel Veillard344cee72001-08-20 00:08:40 +0000338 xmlLoadCatalog(argv[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +0000339 break;
340 }
341
342 if ((add) || (del)) {
343 int ret;
344
345 for (i = 1; i < argc ; i++) {
346 if (!strcmp(argv[i], "-"))
347 break;
348
349 if (argv[i][0] != '-')
350 continue;
351 if ((!strcmp(argv[i], "-add")) ||
352 (!strcmp(argv[i], "--add"))) {
353 if ((argv[i + 3] == NULL) || (argv[i + 3][0] == 0))
354 ret = xmlCatalogAdd(BAD_CAST argv[i + 1], NULL,
355 BAD_CAST argv[i + 2]);
356 else
357 ret = xmlCatalogAdd(BAD_CAST argv[i + 1],
358 BAD_CAST argv[i + 2],
359 BAD_CAST argv[i + 3]);
360 if (ret != 0)
361 printf("add command failed\n");
362 i += 3;
363 } else if ((!strcmp(argv[i], "-del")) ||
364 (!strcmp(argv[i], "--del"))) {
365 ret = xmlCatalogRemove(BAD_CAST argv[i + 1]);
366 i += 1;
367 }
368 }
369
370 if (noout) {
371 FILE *out;
372
373 out = fopen(filename, "w");
374 if (out == NULL) {
375 fprintf(stderr, "could not open %s for saving\n", filename);
376 noout = 0;
377 } else {
378 xmlCatalogDump(out);
379 }
380 }
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000381 } else if (shell) {
Daniel Veillard344cee72001-08-20 00:08:40 +0000382 usershell();
Daniel Veillarde2940dd2001-08-22 00:06:49 +0000383 } else {
384 for (i++; i < argc; i++) {
385 xmlURIPtr uri;
386 xmlChar *ans;
387
388 uri = xmlParseURI(argv[i]);
389 if (uri == NULL) {
390 ans = xmlCatalogResolvePublic((const xmlChar *) argv[i]);
391 if (ans == NULL) {
392 printf("No entry for PUBLIC %s\n", argv[i]);
393 } else {
394 printf("%s\n", ans);
395 xmlFree(ans);
396 }
397 } else {
398 xmlFreeURI(uri);
399 ans = xmlCatalogResolveSystem((const xmlChar *) argv[i]);
400 if (ans == NULL) {
401 printf("No entry for SYSTEM %s\n", argv[i]);
402 } else {
403 printf("%s\n", ans);
404 xmlFree(ans);
405 }
406 }
407 }
Daniel Veillard344cee72001-08-20 00:08:40 +0000408 }
409
410 /*
411 * Cleanup and check for memory leaks
412 */
Daniel Veillard344cee72001-08-20 00:08:40 +0000413 xmlCleanupParser();
414 xmlMemoryDump();
415 return(0);
416}
417#else
418int main(int argc, char **argv) {
419 fprintf(stderr, "libxml was not compiled with catalog support\n");
420 return(1);
421}
422#endif