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