home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / dev / lang / sgmls / src / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-10  |  14.1 KB  |  651 lines

  1. /* main.c -
  2.    Main program for sgmls.
  3.  
  4.      Written by James Clark (jjc@jclark.com).
  5. */
  6.  
  7. #include "config.h"
  8. #include "std.h"
  9. #include "getopt.h"
  10. #include "entity.h"           /* Templates for entity control blocks. */
  11. #include "adl.h"              /* Definitions for attribute list processing. */
  12. #include "sgmlmain.h"         /* Main interface to SGML services. */
  13. #include "appl.h"
  14. #include "alloc.h"
  15.  
  16. #define READCNT 512
  17.  
  18. /* Before using argv[0] in error messages, strip off everything up to and
  19. including the last character in prog that occurs in PROG_PREFIX. */
  20.  
  21. #ifndef PROG_PREFIX
  22. #define PROG_PREFIX "/"
  23. #endif /* not PROG_PREFIX */
  24.  
  25. /* Message catalogue name. */
  26. #define CAT_NAME "sgmls"
  27. /* Message set to use for application error messages. */
  28. #define APP_SET 4
  29. /* Message set to use for error messages from catalog.c. */
  30. #define CAT_SET 5
  31. #define CATALOG_ERROR_HEADER_MSGNO 20
  32. #define CATALOG_ERROR_HEADER_TEXT "Catalog error at %s, line %lu"
  33.  
  34. #ifdef HAVE_EXTENDED_PRINTF
  35. #define xvfprintf vfprintf
  36. #else
  37. extern int xvfprintf P((FILE *, char *, va_list));
  38. #endif
  39.  
  40. static VOID usage P((void));
  41. static VOID fatal VP((int, ...));
  42. static VOID do_error P((int, va_list));
  43. static VOID swinit P((struct switches *));
  44. static VOID write_caps P((char *, struct sgmlcap *));
  45. static VOID do_catalog_error();
  46.  
  47. static UNIV make_docent P((int, char **));
  48. static char *munge_program_name P((char *, char *));
  49. static VOID die P((void));
  50. #ifdef SUPPORT_SUBDOC
  51. static VOID build_subargv P((struct switches *));
  52. static VOID cleanup P((void));
  53. static char *create_subcap_file P((void));
  54. #endif /* SUPPORT_SUBDOC */
  55.  
  56. static char *errlist[] = {
  57.      0,
  58.      "Out of memory",
  59.      "Cannot open SGML document entity",
  60.      "Cannot exec `%s': %s",
  61.      "Cannot fork: %s",
  62.      "Error waiting for process: %s",
  63.      "Program %s got fatal signal %d",
  64.      "Cannot open `%s': %s",
  65.      "Subdocument capacity botch",
  66.      "Non-existent subdocument entity `%s' not processed",
  67. };
  68.  
  69. int suppsw = 0;            /* Non-zero means suppress output. */
  70. int locsw = 0;            /* Non-zero means generate location info. */
  71. static char *prog;        /* Program name (for error messages). */
  72. static nl_catd catd;        /* Message catalogue descriptor. */
  73. static char *capfile = 0;    /* File for capacity report. */
  74. extern char *version_string;
  75. static CATALOG catalog;            /* Entity catalog. */
  76.  
  77. char options[] = {
  78.      'c', ':', 'd', 'e', 'g', 'i', ':', 'l', 'o', ':', 'p', 'r', 's', 'u', 'v',
  79.      'm', ':',
  80. #ifdef CANT_REDIRECT_STDERR
  81.      'f', ':',
  82. #endif /* CANT_REDIRECT_STDERR */
  83. #ifdef TRACE
  84.      'x', ':', 'y', ':',
  85. #endif /* TRACE */
  86.      '\0'
  87. };
  88.  
  89. #ifdef SUPPORT_SUBDOC
  90. int suberr = 0;            /* Error in subdocument. */
  91. static char *subargv[sizeof(options)];
  92. static int subargc = 0;
  93. static char nopenbuf[sizeof(long)*3 + 1];
  94. static char sgmldecl_file[L_tmpnam];
  95. static char subcap_file[L_tmpnam];
  96. #endif
  97.  
  98. int main(argc, argv)
  99. int argc;
  100. char **argv;
  101. {
  102.      static char stderr_buf[BUFSIZ];
  103.      int opt;
  104. #ifdef CANT_REDIRECT_STDERR
  105.      char *errfile = 0;
  106. #endif
  107.      struct sgmlcap cap;
  108.      struct switches sw;
  109.      int nincludes = 0;          /* number of -i options */
  110.      setbuf(stderr, stderr_buf);
  111.  
  112.      /* Define MAIN_HOOK in config.h if some function needs to be called here. */
  113. #ifdef MAIN_HOOK
  114.      MAIN_HOOK(argc, argv);
  115. #endif
  116. #ifdef SUPPORT_SUBDOC
  117.      subargv[subargc++] = argv[0];
  118. #endif
  119.  
  120.      prog = argv[0] = munge_program_name(argv[0], "sgmls");
  121.  
  122.      catd = catopen(CAT_NAME, 0);
  123.      catalog = catalog_create(do_catalog_error);
  124.      swinit(&sw);
  125.  
  126.      while ((opt = getopt(argc, argv, options)) != EOF) {
  127.       switch (opt) {
  128.       case 'm':
  129.            catalog_load_file(catalog, optarg);
  130.            break;
  131.       case 'l':          /* Generate location information. */
  132.            locsw = 1;
  133.            break;
  134.       case 'c':          /* Print capacity usage. */
  135.            sw.swcap = 1;
  136.            capfile = optarg;
  137.            break;
  138.       case 's':          /* Suppress output. */
  139.            suppsw = 1;
  140.            break;
  141.       case 'd':           /* Report duplicate entity declarations. */
  142.            sw.swdupent = 1;
  143.            break;
  144.       case 'e':           /* Provide entity stack trace in error msg. */
  145.            sw.swenttr = 1;
  146.            break;
  147. #ifdef CANT_REDIRECT_STDERR
  148.       case 'f':          /* Redirect errors. */
  149.            errfile = optarg;
  150.            break;
  151. #endif /* CANT_REDIRECT_STDERR */
  152.       case 'g':           /* Provide GI stack trace in error messages. */
  153.            sw.sweltr = 1;
  154.            break;
  155.       case 'p':          /* Parse only the prolog. */
  156.            sw.onlypro = 1;
  157.            suppsw = 1;
  158.            break;
  159.       case 'r':           /* Give warning for defaulted references. */
  160.            sw.swrefmsg = 1;
  161.            break;
  162.       case 'u':
  163.            sw.swundef = 1;
  164.            break;
  165. #ifdef TRACE
  166.       case 'x':           /* Trace options for the document body. */
  167.            sw.trace = optarg;
  168.            break;
  169.       case 'y':           /* Trace options for the prolog. */
  170.            sw.ptrace =  optarg;
  171.            break;
  172. #endif /* TRACE */
  173.       case 'v':           /* Print the version number. */
  174.            fprintf(stderr, "sgmls version %s\n", version_string);
  175.            fflush(stderr);
  176.            break;
  177.       case 'o':
  178.            sw.nopen = atol(optarg);
  179.            if (sw.nopen <= 0)
  180.             usage();
  181.            break;
  182.       case 'i':          /* Define parameter entity as "INCLUDE". */
  183.            sw.includes = (char **)xrealloc((UNIV)sw.includes,
  184.                            (nincludes + 2)*sizeof(char *));
  185.            sw.includes[nincludes++] = optarg;
  186.            sw.includes[nincludes] = 0;
  187.            break;
  188.       case '?':
  189.            usage();
  190.       default:
  191.            abort();
  192.       }
  193.      }
  194.  
  195. #ifdef CANT_REDIRECT_STDERR
  196.      if (errfile) {
  197.       FILE *fp;
  198.       errno = 0;
  199.       fp = fopen(errfile, "w");
  200.       if (!fp)
  201.            fatal(E_OPEN, errfile, strerror(errno));
  202.       fclose(fp);
  203.       errno = 0;
  204.       if (!freopen(errfile, "w", stderr)) {
  205.            /* Can't use fatal() since stderr is now closed */
  206.            printf("%s: ", prog);
  207.            printf(errlist[E_OPEN], errfile, strerror(errno));
  208.            putchar('\n');
  209.            exit(EXIT_FAILURE);
  210.       }
  211.      }
  212. #endif /* CANT_REDIRECT_STDERR */
  213.  
  214.      (void)sgmlset(&sw);
  215.  
  216. #ifdef SUPPORT_SUBDOC
  217.      build_subargv(&sw);
  218. #endif
  219.      if (sgmlsdoc(make_docent(argc - optind, argv + optind)))
  220.       fatal(E_DOC);
  221.  
  222.      process_document(sw.nopen > 0);
  223.      sgmlend(&cap);
  224.      if (capfile)
  225.       write_caps(capfile, &cap);
  226. #ifdef SUPPORT_SUBDOC
  227.      cleanup();
  228.      if (suberr)
  229.       exit(EXIT_FAILURE);
  230. #endif /* SUPPORT_SUBDOC */
  231.      if (sgmlgcnterr() > 0)
  232.       exit(EXIT_FAILURE);
  233.      if (!sw.nopen)
  234.       output_conforming();
  235.      exit(EXIT_SUCCESS);
  236. }
  237.  
  238. static char *munge_program_name(arg, dflt)
  239. char *arg, *dflt;
  240. {
  241.      char *p;
  242. #ifdef PROG_STRIP_EXTENSION
  243.      char *ext;
  244. #endif
  245.      if (!arg || !*arg)
  246.       return dflt;
  247.      p = strchr(arg, '\0');
  248.      for (;;) {
  249.       if (p == arg)
  250.            break;
  251.       --p;
  252.       if (strchr(PROG_PREFIX, *p)) {
  253.            p++;
  254.            break;
  255.       }
  256.      }
  257.      arg = p;
  258. #ifdef PROG_STRIP_EXTENSION
  259.      ext = strrchr(arg, '.');
  260.      if (ext) {
  261.       p = (char *)xmalloc(ext - arg + 1);
  262.       memcpy(p, arg, ext - arg);
  263.       p[ext - arg] = '\0';
  264.       arg = p;
  265.      }
  266. #endif /* PROG_STRIP_EXTENSION */
  267. #ifdef PROG_FOLD
  268. #ifdef PROG_STRIP_EXTENSION
  269.      if (!ext) {
  270. #endif
  271.       p = xmalloc(strlen(arg) + 1);
  272.       strcpy(p, arg);
  273.       arg = p;
  274. #ifdef PROG_STRIP_EXTENSION
  275.      }
  276. #endif
  277.      for (p = arg; *p; p++)
  278.       if (ISASCII((unsigned char)*p) && isupper((unsigned char)*p))
  279.            *p = tolower((unsigned char)*p);
  280. #endif /* PROG_FOLD */
  281.      return arg;
  282. }
  283.  
  284. static UNIV make_docent(argc, argv)
  285. int argc;
  286. char **argv;
  287. {
  288.      UNS len = 1;
  289.      int i;
  290.      UNIV res;
  291.      char *ptr;
  292.      static char *stdinname = STDINNAME;
  293.  
  294.      if (argc == 0) {
  295.       argv = &stdinname;
  296.       argc = 1;
  297.      }
  298.  
  299.      for (i = 0; i < argc; i++)
  300.       len += strlen(argv[i]) + 1;
  301.  
  302.      res = xmalloc(len);
  303.      ptr = (char *)res;
  304.      for (i = 0; i < argc; i++) {
  305.       strcpy(ptr, argv[i]);
  306.       ptr = strchr(ptr, '\0') + 1;
  307.      }
  308.      *ptr = '\0';
  309.      return res;
  310. }
  311.  
  312.  
  313. static VOID usage()
  314. {
  315.      /* Don't mention -o since this are for internal use only. */
  316.      fprintf(stderr, "Usage: %s [-deglprsuv]%s [-c file] [-i entity] [-m file]%s [filename ...]\n",
  317.          prog,
  318. #ifdef CANT_REDIRECT_STDERR
  319.          " [-f file]",
  320. #else /* not CANT_REDIRECT_STDERR */
  321.          "",
  322. #endif /* not CANT_REDIRECT_STDERR */
  323. #ifdef TRACE
  324.          " [-x flags] [-y flags]"
  325. #else /* not TRACE */
  326.          ""
  327. #endif /* not TRACE */
  328.          );
  329.      exit(EXIT_FAILURE);
  330. }
  331.  
  332. static VOID die()
  333. {
  334. #ifdef SUPPORT_SUBDOC
  335.      cleanup();
  336. #endif /* SUPPORT_SUBDOC */
  337.      exit(EXIT_FAILURE);
  338. }
  339.  
  340. static VOID swinit(swp)
  341. struct switches *swp;
  342. {
  343.      swp->swenttr = 0;
  344.      swp->sweltr = 0;
  345.      swp->swbufsz = READCNT+2;
  346.      swp->prog = prog;
  347.      swp->swdupent = 0;
  348.      swp->swrefmsg = 0;
  349. #ifdef TRACE
  350.      swp->trace = 0;
  351.      swp->ptrace = 0;
  352. #endif /* TRACE */
  353.      swp->catd = catd;
  354.      swp->catalog = catalog;
  355.      swp->swambig = 1;          /* Always check for ambiguity. */
  356.      swp->swundef = 0;
  357.      swp->swcap = 0;          /* Don't check capacities. */
  358.      swp->nopen = 0;
  359.      swp->onlypro = 0;
  360.      swp->includes = 0;
  361.      swp->die = die;
  362. }
  363.  
  364. #ifdef SUPPORT_SUBDOC
  365.  
  366. static VOID build_subargv(swp)
  367. struct switches *swp;
  368. {
  369.      if (suppsw)
  370.       subargv[subargc++] = "-s";
  371.      if (locsw)
  372.       subargv[subargc++] = "-l";
  373.      if (swp->swdupent)
  374.       subargv[subargc++] = "-d";
  375.      if (swp->swenttr)
  376.       subargv[subargc++] = "-e";
  377.      if (swp->sweltr)
  378.       subargv[subargc++] = "-g";
  379.      if (swp->swrefmsg)
  380.       subargv[subargc++] = "-r";
  381. #ifdef TRACE
  382.      if (swp->trace) {
  383.       subargv[subargc++] = "-x";
  384.       subargv[subargc++] = swp->trace;
  385.      }
  386.      if (swp->ptrace) {
  387.       subargv[subargc++] = "-y";
  388.       subargv[subargc++] = swp->ptrace;
  389.      }
  390. #endif /* TRACE */
  391.      subargv[subargc++] = "-o";
  392.      sprintf(nopenbuf, "%ld", swp->nopen + 1);
  393.      subargv[subargc++] = nopenbuf;
  394. }
  395.  
  396.  
  397. static
  398. VOID handler(sig)
  399. int sig;
  400. {
  401.      signal(sig, SIG_DFL);
  402.      cleanup();
  403.      raise(sig);
  404. }
  405.  
  406. static
  407. VOID cleanup()
  408. {
  409.      if (sgmldecl_file[0]) {
  410.       (void)remove(sgmldecl_file);
  411.       sgmldecl_file[0] = '\0';
  412.      }
  413.      if (subcap_file[0]) {
  414.       (void)remove(subcap_file);
  415.       subcap_file[0] = '\0';
  416.      }
  417. }
  418.  
  419. static
  420. char *store_sgmldecl()
  421. {
  422.      if (!sgmldecl_file[0]) {
  423.       FILE *fp;
  424.       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  425.            signal(SIGINT, handler);
  426. #ifdef SIGTERM
  427.       if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  428.            signal(SIGTERM, handler);
  429. #endif /* SIGTERM */
  430. #ifdef SIGPIPE
  431.       if (signal(SIGPIPE, SIG_IGN) != SIG_IGN)
  432.            signal(SIGPIPE, handler);
  433. #endif
  434. #ifdef SIGHUP
  435.       if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  436.            signal(SIGHUP, handler);
  437. #endif
  438.       tmpnam(sgmldecl_file);
  439.       errno = 0;
  440.       fp = fopen(sgmldecl_file, "w");
  441.       if (!fp)
  442.            fatal(E_OPEN, sgmldecl_file, strerror(errno));
  443.       sgmlwrsd(fp);
  444.       fclose(fp);
  445.      }
  446.      return sgmldecl_file;
  447. }
  448.  
  449. static
  450. char *create_subcap_file()
  451. {
  452.      if (subcap_file[0] == '\0') {
  453.       FILE *fp;
  454.       tmpnam(subcap_file);
  455.       fp = fopen(subcap_file, "w");
  456.       if (!fp)
  457.            fatal(E_OPEN, subcap_file, strerror(errno));
  458.       fclose(fp);
  459.      }
  460.      return subcap_file;
  461. }
  462.  
  463. char **make_argv(id)
  464. UNIV id;
  465. {
  466.      int nfiles;
  467.      char *p;
  468.      char **argv;
  469.      int i;
  470.  
  471.      for (p = (char *)id, nfiles = 0; *p; p = strchr(p, '\0') + 1)
  472.       nfiles++;
  473.  
  474.      argv = (char **)xmalloc((subargc + 2 + 1 + nfiles + 1)*sizeof(char *));
  475.      memcpy((UNIV)argv, (UNIV)subargv, subargc*sizeof(char *));
  476.  
  477.      i = subargc;
  478.  
  479.      argv[i++] = "-c";
  480.      argv[i++] = create_subcap_file();
  481.  
  482.      argv[i++] = store_sgmldecl();
  483.  
  484.      for (p = (char *)id; *p; p = strchr(p, '\0') + 1)
  485.       argv[i++] = p;
  486.      argv[i] = 0;
  487.      return argv;
  488. }
  489.  
  490. VOID get_subcaps()
  491. {
  492.      long cap[NCAPACITY];
  493.      FILE *fp;
  494.      int i;
  495.  
  496.      if (!subcap_file[0])
  497.       return;
  498.      errno = 0;
  499.      fp = fopen(subcap_file, "r");
  500.      if (!fp)
  501.       fatal(E_OPEN, subcap_file, strerror(errno));
  502.      for (i = 0; i < NCAPACITY; i++)
  503.       if (fscanf(fp, "%*s %ld", cap + i) != 1)
  504.            fatal(E_CAPBOTCH);
  505.      fclose(fp);
  506.      sgmlsubcap(cap);
  507. }
  508.  
  509.  
  510. #endif /* SUPPORT_SUBDOC */
  511.  
  512. /* Print capacity statistics.*/
  513.  
  514. static VOID write_caps(name, p)
  515. char *name;
  516. struct sgmlcap *p;
  517. {
  518.      FILE *fp;
  519.      int i;
  520.      fp = fopen(name, "w");
  521.      if (!fp)
  522.       fatal(E_OPEN, name, strerror(errno));
  523.      /* This is in RACT format. */
  524.      for (i = 0; i < NCAPACITY; i++)
  525.       fprintf(fp, "%s %ld\n", p->name[i], p->number[i]*p->points[i]);
  526.      fclose(fp);
  527. }
  528.  
  529. UNIV xmalloc(n)
  530. UNS n;
  531. {
  532.      UNIV p = malloc(n);
  533.      if (!p)
  534.       fatal(E_NOMEM);
  535.      return p;
  536. }
  537.  
  538. UNIV xrealloc(s, n)
  539. UNIV s;
  540. UNS n;
  541. {
  542.      s = s ? realloc(s, n) : malloc(n);
  543.      if (!s)
  544.       fatal(E_NOMEM);
  545.      return s;
  546. }
  547.  
  548. static
  549. #ifdef VARARGS
  550. VOID fatal(va_alist) va_dcl
  551. #else
  552. VOID fatal(int errnum,...)
  553. #endif
  554. {
  555. #ifdef VARARGS
  556.      int errnum;
  557. #endif
  558.      va_list ap;
  559.  
  560. #ifdef VARARGS
  561.      va_start(ap);
  562.      errnum = va_arg(ap, int);
  563. #else
  564.      va_start(ap, errnum);
  565. #endif
  566.      do_error(errnum, ap);
  567.      va_end(ap);
  568.      exit(EXIT_FAILURE);
  569. }
  570.  
  571. #ifdef VARARGS
  572. VOID appl_error(va_alist) va_dcl
  573. #else
  574. VOID appl_error(int errnum,...)
  575. #endif
  576. {
  577. #ifdef VARARGS
  578.      int errnum;
  579. #endif
  580.      va_list ap;
  581.  
  582. #ifdef VARARGS
  583.      va_start(ap);
  584.      errnum = va_arg(ap, int);
  585. #else
  586.      va_start(ap, errnum);
  587. #endif
  588.      do_error(errnum, ap);
  589.      va_end(ap);
  590. }
  591.  
  592. static
  593. VOID do_error(errnum, ap)
  594. int errnum;
  595. va_list ap;
  596. {
  597.      char *text;
  598.      fprintf(stderr, "%s: ", prog);
  599.      assert(errnum > 0);
  600.      assert(errnum < sizeof(errlist)/sizeof(errlist[0]));
  601.      text = catgets(catd, APP_SET, errnum, errlist[errnum]);
  602.      assert(text != 0);
  603.      xvfprintf(stderr, text, ap);
  604.      fputc('\n', stderr);
  605.      fflush(stderr);
  606. }
  607.  
  608. static
  609. VOID do_catalog_error(char *filename, unsigned long lineno, int error_number, unsigned flags, int sys_errno)
  610.  
  611.  
  612.  
  613.  
  614.  
  615. {
  616.   char *text;
  617.   unsigned indent;
  618.   text = catgets(catd, CAT_SET, error_number,
  619.          catalog_error_text(error_number));
  620.   assert(text != 0);
  621.   fprintf(stderr, "%s: ", prog);
  622.   indent = strlen(prog) + 2;
  623.   if (flags & CATALOG_SYSTEM_ERROR)
  624.        fprintf(stderr, text, filename, strerror(sys_errno));
  625.   else {
  626.        unsigned i;
  627.        fprintf(stderr,
  628.            catgets(catd, APP_SET,
  629.                CATALOG_ERROR_HEADER_MSGNO,
  630.                CATALOG_ERROR_HEADER_TEXT),
  631.            filename, lineno);
  632.        fputs(":\n", stderr);
  633.        for (i = 0; i < indent; i++)
  634.         putc(' ', stderr);
  635.        fputs(text, stderr);
  636.   }
  637.   putc('\n', stderr);
  638.   fflush(stderr);
  639. }
  640.  
  641. /*
  642. Local Variables:
  643. c-indent-level: 5
  644. c-continued-statement-offset: 5
  645. c-brace-offset: -5
  646. c-argdecl-indent: 0
  647. c-label-offset: -5
  648. comment-column: 30
  649. End:
  650. */
  651.