Annotation of mandoc/main.c, Revision 1.185
1.185 ! schwarze 1: /* $Id: main.c,v 1.184 2014/08/22 04:52:55 schwarze Exp $ */
1.1 kristaps 2: /*
1.183 schwarze 3: * Copyright (c) 2008-2012 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>
1.185 ! schwarze 24: #include <ctype.h>
1.183 schwarze 25: #include <errno.h>
1.1 kristaps 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.172 schwarze 33: #include "mandoc_aux.h"
1.90 kristaps 34: #include "main.h"
1.1 kristaps 35: #include "mdoc.h"
1.10 kristaps 36: #include "man.h"
1.180 schwarze 37: #include "manpath.h"
38: #include "mansearch.h"
1.101 joerg 39:
1.55 kristaps 40: #if !defined(__GNUC__) || (__GNUC__ < 2)
1.56 kristaps 41: # if !defined(lint)
42: # define __attribute__(x)
43: # endif
1.55 kristaps 44: #endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
1.16 kristaps 45:
1.181 schwarze 46: enum outmode {
47: OUTMODE_DEF = 0,
48: OUTMODE_FLN,
49: OUTMODE_LST,
50: OUTMODE_ALL,
51: OUTMODE_INT,
52: OUTMODE_ONE
53: };
54:
1.42 kristaps 55: typedef void (*out_mdoc)(void *, const struct mdoc *);
56: typedef void (*out_man)(void *, const struct man *);
1.22 kristaps 57: typedef void (*out_free)(void *);
58:
1.19 kristaps 59: enum outt {
1.154 kristaps 60: OUTT_ASCII = 0, /* -Tascii */
1.162 kristaps 61: OUTT_LOCALE, /* -Tlocale */
1.163 kristaps 62: OUTT_UTF8, /* -Tutf8 */
1.154 kristaps 63: OUTT_TREE, /* -Ttree */
1.164 schwarze 64: OUTT_MAN, /* -Tman */
1.154 kristaps 65: OUTT_HTML, /* -Thtml */
66: OUTT_XHTML, /* -Txhtml */
67: OUTT_LINT, /* -Tlint */
68: OUTT_PS, /* -Tps */
69: OUTT_PDF /* -Tpdf */
1.19 kristaps 70: };
71:
1.5 kristaps 72: struct curparse {
1.154 kristaps 73: struct mparse *mp;
1.148 kristaps 74: enum mandoclevel wlevel; /* ignore messages below this */
75: int wstop; /* stop after a file with a warning */
1.173 schwarze 76: enum outt outtype; /* which output to use */
1.79 kristaps 77: out_mdoc outmdoc; /* mdoc output ptr */
1.173 schwarze 78: out_man outman; /* man output ptr */
1.79 kristaps 79: out_free outfree; /* free output ptr */
80: void *outdata; /* data for output */
81: char outopts[BUFSIZ]; /* buf of output opts */
82: };
83:
1.170 schwarze 84: static int moptions(int *, char *);
1.155 kristaps 85: static void mmsg(enum mandocerr, enum mandoclevel,
86: const char *, int, int, const char *);
1.173 schwarze 87: static void parse(struct curparse *, int,
1.154 kristaps 88: const char *, enum mandoclevel *);
1.183 schwarze 89: static void spawn_pager(void);
1.66 kristaps 90: static int toptions(struct curparse *, char *);
1.180 schwarze 91: static void usage(enum argmode) __attribute__((noreturn));
1.55 kristaps 92: static void version(void) __attribute__((noreturn));
1.103 schwarze 93: static int woptions(struct curparse *, char *);
1.1 kristaps 94:
1.182 schwarze 95: static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
1.54 kristaps 96: static const char *progname;
1.1 kristaps 97:
1.173 schwarze 98:
1.1 kristaps 99: int
100: main(int argc, char *argv[])
101: {
1.5 kristaps 102: struct curparse curp;
1.180 schwarze 103: struct mansearch search;
104: struct manpaths paths;
105: char *conf_file, *defpaths, *auxpaths;
106: char *defos;
107: #if HAVE_SQLITE3
108: struct manpage *res;
1.182 schwarze 109: char **auxargv;
110: size_t isec, i, sz;
111: int prio, best_prio;
112: char sec;
1.180 schwarze 113: #endif
114: enum mandoclevel rc;
1.181 schwarze 115: enum outmode outmode;
1.180 schwarze 116: int show_usage;
1.183 schwarze 117: int use_pager;
1.170 schwarze 118: int options;
1.180 schwarze 119: int c;
1.1 kristaps 120:
1.54 kristaps 121: progname = strrchr(argv[0], '/');
122: if (progname == NULL)
123: progname = argv[0];
124: else
125: ++progname;
1.179 schwarze 126:
1.180 schwarze 127: /* Search options. */
128:
129: memset(&paths, 0, sizeof(struct manpaths));
130: conf_file = defpaths = auxpaths = NULL;
131:
132: memset(&search, 0, sizeof(struct mansearch));
133: search.outkey = "Nd";
134:
135: if (strcmp(progname, "man") == 0)
136: search.argmode = ARG_NAME;
137: else if (strncmp(progname, "apropos", 7) == 0)
138: search.argmode = ARG_EXPR;
139: else if (strncmp(progname, "whatis", 6) == 0)
140: search.argmode = ARG_WORD;
141: else
142: search.argmode = ARG_FILE;
143:
144: /* Parser and formatter options. */
1.54 kristaps 145:
1.51 kristaps 146: memset(&curp, 0, sizeof(struct curparse));
1.22 kristaps 147: curp.outtype = OUTT_ASCII;
1.103 schwarze 148: curp.wlevel = MANDOCLEVEL_FATAL;
1.180 schwarze 149: options = MPARSE_SO;
1.166 schwarze 150: defos = NULL;
1.19 kristaps 151:
1.183 schwarze 152: use_pager = 1;
1.180 schwarze 153: show_usage = 0;
1.181 schwarze 154: outmode = OUTMODE_DEF;
1.183 schwarze 155:
156: while (-1 != (c = getopt(argc, argv, "aC:cfI:ikM:m:O:S:s:T:VW:w"))) {
1.1 kristaps 157: switch (c) {
1.181 schwarze 158: case 'a':
159: outmode = OUTMODE_ALL;
160: break;
1.180 schwarze 161: case 'C':
162: conf_file = optarg;
163: break;
1.183 schwarze 164: case 'c':
165: use_pager = 0;
166: break;
1.180 schwarze 167: case 'f':
168: search.argmode = ARG_WORD;
169: break;
1.173 schwarze 170: case 'I':
1.166 schwarze 171: if (strncmp(optarg, "os=", 3)) {
1.173 schwarze 172: fprintf(stderr,
1.176 schwarze 173: "%s: -I%s: Bad argument\n",
174: progname, optarg);
1.166 schwarze 175: return((int)MANDOCLEVEL_BADARG);
176: }
177: if (defos) {
1.173 schwarze 178: fprintf(stderr,
1.176 schwarze 179: "%s: -I%s: Duplicate argument\n",
180: progname, optarg);
1.166 schwarze 181: return((int)MANDOCLEVEL_BADARG);
182: }
183: defos = mandoc_strdup(optarg + 3);
184: break;
1.181 schwarze 185: case 'i':
186: outmode = OUTMODE_INT;
187: break;
1.180 schwarze 188: case 'k':
189: search.argmode = ARG_EXPR;
190: break;
191: case 'M':
192: defpaths = optarg;
193: break;
1.173 schwarze 194: case 'm':
1.180 schwarze 195: auxpaths = optarg;
1.10 kristaps 196: break;
1.173 schwarze 197: case 'O':
1.180 schwarze 198: search.outkey = optarg;
1.49 kristaps 199: (void)strlcat(curp.outopts, optarg, BUFSIZ);
200: (void)strlcat(curp.outopts, ",", BUFSIZ);
1.44 kristaps 201: break;
1.180 schwarze 202: case 'S':
203: search.arch = optarg;
204: break;
205: case 's':
206: search.sec = optarg;
207: break;
1.173 schwarze 208: case 'T':
1.60 kristaps 209: if ( ! toptions(&curp, optarg))
1.105 kristaps 210: return((int)MANDOCLEVEL_BADARG);
1.1 kristaps 211: break;
1.173 schwarze 212: case 'W':
1.103 schwarze 213: if ( ! woptions(&curp, optarg))
1.105 kristaps 214: return((int)MANDOCLEVEL_BADARG);
1.1 kristaps 215: break;
1.181 schwarze 216: case 'w':
217: outmode = OUTMODE_FLN;
218: break;
1.173 schwarze 219: case 'V':
1.1 kristaps 220: version();
221: /* NOTREACHED */
222: default:
1.180 schwarze 223: show_usage = 1;
224: break;
1.1 kristaps 225: }
1.180 schwarze 226: }
227:
228: if (show_usage)
229: usage(search.argmode);
230:
1.185 ! schwarze 231: /* Postprocess options. */
! 232:
1.181 schwarze 233: if (outmode == OUTMODE_DEF) {
234: switch (search.argmode) {
235: case ARG_FILE:
236: outmode = OUTMODE_ALL;
1.183 schwarze 237: use_pager = 0;
1.181 schwarze 238: break;
239: case ARG_NAME:
240: outmode = OUTMODE_ONE;
241: break;
242: default:
243: outmode = OUTMODE_LST;
244: break;
245: }
246: }
247:
1.185 ! schwarze 248: /* Parse arguments. */
! 249:
1.180 schwarze 250: argc -= optind;
251: argv += optind;
1.182 schwarze 252: #if HAVE_SQLITE3
253: auxargv = NULL;
254: #endif
1.185 ! schwarze 255:
! 256: /* Quirk for a man(1) section argument without -s. */
! 257:
! 258: if (search.argmode == ARG_NAME &&
! 259: argv[0] != NULL &&
! 260: isdigit((unsigned char)argv[0][0]) &&
! 261: (argv[0][1] == '\0' || !strcmp(argv[0], "3p"))) {
! 262: search.sec = argv[0];
! 263: argv++;
! 264: argc--;
! 265: }
1.182 schwarze 266:
267: rc = MANDOCLEVEL_OK;
1.180 schwarze 268:
269: /* man(1), whatis(1), apropos(1) */
270:
271: if (search.argmode != ARG_FILE) {
272: #if HAVE_SQLITE3
273: if (argc == 0)
274: usage(search.argmode);
1.182 schwarze 275:
276: /* Access the mandoc database. */
277:
1.180 schwarze 278: manpath_parse(&paths, conf_file, defpaths, auxpaths);
279: mansearch_setup(1);
280: if( ! mansearch(&search, &paths, argc, argv, &res, &sz))
281: usage(search.argmode);
282: manpath_free(&paths);
1.182 schwarze 283:
284: /*
285: * For standard man(1) and -a output mode,
286: * prepare for copying filename pointers
287: * into the program parameter array.
288: */
289:
290: if (outmode == OUTMODE_ONE) {
291: argc = 1;
292: argv[0] = res[0].file;
293: argv[1] = NULL;
294: best_prio = 10;
295: } else if (outmode == OUTMODE_ALL) {
296: argc = (int)sz;
297: argv = auxargv = mandoc_reallocarray(
298: NULL, sz + 1, sizeof(char *));
299: argv[argc] = NULL;
300: }
301:
302: /* Iterate all matching manuals. */
303:
1.181 schwarze 304: for (i = 0; i < sz; i++) {
305: if (outmode == OUTMODE_FLN)
306: puts(res[i].file);
1.182 schwarze 307: else if (outmode == OUTMODE_LST)
1.181 schwarze 308: printf("%s - %s\n", res[i].names,
309: res[i].output == NULL ? "" :
310: res[i].output);
1.182 schwarze 311: else if (outmode == OUTMODE_ALL)
312: argv[i] = res[i].file;
313: else {
314: /* Search for the best section. */
315: isec = strcspn(res[i].file, "123456789");
316: sec = res[i].file[isec];
317: if ('\0' == sec)
318: continue;
319: prio = sec_prios[sec - '1'];
320: if (prio >= best_prio)
321: continue;
322: best_prio = prio;
323: argv[0] = res[i].file;
324: }
1.181 schwarze 325: }
1.182 schwarze 326:
327: /*
328: * For man(1), -a and -i output mode, fall through
329: * to the main mandoc(1) code iterating files
330: * and running the parsers on each of them.
331: */
332:
333: if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST)
334: goto out;
1.180 schwarze 335: #else
336: fputs("mandoc: database support not compiled in\n",
337: stderr);
338: return((int)MANDOCLEVEL_BADARG);
339: #endif
340: }
341:
342: /* mandoc(1) */
343:
344: if ( ! moptions(&options, auxpaths))
345: return((int)MANDOCLEVEL_BADARG);
1.1 kristaps 346:
1.183 schwarze 347: if (use_pager && isatty(STDOUT_FILENO))
348: spawn_pager();
349:
1.170 schwarze 350: curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
1.154 kristaps 351:
1.165 kristaps 352: /*
353: * Conditionally start up the lookaside buffer before parsing.
354: */
355: if (OUTT_MAN == curp.outtype)
356: mparse_keep(curp.mp);
357:
1.154 kristaps 358: if (NULL == *argv)
359: parse(&curp, STDIN_FILENO, "<stdin>", &rc);
1.64 kristaps 360:
361: while (*argv) {
1.154 kristaps 362: parse(&curp, -1, *argv, &rc);
363: if (MANDOCLEVEL_OK != rc && curp.wstop)
1.64 kristaps 364: break;
365: ++argv;
1.1 kristaps 366: }
367:
1.22 kristaps 368: if (curp.outfree)
369: (*curp.outfree)(curp.outdata);
1.154 kristaps 370: if (curp.mp)
371: mparse_free(curp.mp);
1.182 schwarze 372:
373: #if HAVE_SQLITE3
374: out:
375: if (search.argmode != ARG_FILE) {
376: mansearch_free(res, sz);
377: mansearch_setup(0);
378: free(auxargv);
379: }
380: #endif
381:
1.166 schwarze 382: free(defos);
1.1 kristaps 383:
1.154 kristaps 384: return((int)rc);
1.1 kristaps 385: }
386:
1.55 kristaps 387: static void
1.1 kristaps 388: version(void)
389: {
390:
1.180 schwarze 391: printf("mandoc %s\n", VERSION);
1.105 kristaps 392: exit((int)MANDOCLEVEL_OK);
1.1 kristaps 393: }
394:
1.55 kristaps 395: static void
1.180 schwarze 396: usage(enum argmode argmode)
1.1 kristaps 397: {
398:
1.180 schwarze 399: switch (argmode) {
400: case ARG_FILE:
401: fputs("usage: mandoc [-V] [-Ios=name] [-mformat]"
402: " [-Ooption] [-Toutput] [-Wlevel]\n"
403: "\t [file ...]\n", stderr);
404: break;
405: case ARG_NAME:
406: fputs("usage: man [-acfhkVw] [-C file] "
407: "[-M path] [-m path] [-S arch] [-s section]\n"
408: "\t [section] name ...\n", stderr);
409: break;
410: case ARG_WORD:
411: fputs("usage: whatis [-V] [-C file] [-M path] [-m path] "
412: "[-S arch] [-s section] name ...\n", stderr);
413: break;
414: case ARG_EXPR:
415: fputs("usage: apropos [-V] [-C file] [-M path] [-m path] "
416: "[-O outkey] [-S arch]\n"
417: "\t [-s section] expression ...\n", stderr);
418: break;
419: }
1.105 kristaps 420: exit((int)MANDOCLEVEL_BADARG);
1.68 joerg 421: }
422:
1.64 kristaps 423: static void
1.173 schwarze 424: parse(struct curparse *curp, int fd, const char *file,
425: enum mandoclevel *level)
1.1 kristaps 426: {
1.154 kristaps 427: enum mandoclevel rc;
428: struct mdoc *mdoc;
429: struct man *man;
1.112 kristaps 430:
1.154 kristaps 431: /* Begin by parsing the file itself. */
1.112 kristaps 432:
1.154 kristaps 433: assert(file);
434: assert(fd >= -1);
1.112 kristaps 435:
1.154 kristaps 436: rc = mparse_readfd(curp->mp, fd, file);
1.112 kristaps 437:
1.154 kristaps 438: /* Stop immediately if the parse has failed. */
1.92 kristaps 439:
1.154 kristaps 440: if (MANDOCLEVEL_FATAL <= rc)
1.111 kristaps 441: goto cleanup;
442:
1.1 kristaps 443: /*
1.154 kristaps 444: * With -Wstop and warnings or errors of at least the requested
445: * level, do not produce output.
1.1 kristaps 446: */
447:
1.154 kristaps 448: if (MANDOCLEVEL_OK != rc && curp->wstop)
1.111 kristaps 449: goto cleanup;
450:
451: /* If unset, allocate output dev now (if applicable). */
452:
453: if ( ! (curp->outman && curp->outmdoc)) {
454: switch (curp->outtype) {
1.173 schwarze 455: case OUTT_XHTML:
1.111 kristaps 456: curp->outdata = xhtml_alloc(curp->outopts);
1.162 kristaps 457: curp->outfree = html_free;
1.111 kristaps 458: break;
1.173 schwarze 459: case OUTT_HTML:
1.111 kristaps 460: curp->outdata = html_alloc(curp->outopts);
1.162 kristaps 461: curp->outfree = html_free;
462: break;
1.173 schwarze 463: case OUTT_UTF8:
1.163 kristaps 464: curp->outdata = utf8_alloc(curp->outopts);
465: curp->outfree = ascii_free;
466: break;
1.173 schwarze 467: case OUTT_LOCALE:
1.162 kristaps 468: curp->outdata = locale_alloc(curp->outopts);
469: curp->outfree = ascii_free;
1.111 kristaps 470: break;
1.173 schwarze 471: case OUTT_ASCII:
1.111 kristaps 472: curp->outdata = ascii_alloc(curp->outopts);
473: curp->outfree = ascii_free;
474: break;
1.173 schwarze 475: case OUTT_PDF:
1.111 kristaps 476: curp->outdata = pdf_alloc(curp->outopts);
477: curp->outfree = pspdf_free;
478: break;
1.173 schwarze 479: case OUTT_PS:
1.111 kristaps 480: curp->outdata = ps_alloc(curp->outopts);
481: curp->outfree = pspdf_free;
482: break;
483: default:
484: break;
485: }
486:
487: switch (curp->outtype) {
1.173 schwarze 488: case OUTT_HTML:
1.111 kristaps 489: /* FALLTHROUGH */
1.173 schwarze 490: case OUTT_XHTML:
1.111 kristaps 491: curp->outman = html_man;
492: curp->outmdoc = html_mdoc;
493: break;
1.173 schwarze 494: case OUTT_TREE:
1.111 kristaps 495: curp->outman = tree_man;
496: curp->outmdoc = tree_mdoc;
497: break;
1.173 schwarze 498: case OUTT_MAN:
1.164 schwarze 499: curp->outmdoc = man_mdoc;
1.165 kristaps 500: curp->outman = man_man;
1.164 schwarze 501: break;
1.173 schwarze 502: case OUTT_PDF:
1.111 kristaps 503: /* FALLTHROUGH */
1.173 schwarze 504: case OUTT_ASCII:
1.111 kristaps 505: /* FALLTHROUGH */
1.173 schwarze 506: case OUTT_UTF8:
1.163 kristaps 507: /* FALLTHROUGH */
1.173 schwarze 508: case OUTT_LOCALE:
1.162 kristaps 509: /* FALLTHROUGH */
1.173 schwarze 510: case OUTT_PS:
1.111 kristaps 511: curp->outman = terminal_man;
512: curp->outmdoc = terminal_mdoc;
513: break;
514: default:
515: break;
516: }
517: }
518:
1.171 schwarze 519: mparse_result(curp->mp, &mdoc, &man, NULL);
1.154 kristaps 520:
1.111 kristaps 521: /* Execute the out device, if it exists. */
522:
1.154 kristaps 523: if (man && curp->outman)
524: (*curp->outman)(curp->outdata, man);
525: if (mdoc && curp->outmdoc)
526: (*curp->outmdoc)(curp->outdata, mdoc);
1.111 kristaps 527:
528: cleanup:
1.112 kristaps 529:
1.154 kristaps 530: mparse_reset(curp->mp);
1.111 kristaps 531:
1.154 kristaps 532: if (*level < rc)
533: *level = rc;
1.10 kristaps 534: }
535:
536: static int
1.170 schwarze 537: moptions(int *options, char *arg)
1.10 kristaps 538: {
539:
1.180 schwarze 540: if (arg == NULL)
541: /* nothing to do */;
542: else if (0 == strcmp(arg, "doc"))
1.170 schwarze 543: *options |= MPARSE_MDOC;
1.19 kristaps 544: else if (0 == strcmp(arg, "andoc"))
1.170 schwarze 545: /* nothing to do */;
1.17 kristaps 546: else if (0 == strcmp(arg, "an"))
1.170 schwarze 547: *options |= MPARSE_MAN;
1.10 kristaps 548: else {
1.176 schwarze 549: fprintf(stderr, "%s: -m%s: Bad argument\n",
550: progname, arg);
1.10 kristaps 551: return(0);
552: }
553:
554: return(1);
1.1 kristaps 555: }
556:
557: static int
1.60 kristaps 558: toptions(struct curparse *curp, char *arg)
1.1 kristaps 559: {
560:
561: if (0 == strcmp(arg, "ascii"))
1.60 kristaps 562: curp->outtype = OUTT_ASCII;
563: else if (0 == strcmp(arg, "lint")) {
564: curp->outtype = OUTT_LINT;
1.103 schwarze 565: curp->wlevel = MANDOCLEVEL_WARNING;
1.154 kristaps 566: } else if (0 == strcmp(arg, "tree"))
1.60 kristaps 567: curp->outtype = OUTT_TREE;
1.164 schwarze 568: else if (0 == strcmp(arg, "man"))
569: curp->outtype = OUTT_MAN;
1.43 kristaps 570: else if (0 == strcmp(arg, "html"))
1.60 kristaps 571: curp->outtype = OUTT_HTML;
1.163 kristaps 572: else if (0 == strcmp(arg, "utf8"))
573: curp->outtype = OUTT_UTF8;
1.162 kristaps 574: else if (0 == strcmp(arg, "locale"))
575: curp->outtype = OUTT_LOCALE;
1.59 kristaps 576: else if (0 == strcmp(arg, "xhtml"))
1.60 kristaps 577: curp->outtype = OUTT_XHTML;
1.85 kristaps 578: else if (0 == strcmp(arg, "ps"))
579: curp->outtype = OUTT_PS;
1.100 kristaps 580: else if (0 == strcmp(arg, "pdf"))
581: curp->outtype = OUTT_PDF;
1.1 kristaps 582: else {
1.176 schwarze 583: fprintf(stderr, "%s: -T%s: Bad argument\n",
584: progname, arg);
1.1 kristaps 585: return(0);
586: }
587:
588: return(1);
589: }
590:
591: static int
1.103 schwarze 592: woptions(struct curparse *curp, char *arg)
1.1 kristaps 593: {
1.34 kristaps 594: char *v, *o;
1.173 schwarze 595: const char *toks[6];
1.1 kristaps 596:
1.103 schwarze 597: toks[0] = "stop";
598: toks[1] = "all";
599: toks[2] = "warning";
600: toks[3] = "error";
601: toks[4] = "fatal";
602: toks[5] = NULL;
1.1 kristaps 603:
1.34 kristaps 604: while (*arg) {
605: o = arg;
1.45 kristaps 606: switch (getsubopt(&arg, UNCONST(toks), &v)) {
1.173 schwarze 607: case 0:
1.103 schwarze 608: curp->wstop = 1;
1.1 kristaps 609: break;
1.173 schwarze 610: case 1:
1.103 schwarze 611: /* FALLTHROUGH */
1.173 schwarze 612: case 2:
1.103 schwarze 613: curp->wlevel = MANDOCLEVEL_WARNING;
1.1 kristaps 614: break;
1.173 schwarze 615: case 3:
1.103 schwarze 616: curp->wlevel = MANDOCLEVEL_ERROR;
1.24 kristaps 617: break;
1.173 schwarze 618: case 4:
1.103 schwarze 619: curp->wlevel = MANDOCLEVEL_FATAL;
1.50 kristaps 620: break;
1.1 kristaps 621: default:
1.176 schwarze 622: fprintf(stderr, "%s: -W%s: Bad argument\n",
623: progname, o);
1.1 kristaps 624: return(0);
625: }
1.34 kristaps 626: }
1.1 kristaps 627:
628: return(1);
629: }
630:
1.153 kristaps 631: static void
1.173 schwarze 632: mmsg(enum mandocerr t, enum mandoclevel lvl,
1.155 kristaps 633: const char *file, int line, int col, const char *msg)
1.71 kristaps 634: {
1.177 schwarze 635: const char *mparse_msg;
1.103 schwarze 636:
1.175 schwarze 637: fprintf(stderr, "%s: %s:", progname, file);
638:
639: if (line)
640: fprintf(stderr, "%d:%d:", line, col + 1);
641:
1.177 schwarze 642: fprintf(stderr, " %s", mparse_strlevel(lvl));
643:
644: if (NULL != (mparse_msg = mparse_strerror(t)))
645: fprintf(stderr, ": %s", mparse_msg);
1.154 kristaps 646:
1.73 kristaps 647: if (msg)
648: fprintf(stderr, ": %s", msg);
1.154 kristaps 649:
1.73 kristaps 650: fputc('\n', stderr);
1.183 schwarze 651: }
652:
653: static void
654: spawn_pager(void)
655: {
1.184 schwarze 656: #define MAX_PAGER_ARGS 16
657: char *argv[MAX_PAGER_ARGS];
658: const char *pager;
659: char *cp;
660: int fildes[2];
661: int argc;
1.183 schwarze 662:
663: if (pipe(fildes) == -1) {
664: fprintf(stderr, "%s: pipe: %s\n",
665: progname, strerror(errno));
666: return;
667: }
668:
669: switch (fork()) {
670: case -1:
671: fprintf(stderr, "%s: fork: %s\n",
672: progname, strerror(errno));
673: exit((int)MANDOCLEVEL_SYSERR);
674: case 0:
675: close(fildes[0]);
676: if (dup2(fildes[1], STDOUT_FILENO) == -1) {
677: fprintf(stderr, "%s: dup output: %s\n",
678: progname, strerror(errno));
679: exit((int)MANDOCLEVEL_SYSERR);
680: }
681: return;
682: default:
1.184 schwarze 683: break;
684: }
685:
686: /* The original process becomes the pager. */
687:
688: close(fildes[1]);
689: if (dup2(fildes[0], STDIN_FILENO) == -1) {
690: fprintf(stderr, "%s: dup input: %s\n",
691: progname, strerror(errno));
1.183 schwarze 692: exit((int)MANDOCLEVEL_SYSERR);
693: }
1.184 schwarze 694:
695: pager = getenv("MANPAGER");
696: if (pager == NULL || *pager == '\0')
697: pager = getenv("PAGER");
698: if (pager == NULL || *pager == '\0')
699: pager = "/usr/bin/more -s";
700: cp = mandoc_strdup(pager);
701:
702: /*
703: * Parse the pager command into words.
704: * Intentionally do not do anything fancy here.
705: */
706:
707: argc = 0;
708: while (argc + 1 < MAX_PAGER_ARGS) {
709: argv[argc++] = cp;
710: cp = strchr(cp, ' ');
711: if (cp == NULL)
712: break;
713: *cp++ = '\0';
714: while (*cp == ' ')
715: cp++;
716: if (*cp == '\0')
717: break;
718: }
719: argv[argc] = NULL;
720:
721: /* Hand over to the pager. */
722:
723: execvp(argv[0], argv);
724: fprintf(stderr, "%s: exec: %s\n",
725: progname, strerror(errno));
726: exit((int)MANDOCLEVEL_SYSERR);
1.71 kristaps 727: }
CVSweb