Annotation of mandoc/main.c, Revision 1.87
1.87 ! kristaps 1: /* $Id: main.c,v 1.86 2010/06/08 13:22:37 kristaps Exp $ */
1.1 kristaps 2: /*
1.26 kristaps 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.25 kristaps 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.25 kristaps 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 16: */
1.58 kristaps 17: #ifdef HAVE_CONFIG_H
18: #include "config.h"
19: #endif
20:
1.66 kristaps 21: #include <sys/mman.h>
1.1 kristaps 22: #include <sys/stat.h>
23:
24: #include <assert.h>
25: #include <fcntl.h>
26: #include <stdio.h>
1.45 kristaps 27: #include <stdint.h>
1.1 kristaps 28: #include <stdlib.h>
29: #include <string.h>
30: #include <unistd.h>
31:
1.71 kristaps 32: #include "mandoc.h"
1.1 kristaps 33: #include "mdoc.h"
1.10 kristaps 34: #include "man.h"
1.71 kristaps 35: #include "roff.h"
1.46 kristaps 36: #include "main.h"
1.1 kristaps 37:
1.45 kristaps 38: #define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
39:
1.55 kristaps 40: /* FIXME: Intel's compiler? LLVM? pcc? */
41:
42: #if !defined(__GNUC__) || (__GNUC__ < 2)
1.56 kristaps 43: # if !defined(lint)
44: # define __attribute__(x)
45: # endif
1.55 kristaps 46: #endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
1.16 kristaps 47:
1.42 kristaps 48: typedef void (*out_mdoc)(void *, const struct mdoc *);
49: typedef void (*out_man)(void *, const struct man *);
1.22 kristaps 50: typedef void (*out_free)(void *);
51:
1.5 kristaps 52: struct buf {
53: char *buf;
54: size_t sz;
55: };
56:
1.19 kristaps 57: enum intt {
58: INTT_AUTO,
59: INTT_MDOC,
60: INTT_MAN
61: };
62:
63: enum outt {
64: OUTT_ASCII = 0,
65: OUTT_TREE,
1.43 kristaps 66: OUTT_HTML,
1.59 kristaps 67: OUTT_XHTML,
1.85 kristaps 68: OUTT_LINT,
69: OUTT_PS
1.19 kristaps 70: };
71:
1.5 kristaps 72: struct curparse {
1.22 kristaps 73: const char *file; /* Current parse. */
74: int fd; /* Current parse. */
1.5 kristaps 75: int wflags;
1.71 kristaps 76: /* FIXME: set by max error */
1.36 kristaps 77: #define WARN_WALL (1 << 0) /* All-warnings mask. */
1.1 kristaps 78: #define WARN_WERR (1 << 2) /* Warnings->errors. */
1.23 kristaps 79: int fflags;
1.60 kristaps 80: #define FL_IGN_SCOPE (1 << 0) /* Ignore scope errors. */
81: #define FL_NIGN_ESCAPE (1 << 1) /* Don't ignore bad escapes. */
82: #define FL_NIGN_MACRO (1 << 2) /* Don't ignore bad macros. */
83: #define FL_IGN_ERRORS (1 << 4) /* Ignore failed parse. */
1.66 kristaps 84: #define FL_STRICT FL_NIGN_ESCAPE | \
1.79 kristaps 85: FL_NIGN_MACRO /* ignore nothing */
86: enum intt inttype; /* which parser to use */
87: struct man *man; /* man parser */
88: struct mdoc *mdoc; /* mdoc parser */
89: struct roff *roff; /* roff parser (!NULL) */
90: enum outt outtype; /* which output to use */
91: out_mdoc outmdoc; /* mdoc output ptr */
92: out_man outman; /* man output ptr */
93: out_free outfree; /* free output ptr */
94: void *outdata; /* data for output */
95: char outopts[BUFSIZ]; /* buf of output opts */
96: };
97:
98: static const char * const mandocerrs[MANDOCERR_MAX] = {
99: "ok",
100: "text should be uppercase",
1.81 kristaps 101: "sections out of conventional order",
1.79 kristaps 102: "section name repeats",
103: "out of order prologue",
104: "repeated prologue entry",
105: "list type must come first",
106: "bad standard",
107: "bad library",
108: "bad escape sequence",
109: "unterminated quoted string",
110: "argument requires the width argument",
111: "superfluous width argument",
112: "bad date argument",
113: "bad width argument",
1.81 kristaps 114: "unknown manual section",
1.79 kristaps 115: "section not in conventional manual section",
116: "end of line whitespace",
117: "scope open on exit",
118: "NAME section must come first",
119: "bad Boolean value",
120: "child violates parent syntax",
121: "bad AT&T symbol",
122: "list type repeated",
123: "display type repeated",
124: "argument repeated",
125: "manual name not yet set",
126: "obsolete macro ignored",
127: "empty macro ignored",
128: "macro not allowed in body",
129: "macro not allowed in prologue",
130: "bad character",
131: "bad NAME section contents",
132: "no blank lines",
133: "no text in this context",
134: "bad comment style",
135: "unknown macro will be lost",
136: "line scope broken",
137: "scope broken",
138: "argument count wrong",
139: "request scope close w/none open",
140: "scope already open",
141: "macro requires line argument(s)",
142: "macro requires body argument(s)",
143: "macro requires argument(s)",
144: "no title in document",
1.82 kristaps 145: "missing list type",
1.87 ! kristaps 146: "missing display type",
1.79 kristaps 147: "line argument(s) will be lost",
148: "body argument(s) will be lost",
1.80 kristaps 149: "column syntax is inconsistent",
1.79 kristaps 150: "missing font type",
151: "displays may not be nested",
1.87 ! kristaps 152: "unsupported display type",
1.79 kristaps 153: "no scope to rewind: syntax violated",
154: "scope broken, syntax violated",
155: "line scope broken, syntax violated",
156: "argument count wrong, violates syntax",
157: "child violates parent syntax",
158: "argument count wrong, violates syntax",
159: "no document body",
160: "no document prologue",
161: "utsname system call failed",
162: "memory exhausted",
1.5 kristaps 163: };
1.1 kristaps 164:
1.66 kristaps 165: static void fdesc(struct curparse *);
166: static void ffile(const char *, struct curparse *);
1.1 kristaps 167: static int foptions(int *, char *);
1.66 kristaps 168: static struct man *man_init(struct curparse *);
169: static struct mdoc *mdoc_init(struct curparse *);
1.71 kristaps 170: static struct roff *roff_init(struct curparse *);
1.10 kristaps 171: static int moptions(enum intt *, char *);
1.71 kristaps 172: static int mmsg(enum mandocerr, void *,
173: int, int, const char *);
1.22 kristaps 174: static int pset(const char *, int, struct curparse *,
1.19 kristaps 175: struct man **, struct mdoc **);
1.66 kristaps 176: static int toptions(struct curparse *, char *);
177: static void usage(void) __attribute__((noreturn));
1.55 kristaps 178: static void version(void) __attribute__((noreturn));
1.66 kristaps 179: static int woptions(int *, char *);
1.1 kristaps 180:
1.54 kristaps 181: static const char *progname;
1.66 kristaps 182: static int with_error;
183: static int with_warning;
1.1 kristaps 184:
185: int
186: main(int argc, char *argv[])
187: {
1.64 kristaps 188: int c;
1.5 kristaps 189: struct curparse curp;
1.1 kristaps 190:
1.54 kristaps 191: progname = strrchr(argv[0], '/');
192: if (progname == NULL)
193: progname = argv[0];
194: else
195: ++progname;
196:
1.51 kristaps 197: memset(&curp, 0, sizeof(struct curparse));
1.5 kristaps 198:
1.19 kristaps 199: curp.inttype = INTT_AUTO;
1.22 kristaps 200: curp.outtype = OUTT_ASCII;
1.19 kristaps 201:
1.1 kristaps 202: /* LINTED */
1.47 kristaps 203: while (-1 != (c = getopt(argc, argv, "f:m:O:T:VW:")))
1.1 kristaps 204: switch (c) {
205: case ('f'):
1.19 kristaps 206: if ( ! foptions(&curp.fflags, optarg))
1.32 kristaps 207: return(EXIT_FAILURE);
1.1 kristaps 208: break;
1.10 kristaps 209: case ('m'):
1.19 kristaps 210: if ( ! moptions(&curp.inttype, optarg))
1.32 kristaps 211: return(EXIT_FAILURE);
1.10 kristaps 212: break;
1.48 kristaps 213: case ('O'):
1.49 kristaps 214: (void)strlcat(curp.outopts, optarg, BUFSIZ);
215: (void)strlcat(curp.outopts, ",", BUFSIZ);
1.44 kristaps 216: break;
1.1 kristaps 217: case ('T'):
1.60 kristaps 218: if ( ! toptions(&curp, optarg))
1.32 kristaps 219: return(EXIT_FAILURE);
1.1 kristaps 220: break;
221: case ('W'):
1.5 kristaps 222: if ( ! woptions(&curp.wflags, optarg))
1.32 kristaps 223: return(EXIT_FAILURE);
1.1 kristaps 224: break;
225: case ('V'):
226: version();
227: /* NOTREACHED */
228: default:
229: usage();
230: /* NOTREACHED */
231: }
232:
233: argc -= optind;
234: argv += optind;
235:
1.30 kristaps 236: if (NULL == *argv) {
237: curp.file = "<stdin>";
238: curp.fd = STDIN_FILENO;
1.39 kristaps 239:
1.66 kristaps 240: fdesc(&curp);
1.64 kristaps 241: }
242:
243: while (*argv) {
1.66 kristaps 244: ffile(*argv, &curp);
1.64 kristaps 245:
246: if (with_error && !(curp.fflags & FL_IGN_ERRORS))
247: break;
248: ++argv;
1.1 kristaps 249: }
250:
1.22 kristaps 251: if (curp.outfree)
252: (*curp.outfree)(curp.outdata);
1.71 kristaps 253: if (curp.mdoc)
254: mdoc_free(curp.mdoc);
255: if (curp.man)
256: man_free(curp.man);
257: if (curp.roff)
258: roff_free(curp.roff);
1.1 kristaps 259:
1.66 kristaps 260: return((with_warning || with_error) ?
261: EXIT_FAILURE : EXIT_SUCCESS);
1.1 kristaps 262: }
263:
264:
1.55 kristaps 265: static void
1.1 kristaps 266: version(void)
267: {
268:
1.54 kristaps 269: (void)printf("%s %s\n", progname, VERSION);
1.18 kristaps 270: exit(EXIT_SUCCESS);
1.1 kristaps 271: }
272:
273:
1.55 kristaps 274: static void
1.1 kristaps 275: usage(void)
276: {
277:
1.61 kristaps 278: (void)fprintf(stderr, "usage: %s [-V] [-foption] "
1.48 kristaps 279: "[-mformat] [-Ooption] [-Toutput] "
1.61 kristaps 280: "[-Werr] [file...]\n", progname);
1.18 kristaps 281: exit(EXIT_FAILURE);
1.1 kristaps 282: }
283:
284:
1.19 kristaps 285: static struct man *
286: man_init(struct curparse *curp)
287: {
288: int pflags;
289:
1.30 kristaps 290: /* Defaults from mandoc.1. */
1.27 kristaps 291:
1.62 kristaps 292: pflags = MAN_IGN_MACRO | MAN_IGN_ESCAPE;
1.27 kristaps 293:
1.60 kristaps 294: if (curp->fflags & FL_NIGN_MACRO)
1.20 kristaps 295: pflags &= ~MAN_IGN_MACRO;
1.60 kristaps 296: if (curp->fflags & FL_NIGN_ESCAPE)
1.33 kristaps 297: pflags &= ~MAN_IGN_ESCAPE;
1.19 kristaps 298:
1.79 kristaps 299: return(man_alloc(curp, pflags, mmsg));
1.19 kristaps 300: }
301:
302:
1.71 kristaps 303: static struct roff *
304: roff_init(struct curparse *curp)
305: {
306:
307: return(roff_alloc(mmsg, curp));
308: }
309:
310:
1.19 kristaps 311: static struct mdoc *
312: mdoc_init(struct curparse *curp)
313: {
314: int pflags;
315:
1.30 kristaps 316: /* Defaults from mandoc.1. */
1.27 kristaps 317:
1.62 kristaps 318: pflags = MDOC_IGN_MACRO | MDOC_IGN_ESCAPE;
1.19 kristaps 319:
1.60 kristaps 320: if (curp->fflags & FL_IGN_SCOPE)
1.19 kristaps 321: pflags |= MDOC_IGN_SCOPE;
1.60 kristaps 322: if (curp->fflags & FL_NIGN_ESCAPE)
1.24 kristaps 323: pflags &= ~MDOC_IGN_ESCAPE;
1.60 kristaps 324: if (curp->fflags & FL_NIGN_MACRO)
1.24 kristaps 325: pflags &= ~MDOC_IGN_MACRO;
1.19 kristaps 326:
1.79 kristaps 327: return(mdoc_alloc(curp, pflags, mmsg));
1.19 kristaps 328: }
329:
330:
1.64 kristaps 331: static void
1.66 kristaps 332: ffile(const char *file, struct curparse *curp)
1.1 kristaps 333: {
334:
1.19 kristaps 335: curp->file = file;
336: if (-1 == (curp->fd = open(curp->file, O_RDONLY, 0))) {
1.53 kristaps 337: perror(curp->file);
1.64 kristaps 338: with_error = 1;
339: return;
1.1 kristaps 340: }
341:
1.66 kristaps 342: fdesc(curp);
1.1 kristaps 343:
1.19 kristaps 344: if (-1 == close(curp->fd))
1.53 kristaps 345: perror(curp->file);
1.1 kristaps 346: }
347:
348:
1.66 kristaps 349: static int
1.68 joerg 350: resize_buf(struct buf *buf, size_t initial)
351: {
352: void *tmp;
353: size_t sz;
354:
355: if (buf->sz == 0)
356: sz = initial;
357: else
358: sz = 2 * buf->sz;
359: tmp = realloc(buf->buf, sz);
360: if (NULL == tmp) {
361: perror(NULL);
362: return(0);
363: }
364: buf->buf = tmp;
365: buf->sz = sz;
366: return(1);
367: }
368:
369:
370: static int
1.66 kristaps 371: read_whole_file(struct curparse *curp, struct buf *fb, int *with_mmap)
372: {
373: struct stat st;
1.68 joerg 374: size_t off;
1.66 kristaps 375: ssize_t ssz;
376:
377: if (-1 == fstat(curp->fd, &st)) {
378: perror(curp->file);
379: with_error = 1;
380: return(0);
381: }
382:
383: /*
384: * If we're a regular file, try just reading in the whole entry
385: * via mmap(). This is faster than reading it into blocks, and
386: * since each file is only a few bytes to begin with, I'm not
387: * concerned that this is going to tank any machines.
388: */
389:
390: if (S_ISREG(st.st_mode)) {
391: if (st.st_size >= (1U << 31)) {
392: fprintf(stderr, "%s: input too large\n",
393: curp->file);
394: with_error = 1;
395: return(0);
396: }
397: *with_mmap = 1;
1.71 kristaps 398: fb->sz = (size_t)st.st_size;
1.66 kristaps 399: fb->buf = mmap(NULL, fb->sz, PROT_READ,
1.83 joerg 400: MAP_FILE|MAP_SHARED, curp->fd, 0);
1.66 kristaps 401: if (fb->buf != MAP_FAILED)
402: return(1);
403: }
404:
405: /*
406: * If this isn't a regular file (like, say, stdin), then we must
407: * go the old way and just read things in bit by bit.
408: */
409:
410: *with_mmap = 0;
411: off = 0;
412: fb->sz = 0;
413: fb->buf = NULL;
414: for (;;) {
415: if (off == fb->sz) {
416: if (fb->sz == (1U << 31)) {
417: fprintf(stderr, "%s: input too large\n",
418: curp->file);
419: break;
420: }
1.68 joerg 421: if (! resize_buf(fb, 65536))
1.66 kristaps 422: break;
423: }
1.71 kristaps 424: ssz = read(curp->fd, fb->buf + (int)off, fb->sz - off);
1.66 kristaps 425: if (ssz == 0) {
426: fb->sz = off;
427: return(1);
428: }
429: if (ssz == -1) {
430: perror(curp->file);
431: break;
432: }
1.71 kristaps 433: off += (size_t)ssz;
1.66 kristaps 434: }
435:
436: free(fb->buf);
437: fb->buf = NULL;
438: with_error = 1;
439: return(0);
440: }
441:
442:
1.64 kristaps 443: static void
1.66 kristaps 444: fdesc(struct curparse *curp)
1.1 kristaps 445: {
1.66 kristaps 446: struct buf ln, blk;
1.76 kristaps 447: int i, pos, lnn, lnn_start, with_mmap, of;
1.71 kristaps 448: enum rofferr re;
1.19 kristaps 449: struct man *man;
450: struct mdoc *mdoc;
1.71 kristaps 451: struct roff *roff;
1.10 kristaps 452:
1.19 kristaps 453: man = NULL;
454: mdoc = NULL;
1.71 kristaps 455: roff = NULL;
1.66 kristaps 456: memset(&ln, 0, sizeof(struct buf));
1.1 kristaps 457:
458: /*
1.70 joerg 459: * Two buffers: ln and buf. buf is the input file and may be
460: * memory mapped. ln is a line buffer and grows on-demand.
1.1 kristaps 461: */
462:
1.71 kristaps 463: if ( ! read_whole_file(curp, &blk, &with_mmap))
1.64 kristaps 464: return;
1.1 kristaps 465:
1.71 kristaps 466: if (NULL == curp->roff)
467: curp->roff = roff_init(curp);
468: if (NULL == (roff = curp->roff))
469: goto bailout;
470:
1.70 joerg 471: for (i = 0, lnn = 1; i < (int)blk.sz;) {
472: pos = 0;
473: lnn_start = lnn;
474: while (i < (int)blk.sz) {
475: if ('\n' == blk.buf[i]) {
476: ++i;
477: ++lnn;
478: break;
479: }
480: /* Trailing backslash is like a plain character. */
481: if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
482: if (pos >= (int)ln.sz)
483: if (! resize_buf(&ln, 256))
484: goto bailout;
485: ln.buf[pos++] = blk.buf[i++];
1.67 joerg 486: continue;
1.70 joerg 487: }
488: /* Found an escape and at least one other character. */
489: if ('\n' == blk.buf[i + 1]) {
490: /* Escaped newlines are skipped over */
491: i += 2;
492: ++lnn;
1.67 joerg 493: continue;
494: }
1.70 joerg 495: if ('"' == blk.buf[i + 1]) {
496: i += 2;
497: /* Comment, skip to end of line */
498: for (; i < (int)blk.sz; ++i) {
499: if ('\n' == blk.buf[i]) {
500: ++i;
501: ++lnn;
502: break;
503: }
504: }
505: /* Backout trailing whitespaces */
506: for (; pos > 0; --pos) {
507: if (ln.buf[pos - 1] != ' ')
508: break;
509: if (pos > 2 && ln.buf[pos - 2] == '\\')
510: break;
511: }
512: break;
513: }
514: /* Some other escape sequence, copy and continue. */
515: if (pos + 1 >= (int)ln.sz)
516: if (! resize_buf(&ln, 256))
517: goto bailout;
1.1 kristaps 518:
1.70 joerg 519: ln.buf[pos++] = blk.buf[i++];
520: ln.buf[pos++] = blk.buf[i++];
1.67 joerg 521: }
1.1 kristaps 522:
1.70 joerg 523: if (pos >= (int)ln.sz)
524: if (! resize_buf(&ln, 256))
525: goto bailout;
1.71 kristaps 526: ln.buf[pos] = '\0';
527:
1.76 kristaps 528: /*
529: * A significant amount of complexity is contained by
530: * the roff preprocessor. It's line-oriented but can be
531: * expressed on one line, so we need at times to
532: * readjust our starting point and re-run it. The roff
533: * preprocessor can also readjust the buffers with new
534: * data, so we pass them in wholesale.
535: */
536:
537: of = 0;
538: do {
539: re = roff_parseln(roff, lnn_start,
540: &ln.buf, &ln.sz, of, &of);
541: } while (ROFF_RERUN == re);
542:
1.71 kristaps 543: if (ROFF_IGN == re)
544: continue;
545: else if (ROFF_ERR == re)
546: goto bailout;
1.29 kristaps 547:
1.76 kristaps 548: /*
549: * If input parsers have not been allocated, do so now.
550: * We keep these instanced betwen parsers, but set them
551: * locally per parse routine since we can use different
552: * parsers with each one.
553: */
1.19 kristaps 554:
1.76 kristaps 555: if ( ! (man || mdoc))
556: if ( ! pset(ln.buf + of, pos - of, curp, &man, &mdoc))
557: goto bailout;
1.19 kristaps 558:
1.76 kristaps 559: /* Lastly, push down into the parsers themselves. */
1.30 kristaps 560:
1.76 kristaps 561: if (man && ! man_parseln(man, lnn_start, ln.buf, of))
1.67 joerg 562: goto bailout;
1.76 kristaps 563: if (mdoc && ! mdoc_parseln(mdoc, lnn_start, ln.buf, of))
1.67 joerg 564: goto bailout;
1.1 kristaps 565: }
566:
1.29 kristaps 567: /* NOTE a parser may not have been assigned, yet. */
1.19 kristaps 568:
1.22 kristaps 569: if ( ! (man || mdoc)) {
1.53 kristaps 570: fprintf(stderr, "%s: Not a manual\n", curp->file);
1.64 kristaps 571: goto bailout;
1.22 kristaps 572: }
1.76 kristaps 573:
574: /* Clean up the parse routine ASTs. */
1.22 kristaps 575:
576: if (mdoc && ! mdoc_endparse(mdoc))
1.64 kristaps 577: goto bailout;
1.22 kristaps 578: if (man && ! man_endparse(man))
1.64 kristaps 579: goto bailout;
1.71 kristaps 580: if (roff && ! roff_endparse(roff))
581: goto bailout;
1.19 kristaps 582:
1.29 kristaps 583: /* If unset, allocate output dev now (if applicable). */
1.22 kristaps 584:
585: if ( ! (curp->outman && curp->outmdoc)) {
586: switch (curp->outtype) {
1.59 kristaps 587: case (OUTT_XHTML):
588: curp->outdata = xhtml_alloc(curp->outopts);
589: break;
1.43 kristaps 590: case (OUTT_HTML):
1.44 kristaps 591: curp->outdata = html_alloc(curp->outopts);
1.85 kristaps 592: break;
593: case (OUTT_ASCII):
594: curp->outdata = ascii_alloc(curp->outopts);
1.86 kristaps 595: curp->outfree = ascii_free;
1.85 kristaps 596: break;
597: case (OUTT_PS):
598: curp->outdata = ps_alloc();
1.86 kristaps 599: curp->outfree = ps_free;
1.85 kristaps 600: break;
601: default:
602: break;
603: }
604:
605: switch (curp->outtype) {
606: case (OUTT_HTML):
607: /* FALLTHROUGH */
608: case (OUTT_XHTML):
1.43 kristaps 609: curp->outman = html_man;
610: curp->outmdoc = html_mdoc;
611: curp->outfree = html_free;
612: break;
1.22 kristaps 613: case (OUTT_TREE):
614: curp->outman = tree_man;
615: curp->outmdoc = tree_mdoc;
616: break;
1.85 kristaps 617: case (OUTT_ASCII):
618: /* FALLTHROUGH */
619: case (OUTT_PS):
1.22 kristaps 620: curp->outman = terminal_man;
621: curp->outmdoc = terminal_mdoc;
622: break;
1.85 kristaps 623: default:
624: break;
1.22 kristaps 625: }
626: }
627:
628: /* Execute the out device, if it exists. */
629:
630: if (man && curp->outman)
1.42 kristaps 631: (*curp->outman)(curp->outdata, man);
1.22 kristaps 632: if (mdoc && curp->outmdoc)
1.42 kristaps 633: (*curp->outmdoc)(curp->outdata, mdoc);
1.22 kristaps 634:
1.64 kristaps 635: cleanup:
1.71 kristaps 636: if (mdoc)
637: mdoc_reset(mdoc);
638: if (man)
639: man_reset(man);
640: if (roff)
641: roff_reset(roff);
1.66 kristaps 642: if (ln.buf)
643: free(ln.buf);
644: if (with_mmap)
645: munmap(blk.buf, blk.sz);
646: else
647: free(blk.buf);
1.71 kristaps 648:
1.64 kristaps 649: return;
650:
651: bailout:
652: with_error = 1;
653: goto cleanup;
1.19 kristaps 654: }
655:
656:
657: static int
1.22 kristaps 658: pset(const char *buf, int pos, struct curparse *curp,
1.19 kristaps 659: struct man **man, struct mdoc **mdoc)
660: {
1.29 kristaps 661: int i;
1.19 kristaps 662:
663: /*
664: * Try to intuit which kind of manual parser should be used. If
665: * passed in by command-line (-man, -mdoc), then use that
666: * explicitly. If passed as -mandoc, then try to guess from the
1.30 kristaps 667: * line: either skip dot-lines, use -mdoc when finding `.Dt', or
1.19 kristaps 668: * default to -man, which is more lenient.
669: */
670:
1.75 kristaps 671: if ('.' == buf[0] || '\'' == buf[0]) {
1.29 kristaps 672: for (i = 1; buf[i]; i++)
673: if (' ' != buf[i] && '\t' != buf[i])
674: break;
675: if (0 == buf[i])
676: return(1);
677: }
1.10 kristaps 678:
1.19 kristaps 679: switch (curp->inttype) {
680: case (INTT_MDOC):
681: if (NULL == curp->mdoc)
682: curp->mdoc = mdoc_init(curp);
683: if (NULL == (*mdoc = curp->mdoc))
684: return(0);
685: return(1);
686: case (INTT_MAN):
687: if (NULL == curp->man)
688: curp->man = man_init(curp);
689: if (NULL == (*man = curp->man))
690: return(0);
691: return(1);
692: default:
693: break;
694: }
695:
696: if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) {
697: if (NULL == curp->mdoc)
698: curp->mdoc = mdoc_init(curp);
699: if (NULL == (*mdoc = curp->mdoc))
700: return(0);
701: return(1);
702: }
703:
704: if (NULL == curp->man)
705: curp->man = man_init(curp);
706: if (NULL == (*man = curp->man))
707: return(0);
708: return(1);
1.10 kristaps 709: }
710:
711:
712: static int
713: moptions(enum intt *tflags, char *arg)
714: {
715:
1.17 kristaps 716: if (0 == strcmp(arg, "doc"))
1.10 kristaps 717: *tflags = INTT_MDOC;
1.19 kristaps 718: else if (0 == strcmp(arg, "andoc"))
719: *tflags = INTT_AUTO;
1.17 kristaps 720: else if (0 == strcmp(arg, "an"))
1.10 kristaps 721: *tflags = INTT_MAN;
722: else {
1.57 kristaps 723: fprintf(stderr, "%s: Bad argument\n", arg);
1.10 kristaps 724: return(0);
725: }
726:
727: return(1);
1.1 kristaps 728: }
729:
730:
731: static int
1.60 kristaps 732: toptions(struct curparse *curp, char *arg)
1.1 kristaps 733: {
734:
735: if (0 == strcmp(arg, "ascii"))
1.60 kristaps 736: curp->outtype = OUTT_ASCII;
737: else if (0 == strcmp(arg, "lint")) {
738: curp->outtype = OUTT_LINT;
739: curp->wflags |= WARN_WALL;
740: curp->fflags |= FL_STRICT;
741: }
1.1 kristaps 742: else if (0 == strcmp(arg, "tree"))
1.60 kristaps 743: curp->outtype = OUTT_TREE;
1.43 kristaps 744: else if (0 == strcmp(arg, "html"))
1.60 kristaps 745: curp->outtype = OUTT_HTML;
1.59 kristaps 746: else if (0 == strcmp(arg, "xhtml"))
1.60 kristaps 747: curp->outtype = OUTT_XHTML;
1.85 kristaps 748: else if (0 == strcmp(arg, "ps"))
749: curp->outtype = OUTT_PS;
1.1 kristaps 750: else {
1.57 kristaps 751: fprintf(stderr, "%s: Bad argument\n", arg);
1.1 kristaps 752: return(0);
753: }
754:
755: return(1);
756: }
757:
758:
759: static int
760: foptions(int *fflags, char *arg)
761: {
1.34 kristaps 762: char *v, *o;
1.50 kristaps 763: const char *toks[8];
1.1 kristaps 764:
765: toks[0] = "ign-scope";
1.24 kristaps 766: toks[1] = "no-ign-escape";
767: toks[2] = "no-ign-macro";
1.62 kristaps 768: toks[3] = "ign-errors";
769: toks[4] = "strict";
770: toks[5] = "ign-escape";
771: toks[6] = NULL;
1.1 kristaps 772:
1.34 kristaps 773: while (*arg) {
774: o = arg;
1.45 kristaps 775: switch (getsubopt(&arg, UNCONST(toks), &v)) {
1.1 kristaps 776: case (0):
1.60 kristaps 777: *fflags |= FL_IGN_SCOPE;
1.1 kristaps 778: break;
779: case (1):
1.60 kristaps 780: *fflags |= FL_NIGN_ESCAPE;
1.1 kristaps 781: break;
782: case (2):
1.60 kristaps 783: *fflags |= FL_NIGN_MACRO;
1.1 kristaps 784: break;
1.20 kristaps 785: case (3):
1.62 kristaps 786: *fflags |= FL_IGN_ERRORS;
1.24 kristaps 787: break;
788: case (4):
1.62 kristaps 789: *fflags |= FL_STRICT;
1.39 kristaps 790: break;
791: case (5):
1.60 kristaps 792: *fflags &= ~FL_NIGN_ESCAPE;
1.50 kristaps 793: break;
1.1 kristaps 794: default:
1.57 kristaps 795: fprintf(stderr, "%s: Bad argument\n", o);
1.1 kristaps 796: return(0);
797: }
1.34 kristaps 798: }
1.1 kristaps 799:
800: return(1);
801: }
802:
803:
804: static int
805: woptions(int *wflags, char *arg)
806: {
1.34 kristaps 807: char *v, *o;
1.45 kristaps 808: const char *toks[3];
1.1 kristaps 809:
810: toks[0] = "all";
1.36 kristaps 811: toks[1] = "error";
812: toks[2] = NULL;
1.1 kristaps 813:
1.34 kristaps 814: while (*arg) {
815: o = arg;
1.45 kristaps 816: switch (getsubopt(&arg, UNCONST(toks), &v)) {
1.1 kristaps 817: case (0):
818: *wflags |= WARN_WALL;
819: break;
820: case (1):
821: *wflags |= WARN_WERR;
822: break;
823: default:
1.57 kristaps 824: fprintf(stderr, "%s: Bad argument\n", o);
1.1 kristaps 825: return(0);
826: }
1.34 kristaps 827: }
1.1 kristaps 828:
829: return(1);
830: }
831:
832:
1.71 kristaps 833: static int
834: mmsg(enum mandocerr t, void *arg, int ln, int col, const char *msg)
835: {
836: struct curparse *cp;
837:
838: cp = (struct curparse *)arg;
839:
1.79 kristaps 840: if (t <= MANDOCERR_ERROR) {
841: if ( ! (cp->wflags & WARN_WALL))
842: return(1);
843: with_warning = 1;
844: } else
845: with_error = 1;
846:
1.73 kristaps 847: fprintf(stderr, "%s:%d:%d: %s", cp->file,
848: ln, col + 1, mandocerrs[t]);
849:
850: if (msg)
851: fprintf(stderr, ": %s", msg);
1.71 kristaps 852:
1.73 kristaps 853: fputc('\n', stderr);
1.79 kristaps 854:
855: /* This is superfluous, but whatever. */
856: if (t > MANDOCERR_ERROR)
857: return(0);
858: if (cp->wflags & WARN_WERR) {
859: with_error = 1;
860: return(0);
861: }
1.71 kristaps 862: return(1);
863: }
CVSweb