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