Annotation of mandoc/main.c, Revision 1.178
1.178 ! schwarze 1: /* $Id: main.c,v 1.177 2014/06/21 22:24:01 schwarze Exp $ */
1.1 kristaps 2: /*
1.133 schwarze 3: * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
1.170 schwarze 4: * Copyright (c) 2010, 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
1.169 schwarze 5: * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
1.1 kristaps 6: *
7: * Permission to use, copy, modify, and distribute this software for any
1.25 kristaps 8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 10: *
1.25 kristaps 11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 18: */
1.58 kristaps 19: #include "config.h"
1.178 ! schwarze 20:
! 21: #include <sys/types.h>
1.58 kristaps 22:
1.1 kristaps 23: #include <assert.h>
24: #include <stdio.h>
1.45 kristaps 25: #include <stdint.h>
1.1 kristaps 26: #include <stdlib.h>
27: #include <string.h>
28: #include <unistd.h>
29:
1.71 kristaps 30: #include "mandoc.h"
1.172 schwarze 31: #include "mandoc_aux.h"
1.90 kristaps 32: #include "main.h"
1.1 kristaps 33: #include "mdoc.h"
1.10 kristaps 34: #include "man.h"
1.101 joerg 35:
1.55 kristaps 36: #if !defined(__GNUC__) || (__GNUC__ < 2)
1.56 kristaps 37: # if !defined(lint)
38: # define __attribute__(x)
39: # endif
1.55 kristaps 40: #endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
1.16 kristaps 41:
1.42 kristaps 42: typedef void (*out_mdoc)(void *, const struct mdoc *);
43: typedef void (*out_man)(void *, const struct man *);
1.22 kristaps 44: typedef void (*out_free)(void *);
45:
1.19 kristaps 46: enum outt {
1.154 kristaps 47: OUTT_ASCII = 0, /* -Tascii */
1.162 kristaps 48: OUTT_LOCALE, /* -Tlocale */
1.163 kristaps 49: OUTT_UTF8, /* -Tutf8 */
1.154 kristaps 50: OUTT_TREE, /* -Ttree */
1.164 schwarze 51: OUTT_MAN, /* -Tman */
1.154 kristaps 52: OUTT_HTML, /* -Thtml */
53: OUTT_XHTML, /* -Txhtml */
54: OUTT_LINT, /* -Tlint */
55: OUTT_PS, /* -Tps */
56: OUTT_PDF /* -Tpdf */
1.19 kristaps 57: };
58:
1.5 kristaps 59: struct curparse {
1.154 kristaps 60: struct mparse *mp;
1.148 kristaps 61: enum mandoclevel wlevel; /* ignore messages below this */
62: int wstop; /* stop after a file with a warning */
1.173 schwarze 63: enum outt outtype; /* which output to use */
1.79 kristaps 64: out_mdoc outmdoc; /* mdoc output ptr */
1.173 schwarze 65: out_man outman; /* man output ptr */
1.79 kristaps 66: out_free outfree; /* free output ptr */
67: void *outdata; /* data for output */
68: char outopts[BUFSIZ]; /* buf of output opts */
69: };
70:
1.170 schwarze 71: static int moptions(int *, char *);
1.155 kristaps 72: static void mmsg(enum mandocerr, enum mandoclevel,
73: const char *, int, int, const char *);
1.173 schwarze 74: static void parse(struct curparse *, int,
1.154 kristaps 75: const char *, enum mandoclevel *);
1.66 kristaps 76: static int toptions(struct curparse *, char *);
77: static void usage(void) __attribute__((noreturn));
1.55 kristaps 78: static void version(void) __attribute__((noreturn));
1.103 schwarze 79: static int woptions(struct curparse *, char *);
1.1 kristaps 80:
1.54 kristaps 81: static const char *progname;
1.1 kristaps 82:
1.173 schwarze 83:
1.1 kristaps 84: int
85: main(int argc, char *argv[])
86: {
1.64 kristaps 87: int c;
1.5 kristaps 88: struct curparse curp;
1.170 schwarze 89: int options;
1.154 kristaps 90: enum mandoclevel rc;
1.166 schwarze 91: char *defos;
1.1 kristaps 92:
1.54 kristaps 93: progname = strrchr(argv[0], '/');
94: if (progname == NULL)
95: progname = argv[0];
96: else
97: ++progname;
98:
1.51 kristaps 99: memset(&curp, 0, sizeof(struct curparse));
1.5 kristaps 100:
1.170 schwarze 101: options = MPARSE_SO;
1.22 kristaps 102: curp.outtype = OUTT_ASCII;
1.103 schwarze 103: curp.wlevel = MANDOCLEVEL_FATAL;
1.166 schwarze 104: defos = NULL;
1.19 kristaps 105:
1.166 schwarze 106: while (-1 != (c = getopt(argc, argv, "I:m:O:T:VW:")))
1.1 kristaps 107: switch (c) {
1.173 schwarze 108: case 'I':
1.166 schwarze 109: if (strncmp(optarg, "os=", 3)) {
1.173 schwarze 110: fprintf(stderr,
1.176 schwarze 111: "%s: -I%s: Bad argument\n",
112: progname, optarg);
1.166 schwarze 113: return((int)MANDOCLEVEL_BADARG);
114: }
115: if (defos) {
1.173 schwarze 116: fprintf(stderr,
1.176 schwarze 117: "%s: -I%s: Duplicate argument\n",
118: progname, optarg);
1.166 schwarze 119: return((int)MANDOCLEVEL_BADARG);
120: }
121: defos = mandoc_strdup(optarg + 3);
122: break;
1.173 schwarze 123: case 'm':
1.170 schwarze 124: if ( ! moptions(&options, optarg))
1.105 kristaps 125: return((int)MANDOCLEVEL_BADARG);
1.10 kristaps 126: break;
1.173 schwarze 127: case 'O':
1.49 kristaps 128: (void)strlcat(curp.outopts, optarg, BUFSIZ);
129: (void)strlcat(curp.outopts, ",", BUFSIZ);
1.44 kristaps 130: break;
1.173 schwarze 131: case 'T':
1.60 kristaps 132: if ( ! toptions(&curp, optarg))
1.105 kristaps 133: return((int)MANDOCLEVEL_BADARG);
1.1 kristaps 134: break;
1.173 schwarze 135: case 'W':
1.103 schwarze 136: if ( ! woptions(&curp, optarg))
1.105 kristaps 137: return((int)MANDOCLEVEL_BADARG);
1.1 kristaps 138: break;
1.173 schwarze 139: case 'V':
1.1 kristaps 140: version();
141: /* NOTREACHED */
142: default:
143: usage();
144: /* NOTREACHED */
145: }
146:
1.170 schwarze 147: curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
1.154 kristaps 148:
1.165 kristaps 149: /*
150: * Conditionally start up the lookaside buffer before parsing.
151: */
152: if (OUTT_MAN == curp.outtype)
153: mparse_keep(curp.mp);
154:
1.1 kristaps 155: argc -= optind;
156: argv += optind;
157:
1.154 kristaps 158: rc = MANDOCLEVEL_OK;
1.39 kristaps 159:
1.154 kristaps 160: if (NULL == *argv)
161: parse(&curp, STDIN_FILENO, "<stdin>", &rc);
1.64 kristaps 162:
163: while (*argv) {
1.154 kristaps 164: parse(&curp, -1, *argv, &rc);
165: if (MANDOCLEVEL_OK != rc && curp.wstop)
1.64 kristaps 166: break;
167: ++argv;
1.1 kristaps 168: }
169:
1.22 kristaps 170: if (curp.outfree)
171: (*curp.outfree)(curp.outdata);
1.154 kristaps 172: if (curp.mp)
173: mparse_free(curp.mp);
1.166 schwarze 174: free(defos);
1.1 kristaps 175:
1.154 kristaps 176: return((int)rc);
1.1 kristaps 177: }
178:
1.55 kristaps 179: static void
1.1 kristaps 180: version(void)
181: {
182:
1.154 kristaps 183: printf("%s %s\n", progname, VERSION);
1.105 kristaps 184: exit((int)MANDOCLEVEL_OK);
1.1 kristaps 185: }
186:
1.55 kristaps 187: static void
1.1 kristaps 188: usage(void)
189: {
190:
1.154 kristaps 191: fprintf(stderr, "usage: %s "
1.112 kristaps 192: "[-V] "
1.167 schwarze 193: "[-Ios=name] "
1.112 kristaps 194: "[-mformat] "
195: "[-Ooption] "
196: "[-Toutput] "
1.167 schwarze 197: "[-Wlevel]\n"
1.173 schwarze 198: "\t [file ...]\n",
1.112 kristaps 199: progname);
200:
1.105 kristaps 201: exit((int)MANDOCLEVEL_BADARG);
1.68 joerg 202: }
203:
1.64 kristaps 204: static void
1.173 schwarze 205: parse(struct curparse *curp, int fd, const char *file,
206: enum mandoclevel *level)
1.1 kristaps 207: {
1.154 kristaps 208: enum mandoclevel rc;
209: struct mdoc *mdoc;
210: struct man *man;
1.112 kristaps 211:
1.154 kristaps 212: /* Begin by parsing the file itself. */
1.112 kristaps 213:
1.154 kristaps 214: assert(file);
215: assert(fd >= -1);
1.112 kristaps 216:
1.154 kristaps 217: rc = mparse_readfd(curp->mp, fd, file);
1.112 kristaps 218:
1.154 kristaps 219: /* Stop immediately if the parse has failed. */
1.92 kristaps 220:
1.154 kristaps 221: if (MANDOCLEVEL_FATAL <= rc)
1.111 kristaps 222: goto cleanup;
223:
1.1 kristaps 224: /*
1.154 kristaps 225: * With -Wstop and warnings or errors of at least the requested
226: * level, do not produce output.
1.1 kristaps 227: */
228:
1.154 kristaps 229: if (MANDOCLEVEL_OK != rc && curp->wstop)
1.111 kristaps 230: goto cleanup;
231:
232: /* If unset, allocate output dev now (if applicable). */
233:
234: if ( ! (curp->outman && curp->outmdoc)) {
235: switch (curp->outtype) {
1.173 schwarze 236: case OUTT_XHTML:
1.111 kristaps 237: curp->outdata = xhtml_alloc(curp->outopts);
1.162 kristaps 238: curp->outfree = html_free;
1.111 kristaps 239: break;
1.173 schwarze 240: case OUTT_HTML:
1.111 kristaps 241: curp->outdata = html_alloc(curp->outopts);
1.162 kristaps 242: curp->outfree = html_free;
243: break;
1.173 schwarze 244: case OUTT_UTF8:
1.163 kristaps 245: curp->outdata = utf8_alloc(curp->outopts);
246: curp->outfree = ascii_free;
247: break;
1.173 schwarze 248: case OUTT_LOCALE:
1.162 kristaps 249: curp->outdata = locale_alloc(curp->outopts);
250: curp->outfree = ascii_free;
1.111 kristaps 251: break;
1.173 schwarze 252: case OUTT_ASCII:
1.111 kristaps 253: curp->outdata = ascii_alloc(curp->outopts);
254: curp->outfree = ascii_free;
255: break;
1.173 schwarze 256: case OUTT_PDF:
1.111 kristaps 257: curp->outdata = pdf_alloc(curp->outopts);
258: curp->outfree = pspdf_free;
259: break;
1.173 schwarze 260: case OUTT_PS:
1.111 kristaps 261: curp->outdata = ps_alloc(curp->outopts);
262: curp->outfree = pspdf_free;
263: break;
264: default:
265: break;
266: }
267:
268: switch (curp->outtype) {
1.173 schwarze 269: case OUTT_HTML:
1.111 kristaps 270: /* FALLTHROUGH */
1.173 schwarze 271: case OUTT_XHTML:
1.111 kristaps 272: curp->outman = html_man;
273: curp->outmdoc = html_mdoc;
274: break;
1.173 schwarze 275: case OUTT_TREE:
1.111 kristaps 276: curp->outman = tree_man;
277: curp->outmdoc = tree_mdoc;
278: break;
1.173 schwarze 279: case OUTT_MAN:
1.164 schwarze 280: curp->outmdoc = man_mdoc;
1.165 kristaps 281: curp->outman = man_man;
1.164 schwarze 282: break;
1.173 schwarze 283: case OUTT_PDF:
1.111 kristaps 284: /* FALLTHROUGH */
1.173 schwarze 285: case OUTT_ASCII:
1.111 kristaps 286: /* FALLTHROUGH */
1.173 schwarze 287: case OUTT_UTF8:
1.163 kristaps 288: /* FALLTHROUGH */
1.173 schwarze 289: case OUTT_LOCALE:
1.162 kristaps 290: /* FALLTHROUGH */
1.173 schwarze 291: case OUTT_PS:
1.111 kristaps 292: curp->outman = terminal_man;
293: curp->outmdoc = terminal_mdoc;
294: break;
295: default:
296: break;
297: }
298: }
299:
1.171 schwarze 300: mparse_result(curp->mp, &mdoc, &man, NULL);
1.154 kristaps 301:
1.111 kristaps 302: /* Execute the out device, if it exists. */
303:
1.154 kristaps 304: if (man && curp->outman)
305: (*curp->outman)(curp->outdata, man);
306: if (mdoc && curp->outmdoc)
307: (*curp->outmdoc)(curp->outdata, mdoc);
1.111 kristaps 308:
309: cleanup:
1.112 kristaps 310:
1.154 kristaps 311: mparse_reset(curp->mp);
1.111 kristaps 312:
1.154 kristaps 313: if (*level < rc)
314: *level = rc;
1.10 kristaps 315: }
316:
317: static int
1.170 schwarze 318: moptions(int *options, char *arg)
1.10 kristaps 319: {
320:
1.17 kristaps 321: if (0 == strcmp(arg, "doc"))
1.170 schwarze 322: *options |= MPARSE_MDOC;
1.19 kristaps 323: else if (0 == strcmp(arg, "andoc"))
1.170 schwarze 324: /* nothing to do */;
1.17 kristaps 325: else if (0 == strcmp(arg, "an"))
1.170 schwarze 326: *options |= MPARSE_MAN;
1.10 kristaps 327: else {
1.176 schwarze 328: fprintf(stderr, "%s: -m%s: Bad argument\n",
329: progname, arg);
1.10 kristaps 330: return(0);
331: }
332:
333: return(1);
1.1 kristaps 334: }
335:
336: static int
1.60 kristaps 337: toptions(struct curparse *curp, char *arg)
1.1 kristaps 338: {
339:
340: if (0 == strcmp(arg, "ascii"))
1.60 kristaps 341: curp->outtype = OUTT_ASCII;
342: else if (0 == strcmp(arg, "lint")) {
343: curp->outtype = OUTT_LINT;
1.103 schwarze 344: curp->wlevel = MANDOCLEVEL_WARNING;
1.154 kristaps 345: } else if (0 == strcmp(arg, "tree"))
1.60 kristaps 346: curp->outtype = OUTT_TREE;
1.164 schwarze 347: else if (0 == strcmp(arg, "man"))
348: curp->outtype = OUTT_MAN;
1.43 kristaps 349: else if (0 == strcmp(arg, "html"))
1.60 kristaps 350: curp->outtype = OUTT_HTML;
1.163 kristaps 351: else if (0 == strcmp(arg, "utf8"))
352: curp->outtype = OUTT_UTF8;
1.162 kristaps 353: else if (0 == strcmp(arg, "locale"))
354: curp->outtype = OUTT_LOCALE;
1.59 kristaps 355: else if (0 == strcmp(arg, "xhtml"))
1.60 kristaps 356: curp->outtype = OUTT_XHTML;
1.85 kristaps 357: else if (0 == strcmp(arg, "ps"))
358: curp->outtype = OUTT_PS;
1.100 kristaps 359: else if (0 == strcmp(arg, "pdf"))
360: curp->outtype = OUTT_PDF;
1.1 kristaps 361: else {
1.176 schwarze 362: fprintf(stderr, "%s: -T%s: Bad argument\n",
363: progname, arg);
1.1 kristaps 364: return(0);
365: }
366:
367: return(1);
368: }
369:
370: static int
1.103 schwarze 371: woptions(struct curparse *curp, char *arg)
1.1 kristaps 372: {
1.34 kristaps 373: char *v, *o;
1.173 schwarze 374: const char *toks[6];
1.1 kristaps 375:
1.103 schwarze 376: toks[0] = "stop";
377: toks[1] = "all";
378: toks[2] = "warning";
379: toks[3] = "error";
380: toks[4] = "fatal";
381: toks[5] = NULL;
1.1 kristaps 382:
1.34 kristaps 383: while (*arg) {
384: o = arg;
1.45 kristaps 385: switch (getsubopt(&arg, UNCONST(toks), &v)) {
1.173 schwarze 386: case 0:
1.103 schwarze 387: curp->wstop = 1;
1.1 kristaps 388: break;
1.173 schwarze 389: case 1:
1.103 schwarze 390: /* FALLTHROUGH */
1.173 schwarze 391: case 2:
1.103 schwarze 392: curp->wlevel = MANDOCLEVEL_WARNING;
1.1 kristaps 393: break;
1.173 schwarze 394: case 3:
1.103 schwarze 395: curp->wlevel = MANDOCLEVEL_ERROR;
1.24 kristaps 396: break;
1.173 schwarze 397: case 4:
1.103 schwarze 398: curp->wlevel = MANDOCLEVEL_FATAL;
1.50 kristaps 399: break;
1.1 kristaps 400: default:
1.176 schwarze 401: fprintf(stderr, "%s: -W%s: Bad argument\n",
402: progname, o);
1.1 kristaps 403: return(0);
404: }
1.34 kristaps 405: }
1.1 kristaps 406:
407: return(1);
408: }
409:
1.153 kristaps 410: static void
1.173 schwarze 411: mmsg(enum mandocerr t, enum mandoclevel lvl,
1.155 kristaps 412: const char *file, int line, int col, const char *msg)
1.71 kristaps 413: {
1.177 schwarze 414: const char *mparse_msg;
1.103 schwarze 415:
1.175 schwarze 416: fprintf(stderr, "%s: %s:", progname, file);
417:
418: if (line)
419: fprintf(stderr, "%d:%d:", line, col + 1);
420:
1.177 schwarze 421: fprintf(stderr, " %s", mparse_strlevel(lvl));
422:
423: if (NULL != (mparse_msg = mparse_strerror(t)))
424: fprintf(stderr, ": %s", mparse_msg);
1.154 kristaps 425:
1.73 kristaps 426: if (msg)
427: fprintf(stderr, ": %s", msg);
1.154 kristaps 428:
1.73 kristaps 429: fputc('\n', stderr);
1.71 kristaps 430: }
CVSweb