xmlcatalog.c 14 KB

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