=================================================================== RCS file: /cvs/mandoc/main.c,v retrieving revision 1.159 retrieving revision 1.181 diff -u -p -r1.159 -r1.181 --- mandoc/main.c 2011/03/23 09:47:13 1.159 +++ mandoc/main.c 2014/08/20 21:04:35 1.181 @@ -1,7 +1,8 @@ -/* $Id: main.c,v 1.159 2011/03/23 09:47:13 kristaps Exp $ */ +/* $Id: main.c,v 1.181 2014/08/20 21:04:35 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2010, 2011 Ingo Schwarze + * Copyright (c) 2010, 2011, 2012, 2014 Ingo Schwarze + * Copyright (c) 2010 Joerg Sonnenberger * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,10 +16,10 @@ * 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 + #include #include #include @@ -27,9 +28,12 @@ #include #include "mandoc.h" +#include "mandoc_aux.h" #include "main.h" #include "mdoc.h" #include "man.h" +#include "manpath.h" +#include "mansearch.h" #if !defined(__GNUC__) || (__GNUC__ < 2) # if !defined(lint) @@ -37,13 +41,25 @@ # endif #endif /* !defined(__GNUC__) || (__GNUC__ < 2) */ +enum outmode { + OUTMODE_DEF = 0, + OUTMODE_FLN, + OUTMODE_LST, + OUTMODE_ALL, + OUTMODE_INT, + OUTMODE_ONE +}; + 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 */ @@ -55,151 +71,44 @@ 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 */ + enum outt outtype; /* which output to use */ out_mdoc outmdoc; /* mdoc output ptr */ - out_man outman; /* man 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 const char * const mandoclevels[MANDOCLEVEL_MAX] = { - "SUCCESS", - "RESERVED", - "WARNING", - "ERROR", - "FATAL", - "BADARG", - "SYSERR" -}; - -static const char * const mandocerrs[MANDOCERR_MAX] = { - "ok", - - "generic warning", - - /* related to the prologue */ - "no title in document", - "document title should be all caps", - "unknown manual section", - "date missing, using today's date", - "cannot parse date, using it verbatim", - "prologue macros out of order", - "duplicate prologue macro", - "macro not allowed in prologue", - "macro not allowed in body", - - /* related to document structure */ - ".so is fragile, better use ln(1)", - "NAME section must come first", - "bad NAME section contents", - "manual name not yet set", - "sections out of conventional order", - "duplicate section name", - "section not in conventional manual section", - - /* related to macros and nesting */ - "skipping obsolete macro", - "skipping paragraph macro", - "skipping no-space macro", - "blocks badly nested", - "child violates parent syntax", - "nested displays are not portable", - "already in literal mode", - "line scope broken", - - /* related to missing macro arguments */ - "skipping empty macro", - "argument count wrong", - "missing display type", - "list type must come first", - "tag lists require a width argument", - "missing font type", - "skipping end of block that is not open", - - /* related to bad macro arguments */ - "skipping argument", - "duplicate argument", - "duplicate display type", - "duplicate list type", - "unknown AT&T UNIX version", - "bad Boolean value", - "unknown font", - "unknown standard specifier", - "bad width argument", - - /* related to plain text */ - "blank line in non-literal context", - "tab in non-literal context", - "end of line whitespace", - "bad comment style", - "unknown escape sequence", - "unterminated quoted string", - - "generic error", - - /* related to tables */ - "bad table syntax", - "bad table option", - "bad table layout", - "no table layout cells specified", - "no table data cells specified", - "ignore data in cell", - "data block still open", - "ignoring extra data cells", - - "input stack limit exceeded, infinite loop?", - "skipping bad character", - "escaped character not allowed in a name", - "skipping text before the first section header", - "skipping unknown macro", - "NOT IMPLEMENTED, please use groff: skipping request", - "argument count wrong", - "skipping end of block that is not open", - "missing end of block", - "scope open on exit", - "uname(3) system call failed", - "macro requires line argument(s)", - "macro requires body argument(s)", - "macro requires argument(s)", - "missing list type", - "line argument(s) will be lost", - "body argument(s) will be lost", - - "generic fatal error", - - "not a manual", - "column syntax is inconsistent", - "NOT IMPLEMENTED: .Bd -file", - "line scope broken, syntax violated", - "argument count wrong, violates syntax", - "child violates parent syntax", - "argument count wrong, violates syntax", - "NOT IMPLEMENTED: .so with absolute path or \"..\"", - "no document body", - "no document prologue", - "static buffer exhausted", -}; - -static int moptions(enum mparset *, char *); +static int moptions(int *, char *); static void mmsg(enum mandocerr, enum mandoclevel, const char *, int, int, const char *); -static void parse(struct curparse *, int, +static void parse(struct curparse *, int, const char *, enum mandoclevel *); static int toptions(struct curparse *, char *); -static void usage(void) __attribute__((noreturn)); +static void usage(enum argmode) __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; + struct mansearch search; + struct manpaths paths; + char *conf_file, *defpaths, *auxpaths; + char *defos; +#if HAVE_SQLITE3 + struct manpage *res; + size_t i, sz; +#endif enum mandoclevel rc; + enum outmode outmode; + int show_usage; + int options; + int c; progname = strrchr(argv[0], '/'); if (progname == NULL) @@ -207,44 +116,164 @@ main(int argc, char *argv[]) else ++progname; - memset(&curp, 0, sizeof(struct curparse)); + /* Search options. */ - type = MPARSE_AUTO; + memset(&paths, 0, sizeof(struct manpaths)); + conf_file = defpaths = auxpaths = NULL; + + memset(&search, 0, sizeof(struct mansearch)); + search.outkey = "Nd"; + + if (strcmp(progname, "man") == 0) + search.argmode = ARG_NAME; + else if (strncmp(progname, "apropos", 7) == 0) + search.argmode = ARG_EXPR; + else if (strncmp(progname, "whatis", 6) == 0) + search.argmode = ARG_WORD; + else + search.argmode = ARG_FILE; + + /* Parser and formatter options. */ + + memset(&curp, 0, sizeof(struct curparse)); curp.outtype = OUTT_ASCII; curp.wlevel = MANDOCLEVEL_FATAL; + options = MPARSE_SO; + defos = NULL; - /* LINTED */ - while (-1 != (c = getopt(argc, argv, "m:O:T:VW:"))) + show_usage = 0; + outmode = OUTMODE_DEF; + while (-1 != (c = getopt(argc, argv, "aC:fI:ikM:m:O:S:s:T:VW:w"))) { switch (c) { - case ('m'): - if ( ! moptions(&type, optarg)) + case 'a': + outmode = OUTMODE_ALL; + break; + case 'C': + conf_file = optarg; + break; + case 'f': + search.argmode = ARG_WORD; + break; + case 'I': + if (strncmp(optarg, "os=", 3)) { + fprintf(stderr, + "%s: -I%s: Bad argument\n", + progname, optarg); return((int)MANDOCLEVEL_BADARG); + } + if (defos) { + fprintf(stderr, + "%s: -I%s: Duplicate argument\n", + progname, optarg); + return((int)MANDOCLEVEL_BADARG); + } + defos = mandoc_strdup(optarg + 3); break; - case ('O'): + case 'i': + outmode = OUTMODE_INT; + break; + case 'k': + search.argmode = ARG_EXPR; + break; + case 'M': + defpaths = optarg; + break; + case 'm': + auxpaths = optarg; + break; + case 'O': + search.outkey = optarg; (void)strlcat(curp.outopts, optarg, BUFSIZ); (void)strlcat(curp.outopts, ",", BUFSIZ); break; - case ('T'): + case 'S': + search.arch = optarg; + break; + case 's': + search.sec = optarg; + break; + case 'T': if ( ! toptions(&curp, optarg)) return((int)MANDOCLEVEL_BADARG); break; - case ('W'): + case 'W': if ( ! woptions(&curp, optarg)) return((int)MANDOCLEVEL_BADARG); break; - case ('V'): + case 'w': + outmode = OUTMODE_FLN; + break; + case 'V': version(); /* NOTREACHED */ default: - usage(); - /* NOTREACHED */ + show_usage = 1; + break; } + } - curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp); + if (show_usage) + usage(search.argmode); + if (outmode == OUTMODE_DEF) { + switch (search.argmode) { + case ARG_FILE: + outmode = OUTMODE_ALL; + break; + case ARG_NAME: + outmode = OUTMODE_ONE; + break; + default: + outmode = OUTMODE_LST; + break; + } + } + argc -= optind; argv += optind; + /* man(1), whatis(1), apropos(1) */ + + if (search.argmode != ARG_FILE) { +#if HAVE_SQLITE3 + if (argc == 0) + usage(search.argmode); + manpath_parse(&paths, conf_file, defpaths, auxpaths); + mansearch_setup(1); + if( ! mansearch(&search, &paths, argc, argv, &res, &sz)) + usage(search.argmode); + manpath_free(&paths); + for (i = 0; i < sz; i++) { + if (outmode == OUTMODE_FLN) + puts(res[i].file); + else + printf("%s - %s\n", res[i].names, + res[i].output == NULL ? "" : + res[i].output); + } + mansearch_free(res, sz); + mansearch_setup(0); + return((int)MANDOCLEVEL_OK); +#else + fputs("mandoc: database support not compiled in\n", + stderr); + return((int)MANDOCLEVEL_BADARG); +#endif + } + + /* mandoc(1) */ + + if ( ! moptions(&options, auxpaths)) + return((int)MANDOCLEVEL_BADARG); + + curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos); + + /* + * Conditionally start up the lookaside buffer before parsing. + */ + if (OUTT_MAN == curp.outtype) + mparse_keep(curp.mp); + rc = MANDOCLEVEL_OK; if (NULL == *argv) @@ -261,6 +290,7 @@ main(int argc, char *argv[]) (*curp.outfree)(curp.outdata); if (curp.mp) mparse_free(curp.mp); + free(defos); return((int)rc); } @@ -269,30 +299,41 @@ static void version(void) { - printf("%s %s\n", progname, VERSION); + printf("mandoc %s\n", VERSION); exit((int)MANDOCLEVEL_OK); } static void -usage(void) +usage(enum argmode argmode) { - fprintf(stderr, "usage: %s " - "[-V] " - "[-foption] " - "[-mformat] " - "[-Ooption] " - "[-Toutput] " - "[-Werr] " - "[file...]\n", - progname); - + switch (argmode) { + case ARG_FILE: + fputs("usage: mandoc [-V] [-Ios=name] [-mformat]" + " [-Ooption] [-Toutput] [-Wlevel]\n" + "\t [file ...]\n", stderr); + break; + case ARG_NAME: + fputs("usage: man [-acfhkVw] [-C file] " + "[-M path] [-m path] [-S arch] [-s section]\n" + "\t [section] name ...\n", stderr); + break; + case ARG_WORD: + fputs("usage: whatis [-V] [-C file] [-M path] [-m path] " + "[-S arch] [-s section] name ...\n", stderr); + break; + case ARG_EXPR: + fputs("usage: apropos [-V] [-C file] [-M path] [-m path] " + "[-O outkey] [-S arch]\n" + "\t [-s section] expression ...\n", stderr); + break; + } exit((int)MANDOCLEVEL_BADARG); } static void -parse(struct curparse *curp, int fd, - const char *file, enum mandoclevel *level) +parse(struct curparse *curp, int fd, const char *file, + enum mandoclevel *level) { enum mandoclevel rc; struct mdoc *mdoc; @@ -322,21 +363,31 @@ parse(struct curparse *curp, int fd, if ( ! (curp->outman && curp->outmdoc)) { switch (curp->outtype) { - case (OUTT_XHTML): + case OUTT_XHTML: curp->outdata = xhtml_alloc(curp->outopts); + curp->outfree = html_free; break; - case (OUTT_HTML): + case OUTT_HTML: curp->outdata = html_alloc(curp->outopts); + curp->outfree = html_free; break; - case (OUTT_ASCII): + 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): + case OUTT_PDF: curp->outdata = pdf_alloc(curp->outopts); curp->outfree = pspdf_free; break; - case (OUTT_PS): + case OUTT_PS: curp->outdata = ps_alloc(curp->outopts); curp->outfree = pspdf_free; break; @@ -345,22 +396,29 @@ parse(struct curparse *curp, int fd, } switch (curp->outtype) { - case (OUTT_HTML): + case OUTT_HTML: /* FALLTHROUGH */ - case (OUTT_XHTML): + case OUTT_XHTML: curp->outman = html_man; curp->outmdoc = html_mdoc; - curp->outfree = html_free; break; - case (OUTT_TREE): + case OUTT_TREE: curp->outman = tree_man; curp->outmdoc = tree_mdoc; break; - case (OUTT_PDF): + case OUTT_MAN: + curp->outmdoc = man_mdoc; + curp->outman = man_man; + break; + case OUTT_PDF: /* FALLTHROUGH */ - case (OUTT_ASCII): + case OUTT_ASCII: /* FALLTHROUGH */ - case (OUTT_PS): + case OUTT_UTF8: + /* FALLTHROUGH */ + case OUTT_LOCALE: + /* FALLTHROUGH */ + case OUTT_PS: curp->outman = terminal_man; curp->outmdoc = terminal_mdoc; break; @@ -369,7 +427,7 @@ parse(struct curparse *curp, int fd, } } - mparse_result(curp->mp, &mdoc, &man); + mparse_result(curp->mp, &mdoc, &man, NULL); /* Execute the out device, if it exists. */ @@ -387,17 +445,20 @@ parse(struct curparse *curp, int fd, } static int -moptions(enum mparset *tflags, char *arg) +moptions(int *options, char *arg) { - if (0 == strcmp(arg, "doc")) - *tflags = MPARSE_MDOC; + if (arg == NULL) + /* nothing to do */; + else if (0 == strcmp(arg, "doc")) + *options |= MPARSE_MDOC; else if (0 == strcmp(arg, "andoc")) - *tflags = MPARSE_AUTO; + /* nothing to do */; else if (0 == strcmp(arg, "an")) - *tflags = MPARSE_MAN; + *options |= MPARSE_MAN; else { - fprintf(stderr, "%s: Bad argument\n", arg); + fprintf(stderr, "%s: -m%s: Bad argument\n", + progname, arg); return(0); } @@ -415,8 +476,14 @@ toptions(struct curparse *curp, char *arg) 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")) @@ -424,7 +491,8 @@ toptions(struct curparse *curp, char *arg) else if (0 == strcmp(arg, "pdf")) curp->outtype = OUTT_PDF; else { - fprintf(stderr, "%s: Bad argument\n", arg); + fprintf(stderr, "%s: -T%s: Bad argument\n", + progname, arg); return(0); } @@ -435,7 +503,7 @@ static int woptions(struct curparse *curp, char *arg) { char *v, *o; - const char *toks[6]; + const char *toks[6]; toks[0] = "stop"; toks[1] = "all"; @@ -447,22 +515,23 @@ woptions(struct curparse *curp, char *arg) while (*arg) { o = arg; switch (getsubopt(&arg, UNCONST(toks), &v)) { - case (0): + case 0: curp->wstop = 1; break; - case (1): + case 1: /* FALLTHROUGH */ - case (2): + case 2: curp->wlevel = MANDOCLEVEL_WARNING; break; - case (3): + case 3: curp->wlevel = MANDOCLEVEL_ERROR; break; - case (4): + case 4: curp->wlevel = MANDOCLEVEL_FATAL; break; default: - fprintf(stderr, "-W%s: Bad argument\n", o); + fprintf(stderr, "%s: -W%s: Bad argument\n", + progname, o); return(0); } } @@ -471,13 +540,20 @@ woptions(struct curparse *curp, char *arg) } static void -mmsg(enum mandocerr t, enum mandoclevel lvl, +mmsg(enum mandocerr t, enum mandoclevel lvl, const char *file, int line, int col, const char *msg) { + const char *mparse_msg; - fprintf(stderr, "%s:%d:%d: %s: %s", - file, line, col + 1, - mandoclevels[lvl], mandocerrs[t]); + fprintf(stderr, "%s: %s:", progname, file); + + if (line) + fprintf(stderr, "%d:%d:", line, col + 1); + + fprintf(stderr, " %s", mparse_strlevel(lvl)); + + if (NULL != (mparse_msg = mparse_strerror(t))) + fprintf(stderr, ": %s", mparse_msg); if (msg) fprintf(stderr, ": %s", msg);