diff options
Diffstat (limited to 'usr/src/cmd/mandoc/main.c')
| -rw-r--r-- | usr/src/cmd/mandoc/main.c | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/usr/src/cmd/mandoc/main.c b/usr/src/cmd/mandoc/main.c new file mode 100644 index 0000000000..fec83fba51 --- /dev/null +++ b/usr/src/cmd/mandoc/main.c @@ -0,0 +1,401 @@ +/* $Id: main.c,v 1.165 2011/10/06 22:29:12 kristaps Exp $ */ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "mandoc.h" +#include "main.h" +#include "mdoc.h" +#include "man.h" + +#if !defined(__GNUC__) || (__GNUC__ < 2) +# if !defined(lint) +# define __attribute__(x) +# endif +#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */ + +typedef void (*out_mdoc)(void *, const struct mdoc *); +typedef void (*out_man)(void *, const struct man *); +typedef void (*out_free)(void *); + +enum outt { + OUTT_ASCII = 0, /* -Tascii */ + OUTT_LOCALE, /* -Tlocale */ + OUTT_UTF8, /* -Tutf8 */ + OUTT_TREE, /* -Ttree */ + OUTT_MAN, /* -Tman */ + OUTT_HTML, /* -Thtml */ + OUTT_XHTML, /* -Txhtml */ + OUTT_LINT, /* -Tlint */ + OUTT_PS, /* -Tps */ + OUTT_PDF /* -Tpdf */ +}; + +struct curparse { + struct mparse *mp; + enum mandoclevel wlevel; /* ignore messages below this */ + int wstop; /* stop after a file with a warning */ + enum outt outtype; /* which output to use */ + out_mdoc outmdoc; /* mdoc output ptr */ + out_man outman; /* man output ptr */ + out_free outfree; /* free output ptr */ + void *outdata; /* data for output */ + char outopts[BUFSIZ]; /* buf of output opts */ +}; + +static int moptions(enum mparset *, char *); +static void mmsg(enum mandocerr, enum mandoclevel, + const char *, int, int, const char *); +static void parse(struct curparse *, int, + const char *, enum mandoclevel *); +static int toptions(struct curparse *, char *); +static void usage(void) __attribute__((noreturn)); +static void version(void) __attribute__((noreturn)); +static int woptions(struct curparse *, char *); + +static const char *progname; + +int +main(int argc, char *argv[]) +{ + int c; + struct curparse curp; + enum mparset type; + enum mandoclevel rc; + + progname = strrchr(argv[0], '/'); + if (progname == NULL) + progname = argv[0]; + else + ++progname; + + memset(&curp, 0, sizeof(struct curparse)); + + type = MPARSE_AUTO; + curp.outtype = OUTT_ASCII; + curp.wlevel = MANDOCLEVEL_FATAL; + + /* LINTED */ + while (-1 != (c = getopt(argc, argv, "m:O:T:VW:"))) + switch (c) { + case ('m'): + if ( ! moptions(&type, optarg)) + return((int)MANDOCLEVEL_BADARG); + break; + case ('O'): + (void)strlcat(curp.outopts, optarg, BUFSIZ); + (void)strlcat(curp.outopts, ",", BUFSIZ); + break; + case ('T'): + if ( ! toptions(&curp, optarg)) + return((int)MANDOCLEVEL_BADARG); + break; + case ('W'): + if ( ! woptions(&curp, optarg)) + return((int)MANDOCLEVEL_BADARG); + break; + case ('V'): + version(); + /* NOTREACHED */ + default: + usage(); + /* NOTREACHED */ + } + + curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp); + + /* + * Conditionally start up the lookaside buffer before parsing. + */ + if (OUTT_MAN == curp.outtype) + mparse_keep(curp.mp); + + argc -= optind; + argv += optind; + + rc = MANDOCLEVEL_OK; + + if (NULL == *argv) + parse(&curp, STDIN_FILENO, "<stdin>", &rc); + + while (*argv) { + parse(&curp, -1, *argv, &rc); + if (MANDOCLEVEL_OK != rc && curp.wstop) + break; + ++argv; + } + + if (curp.outfree) + (*curp.outfree)(curp.outdata); + if (curp.mp) + mparse_free(curp.mp); + + return((int)rc); +} + +static void +version(void) +{ + + printf("%s %s\n", progname, VERSION); + exit((int)MANDOCLEVEL_OK); +} + +static void +usage(void) +{ + + fprintf(stderr, "usage: %s " + "[-V] " + "[-foption] " + "[-mformat] " + "[-Ooption] " + "[-Toutput] " + "[-Wlevel] " + "[file...]\n", + progname); + + exit((int)MANDOCLEVEL_BADARG); +} + +static void +parse(struct curparse *curp, int fd, + const char *file, enum mandoclevel *level) +{ + enum mandoclevel rc; + struct mdoc *mdoc; + struct man *man; + + /* Begin by parsing the file itself. */ + + assert(file); + assert(fd >= -1); + + rc = mparse_readfd(curp->mp, fd, file); + + /* Stop immediately if the parse has failed. */ + + if (MANDOCLEVEL_FATAL <= rc) + goto cleanup; + + /* + * With -Wstop and warnings or errors of at least the requested + * level, do not produce output. + */ + + if (MANDOCLEVEL_OK != rc && curp->wstop) + goto cleanup; + + /* If unset, allocate output dev now (if applicable). */ + + if ( ! (curp->outman && curp->outmdoc)) { + switch (curp->outtype) { + case (OUTT_XHTML): + curp->outdata = xhtml_alloc(curp->outopts); + curp->outfree = html_free; + break; + case (OUTT_HTML): + curp->outdata = html_alloc(curp->outopts); + curp->outfree = html_free; + break; + case (OUTT_UTF8): + curp->outdata = utf8_alloc(curp->outopts); + curp->outfree = ascii_free; + break; + case (OUTT_LOCALE): + curp->outdata = locale_alloc(curp->outopts); + curp->outfree = ascii_free; + break; + case (OUTT_ASCII): + curp->outdata = ascii_alloc(curp->outopts); + curp->outfree = ascii_free; + break; + case (OUTT_PDF): + curp->outdata = pdf_alloc(curp->outopts); + curp->outfree = pspdf_free; + break; + case (OUTT_PS): + curp->outdata = ps_alloc(curp->outopts); + curp->outfree = pspdf_free; + break; + default: + break; + } + + switch (curp->outtype) { + case (OUTT_HTML): + /* FALLTHROUGH */ + case (OUTT_XHTML): + curp->outman = html_man; + curp->outmdoc = html_mdoc; + break; + case (OUTT_TREE): + curp->outman = tree_man; + curp->outmdoc = tree_mdoc; + break; + case (OUTT_MAN): + curp->outmdoc = man_mdoc; + curp->outman = man_man; + break; + case (OUTT_PDF): + /* FALLTHROUGH */ + case (OUTT_ASCII): + /* FALLTHROUGH */ + case (OUTT_UTF8): + /* FALLTHROUGH */ + case (OUTT_LOCALE): + /* FALLTHROUGH */ + case (OUTT_PS): + curp->outman = terminal_man; + curp->outmdoc = terminal_mdoc; + break; + default: + break; + } + } + + mparse_result(curp->mp, &mdoc, &man); + + /* Execute the out device, if it exists. */ + + if (man && curp->outman) + (*curp->outman)(curp->outdata, man); + if (mdoc && curp->outmdoc) + (*curp->outmdoc)(curp->outdata, mdoc); + + cleanup: + + mparse_reset(curp->mp); + + if (*level < rc) + *level = rc; +} + +static int +moptions(enum mparset *tflags, char *arg) +{ + + if (0 == strcmp(arg, "doc")) + *tflags = MPARSE_MDOC; + else if (0 == strcmp(arg, "andoc")) + *tflags = MPARSE_AUTO; + else if (0 == strcmp(arg, "an")) + *tflags = MPARSE_MAN; + else { + fprintf(stderr, "%s: Bad argument\n", arg); + return(0); + } + + return(1); +} + +static int +toptions(struct curparse *curp, char *arg) +{ + + if (0 == strcmp(arg, "ascii")) + curp->outtype = OUTT_ASCII; + else if (0 == strcmp(arg, "lint")) { + curp->outtype = OUTT_LINT; + curp->wlevel = MANDOCLEVEL_WARNING; + } else if (0 == strcmp(arg, "tree")) + curp->outtype = OUTT_TREE; + else if (0 == strcmp(arg, "man")) + curp->outtype = OUTT_MAN; + else if (0 == strcmp(arg, "html")) + curp->outtype = OUTT_HTML; + else if (0 == strcmp(arg, "utf8")) + curp->outtype = OUTT_UTF8; + else if (0 == strcmp(arg, "locale")) + curp->outtype = OUTT_LOCALE; + else if (0 == strcmp(arg, "xhtml")) + curp->outtype = OUTT_XHTML; + else if (0 == strcmp(arg, "ps")) + curp->outtype = OUTT_PS; + else if (0 == strcmp(arg, "pdf")) + curp->outtype = OUTT_PDF; + else { + fprintf(stderr, "%s: Bad argument\n", arg); + return(0); + } + + return(1); +} + +static int +woptions(struct curparse *curp, char *arg) +{ + char *v, *o; + const char *toks[6]; + + toks[0] = "stop"; + toks[1] = "all"; + toks[2] = "warning"; + toks[3] = "error"; + toks[4] = "fatal"; + toks[5] = NULL; + + while (*arg) { + o = arg; + switch (getsubopt(&arg, UNCONST(toks), &v)) { + case (0): + curp->wstop = 1; + break; + case (1): + /* FALLTHROUGH */ + case (2): + curp->wlevel = MANDOCLEVEL_WARNING; + break; + case (3): + curp->wlevel = MANDOCLEVEL_ERROR; + break; + case (4): + curp->wlevel = MANDOCLEVEL_FATAL; + break; + default: + fprintf(stderr, "-W%s: Bad argument\n", o); + return(0); + } + } + + return(1); +} + +static void +mmsg(enum mandocerr t, enum mandoclevel lvl, + const char *file, int line, int col, const char *msg) +{ + + fprintf(stderr, "%s:%d:%d: %s: %s", + file, line, col + 1, + mparse_strlevel(lvl), + mparse_strerror(t)); + + if (msg) + fprintf(stderr, ": %s", msg); + + fputc('\n', stderr); +} |
