Annotation of src/usr.bin/mandoc/main.c, Revision 1.28
1.28 ! schwarze 1: /* $Id: main.c,v 1.27 2010/05/15 17:32:25 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;
357: int j, i, pos, lnn, comment, 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: /*
366: * Two buffers: ln and buf. buf is the input buffer optimised
367: * here for each file's block size. ln is a line buffer. Both
368: * growable, hence passed in by ptr-ptr.
369: */
370:
1.27 schwarze 371: if (!read_whole_file(curp, &blk, &with_mmap))
372: return;
373:
374: /* Fill buf with file blocksize. */
1.1 kristaps 375:
1.27 schwarze 376: for (i = lnn = pos = comment = 0; i < (int)blk.sz; ++i) {
377: if (pos >= (int)ln.sz) {
378: if (! resize_buf(&ln, 256))
379: goto bailout;
1.1 kristaps 380: }
381:
1.27 schwarze 382: if ('\n' != blk.buf[i]) {
383: if (comment)
384: continue;
385: ln.buf[pos++] = blk.buf[i];
1.1 kristaps 386:
1.27 schwarze 387: /* Handle in-line `\"' comments. */
1.1 kristaps 388:
1.27 schwarze 389: if (1 == pos || '\"' != ln.buf[pos - 1])
390: continue;
1.1 kristaps 391:
1.27 schwarze 392: for (j = pos - 2; j >= 0; j--)
393: if ('\\' != ln.buf[j])
394: break;
1.1 kristaps 395:
1.27 schwarze 396: if ( ! ((pos - 2 - j) % 2))
1.1 kristaps 397: continue;
398:
1.27 schwarze 399: comment = 1;
400: pos -= 2;
401: for (; pos > 0; --pos) {
402: if (ln.buf[pos - 1] != ' ')
403: break;
404: if (pos > 2 && ln.buf[pos - 2] == '\\')
405: break;
406: }
407: continue;
408: }
409:
410: /* Handle escaped `\\n' newlines. */
1.1 kristaps 411:
1.27 schwarze 412: if (pos > 0 && 0 == comment && '\\' == ln.buf[pos - 1]) {
413: for (j = pos - 1; j >= 0; j--)
414: if ('\\' != ln.buf[j])
415: break;
416: if ( ! ((pos - j) % 2)) {
417: pos--;
418: lnn++;
419: continue;
1.1 kristaps 420: }
1.27 schwarze 421: }
1.1 kristaps 422:
1.27 schwarze 423: ln.buf[pos] = 0;
424: lnn++;
1.5 schwarze 425:
1.27 schwarze 426: /* If unset, assign parser in pset(). */
1.1 kristaps 427:
1.27 schwarze 428: if ( ! (man || mdoc) && ! pset(ln.buf, pos, curp, &man, &mdoc))
429: goto bailout;
1.1 kristaps 430:
1.27 schwarze 431: pos = comment = 0;
1.5 schwarze 432:
1.27 schwarze 433: /* Pass down into parsers. */
1.1 kristaps 434:
1.27 schwarze 435: if (man && ! man_parseln(man, lnn, ln.buf))
436: goto bailout;
437: if (mdoc && ! mdoc_parseln(mdoc, lnn, ln.buf))
438: goto bailout;
1.1 kristaps 439: }
440:
1.5 schwarze 441: /* NOTE a parser may not have been assigned, yet. */
1.1 kristaps 442:
443: if ( ! (man || mdoc)) {
1.19 schwarze 444: fprintf(stderr, "%s: Not a manual\n", curp->file);
1.27 schwarze 445: goto bailout;
1.1 kristaps 446: }
447:
448: if (mdoc && ! mdoc_endparse(mdoc))
1.27 schwarze 449: goto bailout;
1.1 kristaps 450: if (man && ! man_endparse(man))
1.27 schwarze 451: goto bailout;
1.1 kristaps 452:
1.5 schwarze 453: /* If unset, allocate output dev now (if applicable). */
1.1 kristaps 454:
455: if ( ! (curp->outman && curp->outmdoc)) {
456: switch (curp->outtype) {
1.21 schwarze 457: case (OUTT_XHTML):
458: curp->outdata = xhtml_alloc(curp->outopts);
459: curp->outman = html_man;
460: curp->outmdoc = html_mdoc;
461: curp->outfree = html_free;
462: break;
1.17 schwarze 463: case (OUTT_HTML):
464: curp->outdata = html_alloc(curp->outopts);
465: curp->outman = html_man;
466: curp->outmdoc = html_mdoc;
467: curp->outfree = html_free;
468: break;
1.1 kristaps 469: case (OUTT_TREE):
470: curp->outman = tree_man;
471: curp->outmdoc = tree_mdoc;
472: break;
473: case (OUTT_LINT):
474: break;
475: default:
1.28 ! schwarze 476: curp->outdata = ascii_alloc(80);
1.1 kristaps 477: curp->outman = terminal_man;
478: curp->outmdoc = terminal_mdoc;
479: curp->outfree = terminal_free;
480: break;
481: }
482: }
483:
484: /* Execute the out device, if it exists. */
485:
486: if (man && curp->outman)
1.16 schwarze 487: (*curp->outman)(curp->outdata, man);
1.1 kristaps 488: if (mdoc && curp->outmdoc)
1.16 schwarze 489: (*curp->outmdoc)(curp->outdata, mdoc);
1.1 kristaps 490:
1.27 schwarze 491: cleanup:
492: if (curp->mdoc) {
493: mdoc_free(curp->mdoc);
494: curp->mdoc = NULL;
495: }
496: if (curp->man) {
497: man_free(curp->man);
498: curp->man = NULL;
499: }
500: if (ln.buf)
501: free(ln.buf);
502: if (with_mmap)
503: munmap(blk.buf, blk.sz);
504: else
505: free(blk.buf);
506: return;
507:
508: bailout:
509: with_error = 1;
510: goto cleanup;
1.1 kristaps 511: }
512:
513:
514: static int
515: pset(const char *buf, int pos, struct curparse *curp,
516: struct man **man, struct mdoc **mdoc)
517: {
1.5 schwarze 518: int i;
1.1 kristaps 519:
520: /*
521: * Try to intuit which kind of manual parser should be used. If
522: * passed in by command-line (-man, -mdoc), then use that
523: * explicitly. If passed as -mandoc, then try to guess from the
1.5 schwarze 524: * line: either skip dot-lines, use -mdoc when finding `.Dt', or
1.1 kristaps 525: * default to -man, which is more lenient.
526: */
527:
1.5 schwarze 528: if (buf[0] == '.') {
529: for (i = 1; buf[i]; i++)
530: if (' ' != buf[i] && '\t' != buf[i])
531: break;
532: if (0 == buf[i])
533: return(1);
534: }
1.1 kristaps 535:
536: switch (curp->inttype) {
537: case (INTT_MDOC):
538: if (NULL == curp->mdoc)
539: curp->mdoc = mdoc_init(curp);
540: if (NULL == (*mdoc = curp->mdoc))
541: return(0);
542: return(1);
543: case (INTT_MAN):
544: if (NULL == curp->man)
545: curp->man = man_init(curp);
546: if (NULL == (*man = curp->man))
547: return(0);
548: return(1);
549: default:
550: break;
551: }
552:
553: if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) {
554: if (NULL == curp->mdoc)
555: curp->mdoc = mdoc_init(curp);
556: if (NULL == (*mdoc = curp->mdoc))
557: return(0);
558: return(1);
559: }
560:
561: if (NULL == curp->man)
562: curp->man = man_init(curp);
563: if (NULL == (*man = curp->man))
564: return(0);
565: return(1);
566: }
567:
568:
569: static int
570: moptions(enum intt *tflags, char *arg)
571: {
572:
573: if (0 == strcmp(arg, "doc"))
574: *tflags = INTT_MDOC;
575: else if (0 == strcmp(arg, "andoc"))
576: *tflags = INTT_AUTO;
577: else if (0 == strcmp(arg, "an"))
578: *tflags = INTT_MAN;
579: else {
1.20 schwarze 580: fprintf(stderr, "%s: Bad argument\n", arg);
1.1 kristaps 581: return(0);
582: }
583:
584: return(1);
585: }
586:
587:
588: static int
1.22 schwarze 589: toptions(struct curparse *curp, char *arg)
1.1 kristaps 590: {
591:
592: if (0 == strcmp(arg, "ascii"))
1.22 schwarze 593: curp->outtype = OUTT_ASCII;
594: else if (0 == strcmp(arg, "lint")) {
595: curp->outtype = OUTT_LINT;
596: curp->wflags |= WARN_WALL;
597: curp->fflags |= FL_STRICT;
598: }
1.1 kristaps 599: else if (0 == strcmp(arg, "tree"))
1.22 schwarze 600: curp->outtype = OUTT_TREE;
1.17 schwarze 601: else if (0 == strcmp(arg, "html"))
1.22 schwarze 602: curp->outtype = OUTT_HTML;
1.21 schwarze 603: else if (0 == strcmp(arg, "xhtml"))
1.22 schwarze 604: curp->outtype = OUTT_XHTML;
1.1 kristaps 605: else {
1.20 schwarze 606: fprintf(stderr, "%s: Bad argument\n", arg);
1.1 kristaps 607: return(0);
608: }
609:
610: return(1);
611: }
612:
613:
614: static int
615: foptions(int *fflags, char *arg)
616: {
1.10 schwarze 617: char *v, *o;
1.19 schwarze 618: const char *toks[8];
1.1 kristaps 619:
620: toks[0] = "ign-scope";
621: toks[1] = "no-ign-escape";
622: toks[2] = "no-ign-macro";
1.24 schwarze 623: toks[3] = "ign-errors";
624: toks[4] = "strict";
625: toks[5] = "ign-escape";
626: toks[6] = NULL;
1.1 kristaps 627:
1.10 schwarze 628: while (*arg) {
629: o = arg;
1.17 schwarze 630: switch (getsubopt(&arg, UNCONST(toks), &v)) {
1.1 kristaps 631: case (0):
1.22 schwarze 632: *fflags |= FL_IGN_SCOPE;
1.1 kristaps 633: break;
634: case (1):
1.22 schwarze 635: *fflags |= FL_NIGN_ESCAPE;
1.1 kristaps 636: break;
637: case (2):
1.22 schwarze 638: *fflags |= FL_NIGN_MACRO;
1.1 kristaps 639: break;
640: case (3):
1.24 schwarze 641: *fflags |= FL_IGN_ERRORS;
1.1 kristaps 642: break;
643: case (4):
1.24 schwarze 644: *fflags |= FL_STRICT;
1.14 schwarze 645: break;
646: case (5):
1.22 schwarze 647: *fflags &= ~FL_NIGN_ESCAPE;
1.19 schwarze 648: break;
1.1 kristaps 649: default:
1.20 schwarze 650: fprintf(stderr, "%s: Bad argument\n", o);
1.1 kristaps 651: return(0);
652: }
1.10 schwarze 653: }
1.1 kristaps 654:
655: return(1);
656: }
657:
658:
659: static int
660: woptions(int *wflags, char *arg)
661: {
1.10 schwarze 662: char *v, *o;
1.17 schwarze 663: const char *toks[3];
1.1 kristaps 664:
665: toks[0] = "all";
1.13 schwarze 666: toks[1] = "error";
667: toks[2] = NULL;
1.1 kristaps 668:
1.10 schwarze 669: while (*arg) {
670: o = arg;
1.17 schwarze 671: switch (getsubopt(&arg, UNCONST(toks), &v)) {
1.1 kristaps 672: case (0):
673: *wflags |= WARN_WALL;
674: break;
675: case (1):
676: *wflags |= WARN_WERR;
677: break;
678: default:
1.20 schwarze 679: fprintf(stderr, "%s: Bad argument\n", o);
1.1 kristaps 680: return(0);
681: }
1.10 schwarze 682: }
1.1 kristaps 683:
684: return(1);
685: }
686:
687:
688: /* ARGSUSED */
689: static int
690: merr(void *arg, int line, int col, const char *msg)
691: {
692: struct curparse *curp;
693:
694: curp = (struct curparse *)arg;
1.13 schwarze 695:
1.15 schwarze 696: (void)fprintf(stderr, "%s:%d:%d: error: %s\n",
697: curp->file, line, col + 1, msg);
1.2 schwarze 698:
1.27 schwarze 699: with_error = 1;
700:
1.1 kristaps 701: return(0);
702: }
703:
704:
705: static int
1.12 schwarze 706: mwarn(void *arg, int line, int col, const char *msg)
1.1 kristaps 707: {
708: struct curparse *curp;
709:
710: curp = (struct curparse *)arg;
711:
1.12 schwarze 712: if ( ! (curp->wflags & WARN_WALL))
1.1 kristaps 713: return(1);
714:
1.15 schwarze 715: (void)fprintf(stderr, "%s:%d:%d: warning: %s\n",
716: curp->file, line, col + 1, msg);
1.1 kristaps 717:
1.27 schwarze 718: with_warning = 1;
719: if (curp->wflags & WARN_WERR) {
720: with_error = 1;
721: return(0);
722: }
723:
724: return(1);
1.1 kristaps 725: }
726: