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