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