Annotation of mandoc/main.c, Revision 1.172
1.172 ! schwarze 1: /* $Id: main.c,v 1.171 2014/03/19 22:20:43 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: #ifdef HAVE_CONFIG_H
20: #include "config.h"
21: #endif
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.79 kristaps 63: enum outt outtype; /* which output to use */
64: out_mdoc outmdoc; /* mdoc output ptr */
65: out_man outman; /* man output ptr */
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.154 kristaps 74: static void parse(struct curparse *, int,
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:
83: int
84: main(int argc, char *argv[])
85: {
1.64 kristaps 86: int c;
1.5 kristaps 87: struct curparse curp;
1.170 schwarze 88: int options;
1.154 kristaps 89: enum mandoclevel rc;
1.166 schwarze 90: char *defos;
1.1 kristaps 91:
1.54 kristaps 92: progname = strrchr(argv[0], '/');
93: if (progname == NULL)
94: progname = argv[0];
95: else
96: ++progname;
97:
1.51 kristaps 98: memset(&curp, 0, sizeof(struct curparse));
1.5 kristaps 99:
1.170 schwarze 100: options = MPARSE_SO;
1.22 kristaps 101: curp.outtype = OUTT_ASCII;
1.103 schwarze 102: curp.wlevel = MANDOCLEVEL_FATAL;
1.166 schwarze 103: defos = NULL;
1.19 kristaps 104:
1.1 kristaps 105: /* LINTED */
1.166 schwarze 106: while (-1 != (c = getopt(argc, argv, "I:m:O:T:VW:")))
1.1 kristaps 107: switch (c) {
1.166 schwarze 108: case ('I'):
109: if (strncmp(optarg, "os=", 3)) {
110: fprintf(stderr, "-I%s: Bad argument\n",
111: optarg);
112: return((int)MANDOCLEVEL_BADARG);
113: }
114: if (defos) {
115: fprintf(stderr, "-I%s: Duplicate argument\n",
116: optarg);
117: return((int)MANDOCLEVEL_BADARG);
118: }
119: defos = mandoc_strdup(optarg + 3);
120: break;
1.10 kristaps 121: case ('m'):
1.170 schwarze 122: if ( ! moptions(&options, optarg))
1.105 kristaps 123: return((int)MANDOCLEVEL_BADARG);
1.10 kristaps 124: break;
1.48 kristaps 125: case ('O'):
1.49 kristaps 126: (void)strlcat(curp.outopts, optarg, BUFSIZ);
127: (void)strlcat(curp.outopts, ",", BUFSIZ);
1.44 kristaps 128: break;
1.1 kristaps 129: case ('T'):
1.60 kristaps 130: if ( ! toptions(&curp, optarg))
1.105 kristaps 131: return((int)MANDOCLEVEL_BADARG);
1.1 kristaps 132: break;
133: case ('W'):
1.103 schwarze 134: if ( ! woptions(&curp, optarg))
1.105 kristaps 135: return((int)MANDOCLEVEL_BADARG);
1.1 kristaps 136: break;
137: case ('V'):
138: version();
139: /* NOTREACHED */
140: default:
141: usage();
142: /* NOTREACHED */
143: }
144:
1.170 schwarze 145: curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
1.154 kristaps 146:
1.165 kristaps 147: /*
148: * Conditionally start up the lookaside buffer before parsing.
149: */
150: if (OUTT_MAN == curp.outtype)
151: mparse_keep(curp.mp);
152:
1.1 kristaps 153: argc -= optind;
154: argv += optind;
155:
1.154 kristaps 156: rc = MANDOCLEVEL_OK;
1.39 kristaps 157:
1.154 kristaps 158: if (NULL == *argv)
159: parse(&curp, STDIN_FILENO, "<stdin>", &rc);
1.64 kristaps 160:
161: while (*argv) {
1.154 kristaps 162: parse(&curp, -1, *argv, &rc);
163: if (MANDOCLEVEL_OK != rc && curp.wstop)
1.64 kristaps 164: break;
165: ++argv;
1.1 kristaps 166: }
167:
1.22 kristaps 168: if (curp.outfree)
169: (*curp.outfree)(curp.outdata);
1.154 kristaps 170: if (curp.mp)
171: mparse_free(curp.mp);
1.166 schwarze 172: free(defos);
1.1 kristaps 173:
1.154 kristaps 174: return((int)rc);
1.1 kristaps 175: }
176:
1.55 kristaps 177: static void
1.1 kristaps 178: version(void)
179: {
180:
1.154 kristaps 181: printf("%s %s\n", progname, VERSION);
1.105 kristaps 182: exit((int)MANDOCLEVEL_OK);
1.1 kristaps 183: }
184:
1.55 kristaps 185: static void
1.1 kristaps 186: usage(void)
187: {
188:
1.154 kristaps 189: fprintf(stderr, "usage: %s "
1.112 kristaps 190: "[-V] "
1.167 schwarze 191: "[-Ios=name] "
1.112 kristaps 192: "[-mformat] "
193: "[-Ooption] "
194: "[-Toutput] "
1.167 schwarze 195: "[-Wlevel]\n"
196: "\t [file ...]\n",
1.112 kristaps 197: progname);
198:
1.105 kristaps 199: exit((int)MANDOCLEVEL_BADARG);
1.68 joerg 200: }
201:
1.64 kristaps 202: static void
1.154 kristaps 203: parse(struct curparse *curp, int fd,
204: const char *file, enum mandoclevel *level)
1.1 kristaps 205: {
1.154 kristaps 206: enum mandoclevel rc;
207: struct mdoc *mdoc;
208: struct man *man;
1.112 kristaps 209:
1.154 kristaps 210: /* Begin by parsing the file itself. */
1.112 kristaps 211:
1.154 kristaps 212: assert(file);
213: assert(fd >= -1);
1.112 kristaps 214:
1.154 kristaps 215: rc = mparse_readfd(curp->mp, fd, file);
1.112 kristaps 216:
1.154 kristaps 217: /* Stop immediately if the parse has failed. */
1.92 kristaps 218:
1.154 kristaps 219: if (MANDOCLEVEL_FATAL <= rc)
1.111 kristaps 220: goto cleanup;
221:
1.1 kristaps 222: /*
1.154 kristaps 223: * With -Wstop and warnings or errors of at least the requested
224: * level, do not produce output.
1.1 kristaps 225: */
226:
1.154 kristaps 227: if (MANDOCLEVEL_OK != rc && curp->wstop)
1.111 kristaps 228: goto cleanup;
229:
230: /* If unset, allocate output dev now (if applicable). */
231:
232: if ( ! (curp->outman && curp->outmdoc)) {
233: switch (curp->outtype) {
234: case (OUTT_XHTML):
235: curp->outdata = xhtml_alloc(curp->outopts);
1.162 kristaps 236: curp->outfree = html_free;
1.111 kristaps 237: break;
238: case (OUTT_HTML):
239: curp->outdata = html_alloc(curp->outopts);
1.162 kristaps 240: curp->outfree = html_free;
241: break;
1.163 kristaps 242: case (OUTT_UTF8):
243: curp->outdata = utf8_alloc(curp->outopts);
244: curp->outfree = ascii_free;
245: break;
1.162 kristaps 246: case (OUTT_LOCALE):
247: curp->outdata = locale_alloc(curp->outopts);
248: curp->outfree = ascii_free;
1.111 kristaps 249: break;
250: case (OUTT_ASCII):
251: curp->outdata = ascii_alloc(curp->outopts);
252: curp->outfree = ascii_free;
253: break;
254: case (OUTT_PDF):
255: curp->outdata = pdf_alloc(curp->outopts);
256: curp->outfree = pspdf_free;
257: break;
258: case (OUTT_PS):
259: curp->outdata = ps_alloc(curp->outopts);
260: curp->outfree = pspdf_free;
261: break;
262: default:
263: break;
264: }
265:
266: switch (curp->outtype) {
267: case (OUTT_HTML):
268: /* FALLTHROUGH */
269: case (OUTT_XHTML):
270: curp->outman = html_man;
271: curp->outmdoc = html_mdoc;
272: break;
273: case (OUTT_TREE):
274: curp->outman = tree_man;
275: curp->outmdoc = tree_mdoc;
276: break;
1.164 schwarze 277: case (OUTT_MAN):
278: curp->outmdoc = man_mdoc;
1.165 kristaps 279: curp->outman = man_man;
1.164 schwarze 280: break;
1.111 kristaps 281: case (OUTT_PDF):
282: /* FALLTHROUGH */
283: case (OUTT_ASCII):
284: /* FALLTHROUGH */
1.163 kristaps 285: case (OUTT_UTF8):
286: /* FALLTHROUGH */
1.162 kristaps 287: case (OUTT_LOCALE):
288: /* FALLTHROUGH */
1.111 kristaps 289: case (OUTT_PS):
290: curp->outman = terminal_man;
291: curp->outmdoc = terminal_mdoc;
292: break;
293: default:
294: break;
295: }
296: }
297:
1.171 schwarze 298: mparse_result(curp->mp, &mdoc, &man, NULL);
1.154 kristaps 299:
1.111 kristaps 300: /* Execute the out device, if it exists. */
301:
1.154 kristaps 302: if (man && curp->outman)
303: (*curp->outman)(curp->outdata, man);
304: if (mdoc && curp->outmdoc)
305: (*curp->outmdoc)(curp->outdata, mdoc);
1.111 kristaps 306:
307: cleanup:
1.112 kristaps 308:
1.154 kristaps 309: mparse_reset(curp->mp);
1.111 kristaps 310:
1.154 kristaps 311: if (*level < rc)
312: *level = rc;
1.10 kristaps 313: }
314:
315: static int
1.170 schwarze 316: moptions(int *options, char *arg)
1.10 kristaps 317: {
318:
1.17 kristaps 319: if (0 == strcmp(arg, "doc"))
1.170 schwarze 320: *options |= MPARSE_MDOC;
1.19 kristaps 321: else if (0 == strcmp(arg, "andoc"))
1.170 schwarze 322: /* nothing to do */;
1.17 kristaps 323: else if (0 == strcmp(arg, "an"))
1.170 schwarze 324: *options |= MPARSE_MAN;
1.10 kristaps 325: else {
1.57 kristaps 326: fprintf(stderr, "%s: Bad argument\n", arg);
1.10 kristaps 327: return(0);
328: }
329:
330: return(1);
1.1 kristaps 331: }
332:
333: static int
1.60 kristaps 334: toptions(struct curparse *curp, char *arg)
1.1 kristaps 335: {
336:
337: if (0 == strcmp(arg, "ascii"))
1.60 kristaps 338: curp->outtype = OUTT_ASCII;
339: else if (0 == strcmp(arg, "lint")) {
340: curp->outtype = OUTT_LINT;
1.103 schwarze 341: curp->wlevel = MANDOCLEVEL_WARNING;
1.154 kristaps 342: } else if (0 == strcmp(arg, "tree"))
1.60 kristaps 343: curp->outtype = OUTT_TREE;
1.164 schwarze 344: else if (0 == strcmp(arg, "man"))
345: curp->outtype = OUTT_MAN;
1.43 kristaps 346: else if (0 == strcmp(arg, "html"))
1.60 kristaps 347: curp->outtype = OUTT_HTML;
1.163 kristaps 348: else if (0 == strcmp(arg, "utf8"))
349: curp->outtype = OUTT_UTF8;
1.162 kristaps 350: else if (0 == strcmp(arg, "locale"))
351: curp->outtype = OUTT_LOCALE;
1.59 kristaps 352: else if (0 == strcmp(arg, "xhtml"))
1.60 kristaps 353: curp->outtype = OUTT_XHTML;
1.85 kristaps 354: else if (0 == strcmp(arg, "ps"))
355: curp->outtype = OUTT_PS;
1.100 kristaps 356: else if (0 == strcmp(arg, "pdf"))
357: curp->outtype = OUTT_PDF;
1.1 kristaps 358: else {
1.57 kristaps 359: fprintf(stderr, "%s: Bad argument\n", arg);
1.1 kristaps 360: return(0);
361: }
362:
363: return(1);
364: }
365:
366: static int
1.103 schwarze 367: woptions(struct curparse *curp, char *arg)
1.1 kristaps 368: {
1.34 kristaps 369: char *v, *o;
1.103 schwarze 370: const char *toks[6];
1.1 kristaps 371:
1.103 schwarze 372: toks[0] = "stop";
373: toks[1] = "all";
374: toks[2] = "warning";
375: toks[3] = "error";
376: toks[4] = "fatal";
377: toks[5] = NULL;
1.1 kristaps 378:
1.34 kristaps 379: while (*arg) {
380: o = arg;
1.45 kristaps 381: switch (getsubopt(&arg, UNCONST(toks), &v)) {
1.1 kristaps 382: case (0):
1.103 schwarze 383: curp->wstop = 1;
1.1 kristaps 384: break;
385: case (1):
1.103 schwarze 386: /* FALLTHROUGH */
1.1 kristaps 387: case (2):
1.103 schwarze 388: curp->wlevel = MANDOCLEVEL_WARNING;
1.1 kristaps 389: break;
1.20 kristaps 390: case (3):
1.103 schwarze 391: curp->wlevel = MANDOCLEVEL_ERROR;
1.24 kristaps 392: break;
393: case (4):
1.103 schwarze 394: curp->wlevel = MANDOCLEVEL_FATAL;
1.50 kristaps 395: break;
1.1 kristaps 396: default:
1.103 schwarze 397: fprintf(stderr, "-W%s: Bad argument\n", o);
1.1 kristaps 398: return(0);
399: }
1.34 kristaps 400: }
1.1 kristaps 401:
402: return(1);
403: }
404:
1.153 kristaps 405: static void
1.155 kristaps 406: mmsg(enum mandocerr t, enum mandoclevel lvl,
407: const char *file, int line, int col, const char *msg)
1.71 kristaps 408: {
1.103 schwarze 409:
1.155 kristaps 410: fprintf(stderr, "%s:%d:%d: %s: %s",
411: file, line, col + 1,
1.160 kristaps 412: mparse_strlevel(lvl),
413: mparse_strerror(t));
1.154 kristaps 414:
1.73 kristaps 415: if (msg)
416: fprintf(stderr, ": %s", msg);
1.154 kristaps 417:
1.73 kristaps 418: fputc('\n', stderr);
1.71 kristaps 419: }
CVSweb