/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* $XConsortium: main.c /main/3 1996/06/19 17:16:04 drk $ */ /* main.c - Main program for sgmls. Written by James Clark (jjc@jclark.com). */ #include "config.h" #include "std.h" #include "getopt.h" #include "entity.h" /* Templates for entity control blocks. */ #include "adl.h" /* Definitions for attribute list processing. */ #include "sgmlmain.h" /* Main interface to SGML services. */ #include "appl.h" #define READCNT 512 /* Before using argv[0] in error messages, strip off everything up to and including the last character in prog that occurs in PROG_PREFIX. */ #ifndef PROG_PREFIX #define PROG_PREFIX "/" #endif /* not PROG_PREFIX */ /* Message catalogue name. */ #define CAT_NAME "sgmls" /* Message set to use for application error messages. */ #define APP_SET 4 #ifdef HAVE_EXTENDED_PRINTF #define xvfprintf vfprintf #else extern int xvfprintf P((FILE *, char *, va_list)); #endif static VOID usage P((void)); static VOID fatal VP((int, ...)); static VOID do_error P((int, va_list)); static VOID swinit P((struct switches *)); static VOID write_caps P((char *, struct sgmlcap *)); static UNIV make_docent P((int, char **)); static char *munge_program_name P((char *, char *)); static VOID die P((void)); #ifdef SUPPORT_SUBDOC static VOID build_subargv P((struct switches *)); static VOID cleanup P((void)); static char *create_subcap_file P((void)); #endif /* SUPPORT_SUBDOC */ static char *errlist[] = { 0, "Out of memory", "Cannot open SGML document entity", "Cannot exec `%s': %s", "Cannot fork: %s", "Error waiting for process: %s", "Program %s got fatal signal %d", "Cannot open `%s': %s", "Subdocument capacity botch", "Non-existent subdocument entity `%s' not processed", }; int suppsw = 0; /* Non-zero means suppress output. */ int locsw = 0; /* Non-zero means generate location info. */ static char *prog; /* Program name (for error messages). */ static nl_catd catd; /* Message catalogue descriptor. */ static char *capfile = 0; /* File for capacity report. */ extern char *version_string; char options[] = { 'c', ':', 'd', 'e', 'g', 'i', ':', 'l', 'o', ':', 'p', 'r', 's', 'u', 'v', #ifdef CANT_REDIRECT_STDERR 'f', ':', #endif /* CANT_REDIRECT_STDERR */ #ifdef TRACE 'x', ':', 'y', ':', #endif /* TRACE */ '\0' }; #ifdef SUPPORT_SUBDOC int suberr = 0; /* Error in subdocument. */ static char *subargv[sizeof(options)]; static int subargc = 0; static char nopenbuf[sizeof(long)*3 + 1]; static char sgmldecl_file[L_tmpnam]; static char subcap_file[L_tmpnam]; #endif int main(argc, argv) int argc; char **argv; { static char stderr_buf[BUFSIZ]; int opt; #ifdef CANT_REDIRECT_STDERR char *errfile = 0; #endif struct sgmlcap cap; struct switches sw; int nincludes = 0; /* number of -i options */ setbuf(stderr, stderr_buf); /* Define MAIN_HOOK in config.h if some function needs to be called here. */ #ifdef MAIN_HOOK MAIN_HOOK(argc, argv); #endif #ifdef SUPPORT_SUBDOC subargv[subargc++] = argv[0]; #endif prog = argv[0] = munge_program_name(argv[0], "sgmls"); catd = catopen(CAT_NAME, 0); swinit(&sw); while ((opt = getopt(argc, argv, options)) != EOF) { switch (opt) { case 'l': /* Generate location information. */ locsw = 1; break; case 'c': /* Print capacity usage. */ capfile = optarg; break; case 's': /* Suppress output. */ suppsw = 1; break; case 'd': /* Report duplicate entity declarations. */ sw.swdupent = 1; break; case 'e': /* Provide entity stack trace in error msg. */ sw.swenttr = 1; break; #ifdef CANT_REDIRECT_STDERR case 'f': /* Redirect errors. */ errfile = optarg; break; #endif /* CANT_REDIRECT_STDERR */ case 'g': /* Provide GI stack trace in error messages. */ sw.sweltr = 1; break; case 'p': /* Parse only the prolog. */ sw.onlypro = 1; suppsw = 1; break; case 'r': /* Give warning for defaulted references. */ sw.swrefmsg = 1; break; case 'u': sw.swundef = 1; break; #ifdef TRACE case 'x': /* Trace options for the document body. */ sw.trace = optarg; break; case 'y': /* Trace options for the prolog. */ sw.ptrace = optarg; break; #endif /* TRACE */ case 'v': /* Print the version number. */ fprintf(stderr, "sgmls version %s\n", version_string); fflush(stderr); break; case 'o': sw.nopen = atol(optarg); if (sw.nopen <= 0) usage(); break; case 'i': /* Define parameter entity as "INCLUDE". */ sw.includes = (char **)xrealloc((UNIV)sw.includes, (nincludes + 2)*sizeof(char *)); sw.includes[nincludes++] = optarg; sw.includes[nincludes] = 0; break; case '?': usage(); default: abort(); } } #ifdef CANT_REDIRECT_STDERR if (errfile) { FILE *fp; errno = 0; fp = fopen(errfile, "w"); if (!fp) fatal(E_OPEN, errfile, strerror(errno)); fclose(fp); errno = 0; if (!freopen(errfile, "w", stderr)) { /* Can't use fatal() since stderr is now closed */ printf("%s: ", prog); printf(errlist[E_OPEN], errfile, strerror(errno)); putchar('\n'); exit(EXIT_FAILURE); } } #endif /* CANT_REDIRECT_STDERR */ (void)sgmlset(&sw); #ifdef SUPPORT_SUBDOC build_subargv(&sw); #endif if (sgmlsdoc(make_docent(argc - optind, argv + optind))) fatal(E_DOC); process_document(sw.nopen > 0); sgmlend(&cap); if (capfile) write_caps(capfile, &cap); #ifdef SUPPORT_SUBDOC cleanup(); if (suberr) exit(EXIT_FAILURE); #endif /* SUPPORT_SUBDOC */ if (sgmlgcnterr() > 0) exit(EXIT_FAILURE); if (!sw.nopen) output_conforming(); exit(EXIT_SUCCESS); } static char *munge_program_name(arg, dflt) char *arg, *dflt; { char *p; #ifdef PROG_STRIP_EXTENSION char *ext; #endif if (!arg || !*arg) return dflt; p = strchr(arg, '\0'); for (;;) { if (p == arg) break; --p; if (strchr(PROG_PREFIX, *p)) { p++; break; } } arg = p; #ifdef PROG_STRIP_EXTENSION ext = strrchr(arg, '.'); if (ext) { p = (char *)xmalloc(ext - arg + 1); memcpy(p, arg, ext - arg); p[ext - arg] = '\0'; arg = p; } #endif /* PROG_STRIP_EXTENSION */ #ifdef PROG_FOLD #ifdef PROG_STRIP_EXTENSION if (!ext) { #endif p = xmalloc(strlen(arg) + 1); strcpy(p, arg); arg = p; #ifdef PROG_STRIP_EXTENSION } #endif for (p = arg; *p; p++) if (ISASCII((unsigned char)*p) && isupper((unsigned char)*p)) *p = tolower((unsigned char)*p); #endif /* PROG_FOLD */ return arg; } static UNIV make_docent(argc, argv) int argc; char **argv; { UNS len = 1; int i; UNIV res; char *ptr; static char *stdinname = STDINNAME; if (argc == 0) { argv = &stdinname; argc = 1; } for (i = 0; i < argc; i++) len += strlen(argv[i]) + 1; res = xmalloc(len); ptr = (char *)res; for (i = 0; i < argc; i++) { strcpy(ptr, argv[i]); ptr = strchr(ptr, '\0') + 1; } *ptr = '\0'; return res; } static VOID usage() { /* Don't mention -o since this are for internal use only. */ fprintf(stderr, "Usage: %s [-deglprsuv]%s [-c file] [-i entity]%s [filename ...]\n", prog, #ifdef CANT_REDIRECT_STDERR " [-f file]", #else /* not CANT_REDIRECT_STDERR */ "", #endif /* not CANT_REDIRECT_STDERR */ #ifdef TRACE " [-x flags] [-y flags]" #else /* not TRACE */ "" #endif /* not TRACE */ ); exit(EXIT_FAILURE); } static VOID die() { #ifdef SUPPORT_SUBDOC cleanup(); #endif /* SUPPORT_SUBDOC */ exit(EXIT_FAILURE); } static VOID swinit(swp) struct switches *swp; { swp->swenttr = 0; swp->sweltr = 0; swp->swbufsz = READCNT+2; swp->prog = prog; swp->swdupent = 0; swp->swrefmsg = 0; #ifdef TRACE swp->trace = 0; swp->ptrace = 0; #endif /* TRACE */ swp->catd = catd; swp->swambig = 1; /* Always check for ambiguity. */ swp->swundef = 0; swp->nopen = 0; swp->onlypro = 0; swp->includes = 0; swp->die = die; } #ifdef SUPPORT_SUBDOC static VOID build_subargv(swp) struct switches *swp; { if (suppsw) subargv[subargc++] = "-s"; if (locsw) subargv[subargc++] = "-l"; if (swp->swdupent) subargv[subargc++] = "-d"; if (swp->swenttr) subargv[subargc++] = "-e"; if (swp->sweltr) subargv[subargc++] = "-g"; if (swp->swrefmsg) subargv[subargc++] = "-r"; #ifdef TRACE if (swp->trace) { subargv[subargc++] = "-x"; subargv[subargc++] = swp->trace; } if (swp->ptrace) { subargv[subargc++] = "-y"; subargv[subargc++] = swp->ptrace; } #endif /* TRACE */ subargv[subargc++] = "-o"; sprintf(nopenbuf, "%ld", swp->nopen + 1); subargv[subargc++] = nopenbuf; } static VOID handler(sig) int sig; { signal(sig, SIG_DFL); cleanup(); raise(sig); } static VOID cleanup() { if (sgmldecl_file[0]) { (void)remove(sgmldecl_file); sgmldecl_file[0] = '\0'; } if (subcap_file[0]) { (void)remove(subcap_file); subcap_file[0] = '\0'; } } static char *store_sgmldecl() { if (!sgmldecl_file[0]) { FILE *fp; if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, handler); #ifdef SIGTERM if (signal(SIGTERM, SIG_IGN) != SIG_IGN) signal(SIGTERM, handler); #endif /* SIGTERM */ #ifdef SIGPIPE if (signal(SIGPIPE, SIG_IGN) != SIG_IGN) signal(SIGPIPE, handler); #endif #ifdef SIGHUP if (signal(SIGHUP, SIG_IGN) != SIG_IGN) signal(SIGHUP, handler); #endif tmpnam(sgmldecl_file); errno = 0; fp = fopen(sgmldecl_file, "w"); if (!fp) fatal(E_OPEN, sgmldecl_file, strerror(errno)); sgmlwrsd(fp); fclose(fp); } return sgmldecl_file; } static char *create_subcap_file() { if (subcap_file[0] == '\0') { FILE *fp; tmpnam(subcap_file); fp = fopen(subcap_file, "w"); if (!fp) fatal(E_OPEN, subcap_file, strerror(errno)); fclose(fp); } return subcap_file; } char **make_argv(id) UNIV id; { int nfiles; char *p; char **argv; int i; for (p = (char *)id, nfiles = 0; *p; p = strchr(p, '\0') + 1) nfiles++; argv = (char **)xmalloc((subargc + 2 + 1 + nfiles + 1)*sizeof(char *)); memcpy((UNIV)argv, (UNIV)subargv, subargc*sizeof(char *)); i = subargc; argv[i++] = "-c"; argv[i++] = create_subcap_file(); argv[i++] = store_sgmldecl(); for (p = (char *)id; *p; p = strchr(p, '\0') + 1) argv[i++] = p; argv[i] = 0; return argv; } VOID get_subcaps() { long cap[NCAPACITY]; FILE *fp; int i; if (!subcap_file[0]) return; errno = 0; fp = fopen(subcap_file, "r"); if (!fp) fatal(E_OPEN, subcap_file, strerror(errno)); for (i = 0; i < NCAPACITY; i++) if (fscanf(fp, "%*s %ld", cap + i) != 1) fatal(E_CAPBOTCH); fclose(fp); sgmlsubcap(cap); } #endif /* SUPPORT_SUBDOC */ /* Print capacity statistics.*/ static VOID write_caps(name, p) char *name; struct sgmlcap *p; { FILE *fp; int i; fp = fopen(name, "w"); if (!fp) fatal(E_OPEN, name, strerror(errno)); /* This is in RACT format. */ for (i = 0; i < NCAPACITY; i++) fprintf(fp, "%s %ld\n", p->name[i], p->number[i]*p->points[i]); fclose(fp); } UNIV xmalloc(n) UNS n; { UNIV p = malloc(n); if (!p) fatal(E_NOMEM); return p; } UNIV xrealloc(s, n) UNIV s; UNS n; { s = s ? realloc(s, n) : malloc(n); if (!s) fatal(E_NOMEM); return s; } static #ifdef VARARGS VOID fatal(va_alist) va_dcl #else VOID fatal(int errnum,...) #endif { #ifdef VARARGS int errnum; #endif va_list ap; #ifdef VARARGS va_start(ap); errnum = va_arg(ap, int); #else va_start(ap, errnum); #endif do_error(errnum, ap); va_end(ap); exit(EXIT_FAILURE); } #ifdef VARARGS VOID appl_error(va_alist) va_dcl #else VOID appl_error(int errnum,...) #endif { #ifdef VARARGS int errnum; #endif va_list ap; #ifdef VARARGS va_start(ap); errnum = va_arg(ap, int); #else va_start(ap, errnum); #endif do_error(errnum, ap); va_end(ap); } static VOID do_error(errnum, ap) int errnum; va_list ap; { char *text; fprintf(stderr, "%s: ", prog); assert(errnum > 0); assert(errnum < sizeof(errlist)/sizeof(errlist[0])); text = catgets(catd, APP_SET, errnum, errlist[errnum]); assert(text != 0); xvfprintf(stderr, text, ap); fputc('\n', stderr); fflush(stderr); } /* Local Variables: c-indent-level: 5 c-continued-statement-offset: 5 c-brace-offset: -5 c-argdecl-indent: 0 c-label-offset: -5 comment-column: 30 End: */