-/* $Id: main.c,v 1.154 2011/03/20 11:41:24 kristaps Exp $ */
+/* $Id: main.c,v 1.177 2014/06/21 22:24:01 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include <unistd.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "main.h"
#include "mdoc.h"
#include "man.h"
-#include "roff.h"
#if !defined(__GNUC__) || (__GNUC__ < 2)
# if !defined(lint)
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 */
struct curparse {
struct mparse *mp;
- const char *file; /* current file-name */
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 enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
- MANDOCERR_OK,
- MANDOCERR_WARNING,
- MANDOCERR_WARNING,
- MANDOCERR_ERROR,
- MANDOCERR_FATAL,
- MANDOCERR_MAX,
- MANDOCERR_MAX
-};
-
-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",
-
- /* 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",
- "line scope broken",
- "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",
-
- "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 void evt_close(void *, const char *);
-static int evt_open(void *, const char *);
-static int moptions(enum mparset *, char *);
-static void mmsg(enum mandocerr, void *,
- int, int, const char *);
-static void parse(struct curparse *, int,
+static int moptions(int *, 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 const char *progname;
+
int
main(int argc, char *argv[])
{
int c;
struct curparse curp;
- enum mparset type;
+ int options;
enum mandoclevel rc;
+ char *defos;
progname = strrchr(argv[0], '/');
if (progname == NULL)
memset(&curp, 0, sizeof(struct curparse));
- type = MPARSE_AUTO;
+ options = MPARSE_SO;
curp.outtype = OUTT_ASCII;
curp.wlevel = MANDOCLEVEL_FATAL;
+ defos = NULL;
- /* LINTED */
- while (-1 != (c = getopt(argc, argv, "m:O:T:VW:")))
+ while (-1 != (c = getopt(argc, argv, "I:m:O:T:VW:")))
switch (c) {
- case ('m'):
- if ( ! moptions(&type, optarg))
+ 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 'm':
+ if ( ! moptions(&options, optarg))
return((int)MANDOCLEVEL_BADARG);
break;
- case ('O'):
+ case 'O':
(void)strlcat(curp.outopts, optarg, BUFSIZ);
(void)strlcat(curp.outopts, ",", BUFSIZ);
break;
- case ('T'):
+ 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 'V':
version();
/* NOTREACHED */
default:
/* NOTREACHED */
}
- curp.mp = mparse_alloc(type, evt_open, evt_close, mmsg, &curp);
+ 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);
argc -= optind;
argv += optind;
(*curp.outfree)(curp.outdata);
if (curp.mp)
mparse_free(curp.mp);
+ free(defos);
return((int)rc);
}
fprintf(stderr, "usage: %s "
"[-V] "
- "[-foption] "
+ "[-Ios=name] "
"[-mformat] "
"[-Ooption] "
"[-Toutput] "
- "[-Werr] "
- "[file...]\n",
+ "[-Wlevel]\n"
+ "\t [file ...]\n",
progname);
exit((int)MANDOCLEVEL_BADARG);
}
-static int
-evt_open(void *arg, const char *file)
-{
-
- evt_close(arg, file);
- return(1);
-}
-
static void
-evt_close(void *arg, const char *file)
-{
- struct curparse *p;
-
- p = (struct curparse *)arg;
- p->file = file;
-}
-
-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;
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_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):
+ 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;
}
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;
}
}
- mparse_result(curp->mp, &mdoc, &man);
+ mparse_result(curp->mp, &mdoc, &man, NULL);
/* Execute the out device, if it exists. */
}
static int
-moptions(enum mparset *tflags, char *arg)
+moptions(int *options, char *arg)
{
if (0 == strcmp(arg, "doc"))
- *tflags = MPARSE_MDOC;
+ *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);
}
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"))
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);
}
woptions(struct curparse *curp, char *arg)
{
char *v, *o;
- const char *toks[6];
+ const char *toks[6];
toks[0] = "stop";
toks[1] = "all";
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);
}
}
}
static void
-mmsg(enum mandocerr t, void *arg, int ln, int col, const char *msg)
+mmsg(enum mandocerr t, enum mandoclevel lvl,
+ const char *file, int line, int col, const char *msg)
{
- struct curparse *cp;
- enum mandoclevel level;
+ const char *mparse_msg;
- level = MANDOCLEVEL_FATAL;
- while (t < mandoclimits[level])
- /* LINTED */
- level--;
+ fprintf(stderr, "%s: %s:", progname, file);
- cp = (struct curparse *)arg;
- if (level < cp->wlevel)
- return;
+ if (line)
+ fprintf(stderr, "%d:%d:", line, col + 1);
- fprintf(stderr, "%s:%d:%d: %s: %s", cp->file, ln, col + 1,
- mandoclevels[level], mandocerrs[t]);
+ fprintf(stderr, " %s", mparse_strlevel(lvl));
+
+ if (NULL != (mparse_msg = mparse_strerror(t)))
+ fprintf(stderr, ": %s", mparse_msg);
if (msg)
fprintf(stderr, ": %s", msg);
fputc('\n', stderr);
-
- mparse_setstatus(cp->mp, level);
}