Annotation of src/usr.bin/mandoc/main.c, Revision 1.30
1.30 ! schwarze 1: /* $Id: main.c,v 1.29 2010/05/15 22:00:22 schwarze Exp $ */
1.1 kristaps 2: /*
1.2 schwarze 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.2 schwarze 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.2 schwarze 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.27 schwarze 17: #include <sys/types.h>
18: #include <sys/mman.h>
1.1 kristaps 19: #include <sys/stat.h>
20:
21: #include <assert.h>
22: #include <fcntl.h>
23: #include <stdio.h>
1.17 schwarze 24: #include <stdint.h>
1.1 kristaps 25: #include <stdlib.h>
26: #include <string.h>
27: #include <unistd.h>
28:
1.30 ! schwarze 29: #include "mandoc.h"
1.1 kristaps 30: #include "mdoc.h"
31: #include "man.h"
1.30 ! schwarze 32: #include "roff.h"
1.17 schwarze 33: #include "main.h"
34:
35: #define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
1.1 kristaps 36:
1.16 schwarze 37: typedef void (*out_mdoc)(void *, const struct mdoc *);
38: typedef void (*out_man)(void *, const struct man *);
1.1 kristaps 39: typedef void (*out_free)(void *);
40:
41: struct buf {
42: char *buf;
43: size_t sz;
44: };
45:
46: enum intt {
47: INTT_AUTO,
48: INTT_MDOC,
49: INTT_MAN
50: };
51:
52: enum outt {
53: OUTT_ASCII = 0,
54: OUTT_TREE,
1.17 schwarze 55: OUTT_HTML,
1.21 schwarze 56: OUTT_XHTML,
1.1 kristaps 57: OUTT_LINT
58: };
59:
60: struct curparse {
61: const char *file; /* Current parse. */
62: int fd; /* Current parse. */
63: int wflags;
1.30 ! schwarze 64: /* FIXME: set by max error */
1.13 schwarze 65: #define WARN_WALL (1 << 0) /* All-warnings mask. */
1.1 kristaps 66: #define WARN_WERR (1 << 2) /* Warnings->errors. */
67: int fflags;
1.22 schwarze 68: #define FL_IGN_SCOPE (1 << 0) /* Ignore scope errors. */
69: #define FL_NIGN_ESCAPE (1 << 1) /* Don't ignore bad escapes. */
70: #define FL_NIGN_MACRO (1 << 2) /* Don't ignore bad macros. */
71: #define FL_IGN_ERRORS (1 << 4) /* Ignore failed parse. */
1.27 schwarze 72: #define FL_STRICT FL_NIGN_ESCAPE | \
73: FL_NIGN_MACRO
1.6 schwarze 74: enum intt inttype; /* Input parsers... */
1.1 kristaps 75: struct man *man;
76: struct mdoc *mdoc;
1.30 ! schwarze 77: struct roff *roff;
1.6 schwarze 78: enum outt outtype; /* Output devices... */
1.1 kristaps 79: out_mdoc outmdoc;
80: out_man outman;
81: out_free outfree;
82: void *outdata;
1.18 schwarze 83: char outopts[BUFSIZ];
1.1 kristaps 84: };
85:
1.27 schwarze 86: static void fdesc(struct curparse *);
87: static void ffile(const char *, struct curparse *);
1.1 kristaps 88: static int foptions(int *, char *);
1.27 schwarze 89: static struct man *man_init(struct curparse *);
90: static struct mdoc *mdoc_init(struct curparse *);
1.30 ! schwarze 91: static struct roff *roff_init(struct curparse *);
! 92: static int merr(void *, int, int, const char *); /* DEPRECATED */
1.1 kristaps 93: static int moptions(enum intt *, char *);
1.30 ! schwarze 94: static int mwarn(void *, int, int, const char *); /* DEPRECATED */
! 95: static int mmsg(enum mandocerr, void *,
! 96: int, int, const char *);
1.1 kristaps 97: static int pset(const char *, int, struct curparse *,
98: struct man **, struct mdoc **);
1.27 schwarze 99: static int toptions(struct curparse *, char *);
100: static void usage(void) __attribute__((noreturn));
1.20 schwarze 101: static void version(void) __attribute__((noreturn));
1.27 schwarze 102: static int woptions(int *, char *);
1.1 kristaps 103:
1.19 schwarze 104: static const char *progname;
1.27 schwarze 105: static int with_error;
106: static int with_warning;
1.1 kristaps 107:
108: int
109: main(int argc, char *argv[])
110: {
1.27 schwarze 111: int c;
1.1 kristaps 112: struct curparse curp;
113:
1.19 schwarze 114: progname = strrchr(argv[0], '/');
115: if (progname == NULL)
116: progname = argv[0];
117: else
118: ++progname;
119:
120: memset(&curp, 0, sizeof(struct curparse));
1.1 kristaps 121:
122: curp.inttype = INTT_AUTO;
123: curp.outtype = OUTT_ASCII;
124:
125: /* LINTED */
1.18 schwarze 126: while (-1 != (c = getopt(argc, argv, "f:m:O:T:VW:")))
1.1 kristaps 127: switch (c) {
128: case ('f'):
129: if ( ! foptions(&curp.fflags, optarg))
1.9 schwarze 130: return(EXIT_FAILURE);
1.1 kristaps 131: break;
132: case ('m'):
133: if ( ! moptions(&curp.inttype, optarg))
1.9 schwarze 134: return(EXIT_FAILURE);
1.1 kristaps 135: break;
1.18 schwarze 136: case ('O'):
137: (void)strlcat(curp.outopts, optarg, BUFSIZ);
138: (void)strlcat(curp.outopts, ",", BUFSIZ);
1.17 schwarze 139: break;
1.1 kristaps 140: case ('T'):
1.22 schwarze 141: if ( ! toptions(&curp, optarg))
1.9 schwarze 142: return(EXIT_FAILURE);
1.1 kristaps 143: break;
144: case ('W'):
145: if ( ! woptions(&curp.wflags, optarg))
1.9 schwarze 146: return(EXIT_FAILURE);
1.1 kristaps 147: break;
1.3 schwarze 148: case ('V'):
149: version();
150: /* NOTREACHED */
1.1 kristaps 151: default:
152: usage();
153: /* NOTREACHED */
154: }
155:
156: argc -= optind;
157: argv += optind;
158:
1.7 schwarze 159: if (NULL == *argv) {
160: curp.file = "<stdin>";
161: curp.fd = STDIN_FILENO;
1.14 schwarze 162:
1.27 schwarze 163: fdesc(&curp);
164: }
165:
166: while (*argv) {
167: ffile(*argv, &curp);
168:
169: if (with_error && !(curp.fflags & FL_IGN_ERRORS))
170: break;
171: ++argv;
1.1 kristaps 172: }
173:
174: if (curp.outfree)
175: (*curp.outfree)(curp.outdata);
1.30 ! schwarze 176: if (curp.mdoc)
! 177: mdoc_free(curp.mdoc);
! 178: if (curp.man)
! 179: man_free(curp.man);
! 180: if (curp.roff)
! 181: roff_free(curp.roff);
1.1 kristaps 182:
1.27 schwarze 183: return((with_warning || with_error) ?
184: EXIT_FAILURE : EXIT_SUCCESS);
1.1 kristaps 185: }
186:
187:
1.20 schwarze 188: static void
1.3 schwarze 189: version(void)
190: {
191:
1.19 schwarze 192: (void)printf("%s %s\n", progname, VERSION);
1.3 schwarze 193: exit(EXIT_SUCCESS);
194: }
195:
196:
1.20 schwarze 197: static void
1.1 kristaps 198: usage(void)
199: {
200:
1.23 jmc 201: (void)fprintf(stderr, "usage: %s [-V] [-foption] "
1.18 schwarze 202: "[-mformat] [-Ooption] [-Toutput] "
1.23 jmc 203: "[-Werr] [file...]\n", progname);
1.1 kristaps 204: exit(EXIT_FAILURE);
205: }
206:
207:
208: static struct man *
209: man_init(struct curparse *curp)
210: {
211: int pflags;
212: struct man_cb mancb;
213:
214: mancb.man_err = merr;
1.12 schwarze 215: mancb.man_warn = mwarn;
1.1 kristaps 216:
1.6 schwarze 217: /* Defaults from mandoc.1. */
1.2 schwarze 218:
1.24 schwarze 219: pflags = MAN_IGN_MACRO | MAN_IGN_ESCAPE;
1.2 schwarze 220:
1.22 schwarze 221: if (curp->fflags & FL_NIGN_MACRO)
1.1 kristaps 222: pflags &= ~MAN_IGN_MACRO;
1.22 schwarze 223: if (curp->fflags & FL_NIGN_ESCAPE)
1.11 schwarze 224: pflags &= ~MAN_IGN_ESCAPE;
1.1 kristaps 225:
1.19 schwarze 226: return(man_alloc(curp, pflags, &mancb));
1.1 kristaps 227: }
228:
229:
1.30 ! schwarze 230: static struct roff *
! 231: roff_init(struct curparse *curp)
! 232: {
! 233:
! 234: return(roff_alloc(mmsg, curp));
! 235: }
! 236:
! 237:
1.1 kristaps 238: static struct mdoc *
239: mdoc_init(struct curparse *curp)
240: {
241: int pflags;
242: struct mdoc_cb mdoccb;
243:
244: mdoccb.mdoc_err = merr;
1.12 schwarze 245: mdoccb.mdoc_warn = mwarn;
1.1 kristaps 246:
1.6 schwarze 247: /* Defaults from mandoc.1. */
1.2 schwarze 248:
1.24 schwarze 249: pflags = MDOC_IGN_MACRO | MDOC_IGN_ESCAPE;
1.1 kristaps 250:
1.22 schwarze 251: if (curp->fflags & FL_IGN_SCOPE)
1.1 kristaps 252: pflags |= MDOC_IGN_SCOPE;
1.22 schwarze 253: if (curp->fflags & FL_NIGN_ESCAPE)
1.1 kristaps 254: pflags &= ~MDOC_IGN_ESCAPE;
1.22 schwarze 255: if (curp->fflags & FL_NIGN_MACRO)
1.1 kristaps 256: pflags &= ~MDOC_IGN_MACRO;
257:
1.19 schwarze 258: return(mdoc_alloc(curp, pflags, &mdoccb));
1.1 kristaps 259: }
260:
261:
1.27 schwarze 262: static void
263: ffile(const char *file, struct curparse *curp)
1.1 kristaps 264: {
265:
266: curp->file = file;
267: if (-1 == (curp->fd = open(curp->file, O_RDONLY, 0))) {
1.19 schwarze 268: perror(curp->file);
1.27 schwarze 269: with_error = 1;
270: return;
1.1 kristaps 271: }
272:
1.27 schwarze 273: fdesc(curp);
1.1 kristaps 274:
275: if (-1 == close(curp->fd))
1.19 schwarze 276: perror(curp->file);
1.27 schwarze 277: }
1.1 kristaps 278:
1.27 schwarze 279:
280: static int
281: resize_buf(struct buf *buf, size_t initial)
282: {
283: void *tmp;
284: size_t sz;
285:
286: if (buf->sz == 0)
287: sz = initial;
288: else
289: sz = 2 * buf->sz;
290: tmp = realloc(buf->buf, sz);
291: if (NULL == tmp) {
292: perror(NULL);
293: return(0);
294: }
295: buf->buf = tmp;
296: buf->sz = sz;
297: return(1);
1.1 kristaps 298: }
299:
300:
301: static int
1.27 schwarze 302: read_whole_file(struct curparse *curp, struct buf *fb, int *with_mmap)
1.1 kristaps 303: {
1.27 schwarze 304: struct stat st;
305: size_t off;
1.1 kristaps 306: ssize_t ssz;
1.27 schwarze 307:
308: if (-1 == fstat(curp->fd, &st)) {
309: perror(curp->file);
310: with_error = 1;
311: return(0);
312: }
313:
314: /*
315: * If we're a regular file, try just reading in the whole entry
316: * via mmap(). This is faster than reading it into blocks, and
317: * since each file is only a few bytes to begin with, I'm not
318: * concerned that this is going to tank any machines.
319: */
320:
321: if (S_ISREG(st.st_mode)) {
322: if (st.st_size >= (1U << 31)) {
323: fprintf(stderr, "%s: input too large\n",
324: curp->file);
325: with_error = 1;
326: return(0);
327: }
328: *with_mmap = 1;
1.30 ! schwarze 329: fb->sz = (size_t)st.st_size;
1.27 schwarze 330: fb->buf = mmap(NULL, fb->sz, PROT_READ,
331: MAP_FILE, curp->fd, 0);
332: if (fb->buf != MAP_FAILED)
333: return(1);
334: }
335:
336: /*
337: * If this isn't a regular file (like, say, stdin), then we must
338: * go the old way and just read things in bit by bit.
339: */
340:
341: *with_mmap = 0;
342: off = 0;
343: fb->sz = 0;
344: fb->buf = NULL;
345: for (;;) {
346: if (off == fb->sz) {
347: if (fb->sz == (1U << 31)) {
348: fprintf(stderr, "%s: input too large\n",
349: curp->file);
350: break;
351: }
352: if (! resize_buf(fb, 65536))
353: break;
354: }
1.30 ! schwarze 355: ssz = read(curp->fd, fb->buf + (int)off, fb->sz - off);
1.27 schwarze 356: if (ssz == 0) {
357: fb->sz = off;
358: return(1);
359: }
360: if (ssz == -1) {
361: perror(curp->file);
362: break;
363: }
1.30 ! schwarze 364: off += (size_t)ssz;
1.27 schwarze 365: }
366:
367: free(fb->buf);
368: fb->buf = NULL;
369: with_error = 1;
370: return(0);
371: }
372:
373:
374: static void
375: fdesc(struct curparse *curp)
376: {
377: struct buf ln, blk;
1.29 schwarze 378: int i, pos, lnn, lnn_start, with_mmap;
1.30 ! schwarze 379: enum rofferr re;
1.1 kristaps 380: struct man *man;
381: struct mdoc *mdoc;
1.30 ! schwarze 382: struct roff *roff;
1.1 kristaps 383:
384: man = NULL;
385: mdoc = NULL;
1.30 ! schwarze 386: roff = NULL;
1.27 schwarze 387: memset(&ln, 0, sizeof(struct buf));
1.1 kristaps 388:
389: /*
1.29 schwarze 390: * Two buffers: ln and buf. buf is the input file and may be
391: * memory mapped. ln is a line buffer and grows on-demand.
1.1 kristaps 392: */
393:
1.30 ! schwarze 394: if ( ! read_whole_file(curp, &blk, &with_mmap))
1.27 schwarze 395: return;
396:
1.30 ! schwarze 397: if (NULL == curp->roff)
! 398: curp->roff = roff_init(curp);
! 399: if (NULL == (roff = curp->roff))
! 400: goto bailout;
! 401:
1.29 schwarze 402: for (i = 0, lnn = 1; i < (int)blk.sz;) {
403: pos = 0;
404: lnn_start = lnn;
405: while (i < (int)blk.sz) {
406: if ('\n' == blk.buf[i]) {
407: ++i;
408: ++lnn;
409: break;
410: }
411: /* Trailing backslash is like a plain character. */
412: if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
413: if (pos >= (int)ln.sz)
414: if (! resize_buf(&ln, 256))
415: goto bailout;
416: ln.buf[pos++] = blk.buf[i++];
1.27 schwarze 417: continue;
1.29 schwarze 418: }
419: /* Found an escape and at least one other character. */
420: if ('\n' == blk.buf[i + 1]) {
421: /* Escaped newlines are skipped over */
422: i += 2;
423: ++lnn;
1.27 schwarze 424: continue;
425: }
1.29 schwarze 426: if ('"' == blk.buf[i + 1]) {
427: i += 2;
428: /* Comment, skip to end of line */
429: for (; i < (int)blk.sz; ++i) {
430: if ('\n' == blk.buf[i]) {
431: ++i;
432: ++lnn;
433: break;
434: }
435: }
436: /* Backout trailing whitespaces */
437: for (; pos > 0; --pos) {
438: if (ln.buf[pos - 1] != ' ')
439: break;
440: if (pos > 2 && ln.buf[pos - 2] == '\\')
441: break;
442: }
443: break;
444: }
445: /* Some other escape sequence, copy and continue. */
446: if (pos + 1 >= (int)ln.sz)
447: if (! resize_buf(&ln, 256))
448: goto bailout;
1.1 kristaps 449:
1.29 schwarze 450: ln.buf[pos++] = blk.buf[i++];
451: ln.buf[pos++] = blk.buf[i++];
1.27 schwarze 452: }
1.1 kristaps 453:
1.29 schwarze 454: if (pos >= (int)ln.sz)
455: if (! resize_buf(&ln, 256))
456: goto bailout;
1.30 ! schwarze 457: ln.buf[pos] = '\0';
! 458:
! 459: re = roff_parseln(roff, lnn_start, &ln.buf, &ln.sz);
! 460: if (ROFF_IGN == re)
! 461: continue;
! 462: else if (ROFF_ERR == re)
! 463: goto bailout;
1.5 schwarze 464:
1.27 schwarze 465: /* If unset, assign parser in pset(). */
1.1 kristaps 466:
1.27 schwarze 467: if ( ! (man || mdoc) && ! pset(ln.buf, pos, curp, &man, &mdoc))
468: goto bailout;
1.5 schwarze 469:
1.27 schwarze 470: /* Pass down into parsers. */
1.1 kristaps 471:
1.30 ! schwarze 472: if (man && ! man_parseln(man, lnn_start, ln.buf))
1.27 schwarze 473: goto bailout;
1.30 ! schwarze 474: if (mdoc && ! mdoc_parseln(mdoc, lnn_start, ln.buf))
1.27 schwarze 475: goto bailout;
1.1 kristaps 476: }
477:
1.5 schwarze 478: /* NOTE a parser may not have been assigned, yet. */
1.1 kristaps 479:
480: if ( ! (man || mdoc)) {
1.19 schwarze 481: fprintf(stderr, "%s: Not a manual\n", curp->file);
1.27 schwarze 482: goto bailout;
1.1 kristaps 483: }
484:
485: if (mdoc && ! mdoc_endparse(mdoc))
1.27 schwarze 486: goto bailout;
1.1 kristaps 487: if (man && ! man_endparse(man))
1.27 schwarze 488: goto bailout;
1.30 ! schwarze 489: if (roff && ! roff_endparse(roff))
! 490: goto bailout;
1.1 kristaps 491:
1.5 schwarze 492: /* If unset, allocate output dev now (if applicable). */
1.1 kristaps 493:
494: if ( ! (curp->outman && curp->outmdoc)) {
495: switch (curp->outtype) {
1.21 schwarze 496: case (OUTT_XHTML):
497: curp->outdata = xhtml_alloc(curp->outopts);
498: curp->outman = html_man;
499: curp->outmdoc = html_mdoc;
500: curp->outfree = html_free;
501: break;
1.17 schwarze 502: case (OUTT_HTML):
503: curp->outdata = html_alloc(curp->outopts);
504: curp->outman = html_man;
505: curp->outmdoc = html_mdoc;
506: curp->outfree = html_free;
507: break;
1.1 kristaps 508: case (OUTT_TREE):
509: curp->outman = tree_man;
510: curp->outmdoc = tree_mdoc;
511: break;
512: case (OUTT_LINT):
513: break;
514: default:
1.28 schwarze 515: curp->outdata = ascii_alloc(80);
1.1 kristaps 516: curp->outman = terminal_man;
517: curp->outmdoc = terminal_mdoc;
518: curp->outfree = terminal_free;
519: break;
520: }
521: }
522:
523: /* Execute the out device, if it exists. */
524:
525: if (man && curp->outman)
1.16 schwarze 526: (*curp->outman)(curp->outdata, man);
1.1 kristaps 527: if (mdoc && curp->outmdoc)
1.16 schwarze 528: (*curp->outmdoc)(curp->outdata, mdoc);
1.1 kristaps 529:
1.27 schwarze 530: cleanup:
1.30 ! schwarze 531: if (mdoc)
! 532: mdoc_reset(mdoc);
! 533: if (man)
! 534: man_reset(man);
! 535: if (roff)
! 536: roff_reset(roff);
1.27 schwarze 537: if (ln.buf)
538: free(ln.buf);
539: if (with_mmap)
540: munmap(blk.buf, blk.sz);
541: else
542: free(blk.buf);
1.30 ! schwarze 543:
1.27 schwarze 544: return;
545:
546: bailout:
547: with_error = 1;
548: goto cleanup;
1.1 kristaps 549: }
550:
551:
552: static int
553: pset(const char *buf, int pos, struct curparse *curp,
554: struct man **man, struct mdoc **mdoc)
555: {
1.5 schwarze 556: int i;
1.1 kristaps 557:
558: /*
559: * Try to intuit which kind of manual parser should be used. If
560: * passed in by command-line (-man, -mdoc), then use that
561: * explicitly. If passed as -mandoc, then try to guess from the
1.5 schwarze 562: * line: either skip dot-lines, use -mdoc when finding `.Dt', or
1.1 kristaps 563: * default to -man, which is more lenient.
564: */
565:
1.5 schwarze 566: if (buf[0] == '.') {
567: for (i = 1; buf[i]; i++)
568: if (' ' != buf[i] && '\t' != buf[i])
569: break;
570: if (0 == buf[i])
571: return(1);
572: }
1.1 kristaps 573:
574: switch (curp->inttype) {
575: case (INTT_MDOC):
576: if (NULL == curp->mdoc)
577: curp->mdoc = mdoc_init(curp);
578: if (NULL == (*mdoc = curp->mdoc))
579: return(0);
580: return(1);
581: case (INTT_MAN):
582: if (NULL == curp->man)
583: curp->man = man_init(curp);
584: if (NULL == (*man = curp->man))
585: return(0);
586: return(1);
587: default:
588: break;
589: }
590:
591: if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) {
592: if (NULL == curp->mdoc)
593: curp->mdoc = mdoc_init(curp);
594: if (NULL == (*mdoc = curp->mdoc))
595: return(0);
596: return(1);
597: }
598:
599: if (NULL == curp->man)
600: curp->man = man_init(curp);
601: if (NULL == (*man = curp->man))
602: return(0);
603: return(1);
604: }
605:
606:
607: static int
608: moptions(enum intt *tflags, char *arg)
609: {
610:
611: if (0 == strcmp(arg, "doc"))
612: *tflags = INTT_MDOC;
613: else if (0 == strcmp(arg, "andoc"))
614: *tflags = INTT_AUTO;
615: else if (0 == strcmp(arg, "an"))
616: *tflags = INTT_MAN;
617: else {
1.20 schwarze 618: fprintf(stderr, "%s: Bad argument\n", arg);
1.1 kristaps 619: return(0);
620: }
621:
622: return(1);
623: }
624:
625:
626: static int
1.22 schwarze 627: toptions(struct curparse *curp, char *arg)
1.1 kristaps 628: {
629:
630: if (0 == strcmp(arg, "ascii"))
1.22 schwarze 631: curp->outtype = OUTT_ASCII;
632: else if (0 == strcmp(arg, "lint")) {
633: curp->outtype = OUTT_LINT;
634: curp->wflags |= WARN_WALL;
635: curp->fflags |= FL_STRICT;
636: }
1.1 kristaps 637: else if (0 == strcmp(arg, "tree"))
1.22 schwarze 638: curp->outtype = OUTT_TREE;
1.17 schwarze 639: else if (0 == strcmp(arg, "html"))
1.22 schwarze 640: curp->outtype = OUTT_HTML;
1.21 schwarze 641: else if (0 == strcmp(arg, "xhtml"))
1.22 schwarze 642: curp->outtype = OUTT_XHTML;
1.1 kristaps 643: else {
1.20 schwarze 644: fprintf(stderr, "%s: Bad argument\n", arg);
1.1 kristaps 645: return(0);
646: }
647:
648: return(1);
649: }
650:
651:
652: static int
653: foptions(int *fflags, char *arg)
654: {
1.10 schwarze 655: char *v, *o;
1.19 schwarze 656: const char *toks[8];
1.1 kristaps 657:
658: toks[0] = "ign-scope";
659: toks[1] = "no-ign-escape";
660: toks[2] = "no-ign-macro";
1.24 schwarze 661: toks[3] = "ign-errors";
662: toks[4] = "strict";
663: toks[5] = "ign-escape";
664: toks[6] = NULL;
1.1 kristaps 665:
1.10 schwarze 666: while (*arg) {
667: o = arg;
1.17 schwarze 668: switch (getsubopt(&arg, UNCONST(toks), &v)) {
1.1 kristaps 669: case (0):
1.22 schwarze 670: *fflags |= FL_IGN_SCOPE;
1.1 kristaps 671: break;
672: case (1):
1.22 schwarze 673: *fflags |= FL_NIGN_ESCAPE;
1.1 kristaps 674: break;
675: case (2):
1.22 schwarze 676: *fflags |= FL_NIGN_MACRO;
1.1 kristaps 677: break;
678: case (3):
1.24 schwarze 679: *fflags |= FL_IGN_ERRORS;
1.1 kristaps 680: break;
681: case (4):
1.24 schwarze 682: *fflags |= FL_STRICT;
1.14 schwarze 683: break;
684: case (5):
1.22 schwarze 685: *fflags &= ~FL_NIGN_ESCAPE;
1.19 schwarze 686: break;
1.1 kristaps 687: default:
1.20 schwarze 688: fprintf(stderr, "%s: Bad argument\n", o);
1.1 kristaps 689: return(0);
690: }
1.10 schwarze 691: }
1.1 kristaps 692:
693: return(1);
694: }
695:
696:
697: static int
698: woptions(int *wflags, char *arg)
699: {
1.10 schwarze 700: char *v, *o;
1.17 schwarze 701: const char *toks[3];
1.1 kristaps 702:
703: toks[0] = "all";
1.13 schwarze 704: toks[1] = "error";
705: toks[2] = NULL;
1.1 kristaps 706:
1.10 schwarze 707: while (*arg) {
708: o = arg;
1.17 schwarze 709: switch (getsubopt(&arg, UNCONST(toks), &v)) {
1.1 kristaps 710: case (0):
711: *wflags |= WARN_WALL;
712: break;
713: case (1):
714: *wflags |= WARN_WERR;
715: break;
716: default:
1.20 schwarze 717: fprintf(stderr, "%s: Bad argument\n", o);
1.1 kristaps 718: return(0);
719: }
1.10 schwarze 720: }
1.1 kristaps 721:
722: return(1);
723: }
724:
725:
726: /* ARGSUSED */
727: static int
728: merr(void *arg, int line, int col, const char *msg)
729: {
730: struct curparse *curp;
731:
732: curp = (struct curparse *)arg;
1.13 schwarze 733:
1.15 schwarze 734: (void)fprintf(stderr, "%s:%d:%d: error: %s\n",
735: curp->file, line, col + 1, msg);
1.2 schwarze 736:
1.27 schwarze 737: with_error = 1;
738:
1.1 kristaps 739: return(0);
740: }
741:
742:
743: static int
1.12 schwarze 744: mwarn(void *arg, int line, int col, const char *msg)
1.1 kristaps 745: {
746: struct curparse *curp;
747:
748: curp = (struct curparse *)arg;
749:
1.12 schwarze 750: if ( ! (curp->wflags & WARN_WALL))
1.1 kristaps 751: return(1);
752:
1.15 schwarze 753: (void)fprintf(stderr, "%s:%d:%d: warning: %s\n",
754: curp->file, line, col + 1, msg);
1.1 kristaps 755:
1.27 schwarze 756: with_warning = 1;
757: if (curp->wflags & WARN_WERR) {
758: with_error = 1;
759: return(0);
760: }
761:
762: return(1);
1.1 kristaps 763: }
764:
1.30 ! schwarze 765: static const char * const mandocerrs[MANDOCERR_MAX] = {
! 766: "ok",
! 767: "multi-line scope open on exit",
! 768: "request for scope closure when no matching scope is open",
! 769: "line arguments will be lost",
! 770: "memory exhausted"
! 771: };
! 772:
! 773: /*
! 774: * XXX: this is experimental code that will eventually become the
! 775: * generic means of covering all warnings and errors!
! 776: */
! 777: /* ARGSUSED */
! 778: static int
! 779: mmsg(enum mandocerr t, void *arg, int ln, int col, const char *msg)
! 780: {
! 781: #if 0
! 782: struct curparse *cp;
! 783:
! 784: cp = (struct curparse *)arg;
! 785:
! 786: fprintf(stderr, "%s:%d:%d: %s", cp->file,
! 787: ln, col + 1, mandocerrs[t]);
! 788:
! 789: if (msg)
! 790: fprintf(stderr, ": %s", msg);
! 791:
! 792: fputc('\n', stderr);
! 793: #endif
! 794: return(1);
! 795: }