diff options
-rw-r--r-- | chars.c | 4 | ||||
-rw-r--r-- | html.c | 4 | ||||
-rw-r--r-- | libman.h | 1 | ||||
-rw-r--r-- | libmdoc.h | 1 | ||||
-rw-r--r-- | main.c | 365 | ||||
-rw-r--r-- | man.3 | 7 | ||||
-rw-r--r-- | man.c | 32 | ||||
-rw-r--r-- | man.h | 5 | ||||
-rw-r--r-- | man_validate.c | 8 | ||||
-rw-r--r-- | mandoc.1 | 200 | ||||
-rw-r--r-- | mandoc.c | 8 | ||||
-rw-r--r-- | mandoc.h | 13 | ||||
-rw-r--r-- | mdoc.3 | 7 | ||||
-rw-r--r-- | mdoc.c | 35 | ||||
-rw-r--r-- | mdoc.h | 6 | ||||
-rw-r--r-- | mdoc_html.c | 2 | ||||
-rw-r--r-- | mdoc_validate.c | 8 | ||||
-rw-r--r-- | roff.3 | 6 | ||||
-rw-r--r-- | roff.c | 32 | ||||
-rw-r--r-- | roff.h | 2 | ||||
-rw-r--r-- | term.c | 4 | ||||
-rw-r--r-- | term_ps.c | 5 |
22 files changed, 334 insertions, 421 deletions
@@ -94,13 +94,13 @@ chars_init(enum chars type) tab = malloc(sizeof(struct tbl)); if (NULL == tab) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } htab = calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln **)); if (NULL == htab) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } for (i = 0; i < LINES_MAX; i++) { @@ -116,7 +116,7 @@ ml_alloc(char *outopts, enum htmltype type) h = calloc(1, sizeof(struct html)); if (NULL == h) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } h->type = type; @@ -398,7 +398,7 @@ print_otag(struct html *h, enum htmltag tag, t = malloc(sizeof(struct tag)); if (NULL == t) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } t->tag = tag; t->next = h->tags.head; @@ -27,7 +27,6 @@ enum man_next { struct man { void *data; /* private application data */ mandocmsg msg; /* output message handler */ - int pflags; /* parse flags (see man.h) */ int flags; /* parse flags */ #define MAN_HALT (1 << 0) /* badness happened: die */ #define MAN_ELINE (1 << 1) /* Next-line element scope. */ @@ -36,7 +36,6 @@ struct mdoc { #define MDOC_PPHRASE (1 << 5) /* within a partial phrase */ #define MDOC_FREECOL (1 << 6) /* `It' invocation should close */ #define MDOC_SYNOPSIS (1 << 7) /* SYNOPSIS-style formatting */ - int pflags; enum mdoc_next next; /* where to put the next node */ struct mdoc_node *last; /* the last node parsed */ struct mdoc_node *first; /* the first node parsed */ @@ -79,17 +79,8 @@ enum outt { struct curparse { const char *file; /* Current parse. */ int fd; /* Current parse. */ - int wflags; - /* FIXME: set by max error */ -#define WARN_WALL (1 << 0) /* All-warnings mask. */ -#define WARN_WERR (1 << 2) /* Warnings->errors. */ - int fflags; -#define FL_IGN_SCOPE (1 << 0) /* Ignore scope errors. */ -#define FL_NIGN_ESCAPE (1 << 1) /* Don't ignore bad escapes. */ -#define FL_NIGN_MACRO (1 << 2) /* Don't ignore bad macros. */ -#define FL_IGN_ERRORS (1 << 4) /* Ignore failed parse. */ -#define FL_STRICT FL_NIGN_ESCAPE | \ - FL_NIGN_MACRO /* ignore nothing */ + enum mandoclevel wlevel; /* Ignore messages below this. */ + int wstop; /* Stop after a file with a warning. */ enum intt inttype; /* which parser to use */ struct man *man; /* man parser */ struct mdoc *mdoc; /* mdoc parser */ @@ -103,6 +94,26 @@ struct curparse { 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", @@ -179,28 +190,23 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "no document body", "no document prologue", "utsname system call failed", - "memory exhausted", + "static buffer exhausted", }; static void fdesc(struct curparse *); static void ffile(const char *, struct curparse *); -static int foptions(int *, char *); -static struct man *man_init(struct curparse *); -static struct mdoc *mdoc_init(struct curparse *); -static struct roff *roff_init(struct curparse *); static int moptions(enum intt *, char *); static int mmsg(enum mandocerr, void *, int, int, const char *); -static int pset(const char *, int, struct curparse *, +static void pset(const char *, int, struct curparse *, struct man **, struct mdoc **); static int toptions(struct curparse *, char *); static void usage(void) __attribute__((noreturn)); static void version(void) __attribute__((noreturn)); -static int woptions(int *, char *); +static int woptions(struct curparse *, char *); static const char *progname; -static int with_fatal; -static int with_error; +static enum mandoclevel exit_status = MANDOCLEVEL_OK; int main(int argc, char *argv[]) @@ -218,17 +224,14 @@ main(int argc, char *argv[]) curp.inttype = INTT_AUTO; curp.outtype = OUTT_ASCII; + curp.wlevel = MANDOCLEVEL_FATAL; /* LINTED */ - while (-1 != (c = getopt(argc, argv, "f:m:O:T:VW:"))) + while (-1 != (c = getopt(argc, argv, "m:O:T:VW:"))) switch (c) { - case ('f'): - if ( ! foptions(&curp.fflags, optarg)) - return(EXIT_FAILURE); - break; case ('m'): if ( ! moptions(&curp.inttype, optarg)) - return(EXIT_FAILURE); + return(MANDOCLEVEL_BADARG); break; case ('O'): (void)strlcat(curp.outopts, optarg, BUFSIZ); @@ -236,11 +239,11 @@ main(int argc, char *argv[]) break; case ('T'): if ( ! toptions(&curp, optarg)) - return(EXIT_FAILURE); + return(MANDOCLEVEL_BADARG); break; case ('W'): - if ( ! woptions(&curp.wflags, optarg)) - return(EXIT_FAILURE); + if ( ! woptions(&curp, optarg)) + return(MANDOCLEVEL_BADARG); break; case ('V'): version(); @@ -262,8 +265,7 @@ main(int argc, char *argv[]) while (*argv) { ffile(*argv, &curp); - - if (with_fatal && !(curp.fflags & FL_IGN_ERRORS)) + if (MANDOCLEVEL_OK != exit_status && curp.wstop) break; ++argv; } @@ -277,8 +279,7 @@ main(int argc, char *argv[]) if (curp.roff) roff_free(curp.roff); - return((with_fatal || with_error) ? - EXIT_FAILURE : EXIT_SUCCESS); + return(exit_status); } @@ -287,7 +288,7 @@ version(void) { (void)printf("%s %s\n", progname, VERSION); - exit(EXIT_SUCCESS); + exit(MANDOCLEVEL_OK); } @@ -298,53 +299,7 @@ usage(void) (void)fprintf(stderr, "usage: %s [-V] [-foption] " "[-mformat] [-Ooption] [-Toutput] " "[-Werr] [file...]\n", progname); - exit(EXIT_FAILURE); -} - - -static struct man * -man_init(struct curparse *curp) -{ - int pflags; - - /* Defaults from mandoc.1. */ - - pflags = MAN_IGN_MACRO | MAN_IGN_ESCAPE; - - if (curp->fflags & FL_NIGN_MACRO) - pflags &= ~MAN_IGN_MACRO; - if (curp->fflags & FL_NIGN_ESCAPE) - pflags &= ~MAN_IGN_ESCAPE; - - return(man_alloc(&curp->regs, curp, pflags, mmsg)); -} - - -static struct roff * -roff_init(struct curparse *curp) -{ - - return(roff_alloc(&curp->regs, mmsg, curp)); -} - - -static struct mdoc * -mdoc_init(struct curparse *curp) -{ - int pflags; - - /* Defaults from mandoc.1. */ - - pflags = MDOC_IGN_MACRO | MDOC_IGN_ESCAPE; - - if (curp->fflags & FL_IGN_SCOPE) - pflags |= MDOC_IGN_SCOPE; - if (curp->fflags & FL_NIGN_ESCAPE) - pflags &= ~MDOC_IGN_ESCAPE; - if (curp->fflags & FL_NIGN_MACRO) - pflags &= ~MDOC_IGN_MACRO; - - return(mdoc_alloc(&curp->regs, curp, pflags, mmsg)); + exit(MANDOCLEVEL_BADARG); } @@ -355,7 +310,7 @@ ffile(const char *file, struct curparse *curp) curp->file = file; if (-1 == (curp->fd = open(curp->file, O_RDONLY, 0))) { perror(curp->file); - with_fatal = 1; + exit_status = MANDOCLEVEL_SYSERR; return; } @@ -366,24 +321,16 @@ ffile(const char *file, struct curparse *curp) } -static int +static void resize_buf(struct buf *buf, size_t initial) { - void *tmp; - size_t sz; - if (buf->sz == 0) - sz = initial; - else - sz = 2 * buf->sz; - tmp = realloc(buf->buf, sz); - if (NULL == tmp) { + buf->sz = buf->sz ? 2 * buf->sz : initial; + buf->buf = realloc(buf->buf, buf->sz); + if (NULL == buf->buf) { perror(NULL); - return(0); + exit(MANDOCLEVEL_SYSERR); } - buf->buf = tmp; - buf->sz = sz; - return(1); } @@ -396,7 +343,6 @@ read_whole_file(struct curparse *curp, struct buf *fb, int *with_mmap) if (-1 == fstat(curp->fd, &st)) { perror(curp->file); - with_fatal = 1; return(0); } @@ -411,7 +357,6 @@ read_whole_file(struct curparse *curp, struct buf *fb, int *with_mmap) if (st.st_size >= (1U << 31)) { fprintf(stderr, "%s: input too large\n", curp->file); - with_fatal = 1; return(0); } *with_mmap = 1; @@ -438,8 +383,7 @@ read_whole_file(struct curparse *curp, struct buf *fb, int *with_mmap) curp->file); break; } - if (! resize_buf(fb, 65536)) - break; + resize_buf(fb, 65536); } ssz = read(curp->fd, fb->buf + (int)off, fb->sz - off); if (ssz == 0) { @@ -455,7 +399,6 @@ read_whole_file(struct curparse *curp, struct buf *fb, int *with_mmap) free(fb->buf); fb->buf = NULL; - with_fatal = 1; return(0); } @@ -482,13 +425,15 @@ fdesc(struct curparse *curp) * memory mapped. ln is a line buffer and grows on-demand. */ - if ( ! read_whole_file(curp, &blk, &with_mmap)) + if ( ! read_whole_file(curp, &blk, &with_mmap)) { + exit_status = MANDOCLEVEL_SYSERR; return; + } if (NULL == curp->roff) - curp->roff = roff_init(curp); - if (NULL == (roff = curp->roff)) - goto bailout; + curp->roff = roff_alloc(&curp->regs, curp, mmsg); + assert(curp->roff); + roff = curp->roff; for (i = 0, lnn = 1; i < (int)blk.sz;) { pos = 0; @@ -511,10 +456,8 @@ fdesc(struct curparse *curp) c = (unsigned char) blk.buf[i]; if ( ! (isascii(c) && (isgraph(c) || isblank(c)))) { - if ( ! mmsg(MANDOCERR_BADCHAR, curp, - lnn_start, pos, - "ignoring byte")) - goto bailout; + mmsg(MANDOCERR_BADCHAR, curp, + lnn_start, pos, "ignoring byte"); i++; continue; } @@ -522,8 +465,7 @@ fdesc(struct curparse *curp) /* Trailing backslash is like a plain character. */ if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) { if (pos >= (int)ln.sz) - if (! resize_buf(&ln, 256)) - goto bailout; + resize_buf(&ln, 256); ln.buf[pos++] = blk.buf[i++]; continue; } @@ -555,16 +497,14 @@ fdesc(struct curparse *curp) } /* Some other escape sequence, copy and continue. */ if (pos + 1 >= (int)ln.sz) - if (! resize_buf(&ln, 256)) - goto bailout; + resize_buf(&ln, 256); ln.buf[pos++] = blk.buf[i++]; ln.buf[pos++] = blk.buf[i++]; } if (pos >= (int)ln.sz) - if (! resize_buf(&ln, 256)) - goto bailout; + resize_buf(&ln, 256); ln.buf[pos] = '\0'; /* @@ -582,10 +522,12 @@ fdesc(struct curparse *curp) &ln.buf, &ln.sz, of, &of); } while (ROFF_RERUN == re); - if (ROFF_IGN == re) + if (ROFF_IGN == re) { continue; - else if (ROFF_ERR == re) - goto bailout; + } else if (ROFF_ERR == re) { + assert(MANDOCLEVEL_FATAL <= exit_status); + goto cleanup; + } /* * If input parsers have not been allocated, do so now. @@ -595,32 +537,50 @@ fdesc(struct curparse *curp) */ if ( ! (man || mdoc)) - if ( ! pset(ln.buf + of, pos - of, curp, &man, &mdoc)) - goto bailout; + pset(ln.buf + of, pos - of, curp, &man, &mdoc); /* Lastly, push down into the parsers themselves. */ - if (man && ! man_parseln(man, lnn_start, ln.buf, of)) - goto bailout; - if (mdoc && ! mdoc_parseln(mdoc, lnn_start, ln.buf, of)) - goto bailout; + if (man && ! man_parseln(man, lnn_start, ln.buf, of)) { + assert(MANDOCLEVEL_FATAL <= exit_status); + goto cleanup; + } + if (mdoc && ! mdoc_parseln(mdoc, lnn_start, ln.buf, of)) { + assert(MANDOCLEVEL_FATAL <= exit_status); + goto cleanup; + } } + /* + * With -Wstop and warnings or errors of at least + * the requested level, do not produce output. + */ + + if (MANDOCLEVEL_OK != exit_status && curp->wstop) + goto cleanup; + /* NOTE a parser may not have been assigned, yet. */ if ( ! (man || mdoc)) { fprintf(stderr, "%s: Not a manual\n", curp->file); - goto bailout; + exit_status = MANDOCLEVEL_FATAL; + goto cleanup; } /* Clean up the parse routine ASTs. */ - if (mdoc && ! mdoc_endparse(mdoc)) - goto bailout; - if (man && ! man_endparse(man)) - goto bailout; - if (roff && ! roff_endparse(roff)) - goto bailout; + if (mdoc && ! mdoc_endparse(mdoc)) { + assert(MANDOCLEVEL_FATAL <= exit_status); + goto cleanup; + } + if (man && ! man_endparse(man)) { + assert(MANDOCLEVEL_FATAL <= exit_status); + goto cleanup; + } + if (roff && ! roff_endparse(roff)) { + assert(MANDOCLEVEL_FATAL <= exit_status); + goto cleanup; + } /* If unset, allocate output dev now (if applicable). */ @@ -696,14 +656,10 @@ fdesc(struct curparse *curp) free(blk.buf); return; - - bailout: - with_fatal = 1; - goto cleanup; } -static int +static void pset(const char *buf, int pos, struct curparse *curp, struct man **man, struct mdoc **mdoc) { @@ -721,40 +677,39 @@ pset(const char *buf, int pos, struct curparse *curp, for (i = 1; buf[i]; i++) if (' ' != buf[i] && '\t' != buf[i]) break; - if (0 == buf[i]) - return(1); + if ('\0' == buf[i]) + return; } switch (curp->inttype) { case (INTT_MDOC): if (NULL == curp->mdoc) - curp->mdoc = mdoc_init(curp); - if (NULL == (*mdoc = curp->mdoc)) - return(0); - return(1); + curp->mdoc = mdoc_alloc(&curp->regs, curp, mmsg); + assert(curp->mdoc); + *mdoc = curp->mdoc; + return; case (INTT_MAN): if (NULL == curp->man) - curp->man = man_init(curp); - if (NULL == (*man = curp->man)) - return(0); - return(1); + curp->man = man_alloc(&curp->regs, curp, mmsg); + assert(curp->man); + *man = curp->man; + return; default: break; } if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) { if (NULL == curp->mdoc) - curp->mdoc = mdoc_init(curp); - if (NULL == (*mdoc = curp->mdoc)) - return(0); - return(1); + curp->mdoc = mdoc_alloc(&curp->regs, curp, mmsg); + assert(curp->mdoc); + *mdoc = curp->mdoc; + return; } if (NULL == curp->man) - curp->man = man_init(curp); - if (NULL == (*man = curp->man)) - return(0); - return(1); + curp->man = man_alloc(&curp->regs, curp, mmsg); + assert(curp->man); + *man = curp->man; } @@ -785,8 +740,7 @@ toptions(struct curparse *curp, char *arg) curp->outtype = OUTT_ASCII; else if (0 == strcmp(arg, "lint")) { curp->outtype = OUTT_LINT; - curp->wflags |= WARN_WALL; - curp->fflags |= FL_STRICT; + curp->wlevel = MANDOCLEVEL_WARNING; } else if (0 == strcmp(arg, "tree")) curp->outtype = OUTT_TREE; @@ -808,71 +762,37 @@ toptions(struct curparse *curp, char *arg) static int -foptions(int *fflags, char *arg) +woptions(struct curparse *curp, char *arg) { char *v, *o; - const char *toks[8]; + const char *toks[6]; - toks[0] = "ign-scope"; - toks[1] = "no-ign-escape"; - toks[2] = "no-ign-macro"; - toks[3] = "ign-errors"; - toks[4] = "strict"; - toks[5] = "ign-escape"; - toks[6] = NULL; + 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): - *fflags |= FL_IGN_SCOPE; + curp->wstop = 1; break; case (1): - *fflags |= FL_NIGN_ESCAPE; - break; + /* FALLTHROUGH */ case (2): - *fflags |= FL_NIGN_MACRO; + curp->wlevel = MANDOCLEVEL_WARNING; break; case (3): - *fflags |= FL_IGN_ERRORS; + curp->wlevel = MANDOCLEVEL_ERROR; break; case (4): - *fflags |= FL_STRICT; - break; - case (5): - *fflags &= ~FL_NIGN_ESCAPE; - break; - default: - fprintf(stderr, "%s: Bad argument\n", o); - return(0); - } - } - - return(1); -} - - -static int -woptions(int *wflags, char *arg) -{ - char *v, *o; - const char *toks[3]; - - toks[0] = "all"; - toks[1] = "error"; - toks[2] = NULL; - - while (*arg) { - o = arg; - switch (getsubopt(&arg, UNCONST(toks), &v)) { - case (0): - *wflags |= WARN_WALL; - break; - case (1): - *wflags |= WARN_WERR; + curp->wlevel = MANDOCLEVEL_FATAL; break; default: - fprintf(stderr, "%s: Bad argument\n", o); + fprintf(stderr, "-W%s: Bad argument\n", o); return(0); } } @@ -885,37 +805,24 @@ static int mmsg(enum mandocerr t, void *arg, int ln, int col, const char *msg) { struct curparse *cp; - const char *level; - int rc; + enum mandoclevel level; + + level = MANDOCLEVEL_FATAL; + while (t < mandoclimits[level]) + level--; cp = (struct curparse *)arg; - level = NULL; - rc = 1; - - if (t >= MANDOCERR_FATAL) { - with_fatal = 1; - level = "FATAL"; - rc = 0; - } else { - if ( ! (WARN_WALL & cp->wflags)) - return(1); - if (t >= MANDOCERR_ERROR) { - with_error = 1; - level = "ERROR"; - } - if (WARN_WERR & cp->wflags) { - with_fatal = 1; - rc = 0; - } - } + if (level < cp->wlevel) + return(1); - fprintf(stderr, "%s:%d:%d:", cp->file, ln, col + 1); - if (level) - fprintf(stderr, " %s:", level); - fprintf(stderr, " %s", mandocerrs[t]); + fprintf(stderr, "%s:%d:%d: %s: %s", + cp->file, ln, col + 1, mandoclevels[level], mandocerrs[t]); if (msg) fprintf(stderr, ": %s", msg); fputc('\n', stderr); - return(rc); + if (exit_status < level) + exit_status = level; + + return(level < MANDOCLEVEL_FATAL); } @@ -35,7 +35,6 @@ .Fo man_alloc .Fa "struct regset *regs" .Fa "void *data" -.Fa "int pflags" .Fa "mandocmsg msgs" .Fc .Ft int @@ -172,10 +171,6 @@ The .Fa data pointer is passed to .Fa msgs . -The -.Fa pflags -arguments are defined in -.Pa man.h . Returns NULL on failure. If non-NULL, the pointer must be freed with .Fn man_free . @@ -298,7 +293,7 @@ int line; bzero(®s, sizeof(struct regset)); line = 1; -man = man_alloc(®s, NULL, 0, NULL); +man = man_alloc(®s, NULL, NULL); buf = NULL; alloc_len = 0; @@ -56,7 +56,6 @@ static int man_ptext(struct man *, int, char *, int); static int man_pmacro(struct man *, int, char *, int); static void man_free1(struct man *); static void man_alloc1(struct man *); -static int macrowarn(struct man *, int, const char *, int); const struct man_node * @@ -94,8 +93,7 @@ man_free(struct man *man) struct man * -man_alloc(struct regset *regs, void *data, - int pflags, mandocmsg msg) +man_alloc(struct regset *regs, void *data, mandocmsg msg) { struct man *p; @@ -103,7 +101,6 @@ man_alloc(struct regset *regs, void *data, man_hash_init(); p->data = data; - p->pflags = pflags; p->msg = msg; p->regs = regs; @@ -435,19 +432,6 @@ descope: } -static int -macrowarn(struct man *m, int ln, const char *buf, int offs) -{ - int rc; - - rc = man_vmsg(m, MANDOCERR_MACRO, ln, offs, - "unknown macro: %s%s", - buf, strlen(buf) > 3 ? "..." : ""); - - return(MAN_IGN_MACRO & m->pflags ? rc : 0); -} - - int man_pmacro(struct man *m, int ln, char *buf, int offs) { @@ -490,15 +474,11 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) mac[j++] = buf[i++]; mac[j] = '\0'; - if (j == 4 || j < 1) { - if ( ! macrowarn(m, ln, mac, ppos)) - goto err; - return(1); - } - - if (MAN_MAX == (tok = man_hash_find(mac))) { - if ( ! macrowarn(m, ln, mac, ppos)) - goto err; + tok = (j > 0 && j < 4) ? man_hash_find(mac) : MAN_MAX; + if (MAN_MAX == tok) { + man_vmsg(m, MANDOCERR_MACRO, ln, ppos, + "unknown macro: %s%s", + buf, strlen(buf) > 3 ? "..." : ""); return(1); } @@ -97,9 +97,6 @@ struct man_node { struct man_node *body; }; -#define MAN_IGN_MACRO (1 << 0) -#define MAN_IGN_ESCAPE (1 << 2) - extern const char *const *man_macronames; __BEGIN_DECLS @@ -107,7 +104,7 @@ __BEGIN_DECLS struct man; void man_free(struct man *); -struct man *man_alloc(struct regset *, void *, int, mandocmsg); +struct man *man_alloc(struct regset *, void *, mandocmsg); void man_reset(struct man *); int man_parseln(struct man *, int, char *, int); int man_endparse(struct man *); diff --git a/man_validate.c b/man_validate.c index 0e09ace7..865e534a 100644 --- a/man_validate.c +++ b/man_validate.c @@ -233,12 +233,8 @@ check_text(CHKARGS) if (c) { p += c - 1; pos += c - 1; - continue; - } - - c = man_pmsg(m, n->line, pos, MANDOCERR_BADESCAPE); - if ( ! (MAN_IGN_ESCAPE & m->pflags) && ! c) - return(c); + } else + man_pmsg(m, n->line, pos, MANDOCERR_BADESCAPE); } return(1); @@ -23,11 +23,10 @@ .Sh SYNOPSIS .Nm mandoc .Op Fl V -.Op Fl f Ns Ar option .Op Fl m Ns Ar format .Op Fl O Ns Ar option .Op Fl T Ns Ar output -.Op Fl W Ns Ar err +.Op Fl W Ns Ar level .Op Ar file... .Sh DESCRIPTION The @@ -37,11 +36,6 @@ utility formats manual pages for display. The arguments are as follows: .Bl -tag -width Ds -.It Fl f Ns Ar option -Comma-separated compiler options. -See -.Sx Compiler Options -for details. .It Fl m Ns Ar format Input format. See @@ -60,18 +54,41 @@ Defaults to .Fl T Ns Cm ascii . .It Fl V Print version and exit. -.It Fl W Ns Ar err -Comma-separated warning options. -Use +.It Fl W Ns Ar level +Specify the minimum message +.Ar level +to be reported on the standard error output and to affect the exit status. +The +.Ar level +can be +.Cm warning , +.Cm error , +or +.Cm fatal . +The default is +.Fl W Ns Cm fatal ; .Fl W Ns Cm all -to print warnings, -.Fl W Ns Cm error -for warnings to be considered errors and cause utility -termination. -Multiple -.Fl W -arguments may be comma-separated, such as -.Fl W Ns Cm error , Ns Cm all . +is an alias for +.Fl W Ns Cm warning . +See +.Sx EXIT STATUS +and +.Sx DIAGNOSTICS +for details. +.Pp +The special option +.Fl W Ns Cm stop +tells +.Nm +to exit after parsing a file that causes warnings or errors of at least +the requested level. +No formatted output will be produced from that file. +If both a +.Ar level +and +.Cm stop +are requested, they can be joined with a comma, for example +.Fl W Ns Cm error , Ns Cm stop . .It Ar file Read input from zero or more files. If unspecified, reads from stdin. @@ -91,8 +108,6 @@ text from stdin, implying and produces .Fl T Ns Cm ascii output. -.Pp -.Ex -std mandoc .Ss Input Formats The .Nm @@ -136,39 +151,6 @@ specified and or .Fl m Ns Cm an is specified, then this format is used exclusively. -.Ss Compiler Options -Default -.Xr mdoc 7 -and -.Xr man 7 -compilation behaviour may be overridden with the -.Fl f -flag. -.Bl -tag -width Ds -.It Fl f Ns Cm ign-errors -When parsing multiple files, don't halt when one errors out. -Useful with -.Fl T Ns Cm lint -over a large set of manuals passed on the command line. -.It Fl f Ns Cm ign-escape -Ignore invalid escape sequences. -This is the default, but the option can be used to override an earlier -.Fl f Ns Cm strict . -.It Fl f Ns Cm ign-scope -When rewinding the scope of a block macro, forces the compiler to ignore -scope violations. -This can seriously mangle the resulting tree. -.Pq mdoc only -.It Fl f Ns Cm no-ign-escape -Do not ignore invalid escape sequences. -.It Fl f Ns Cm no-ign-macro -Do not ignore unknown macros at the start of input lines. -.It Fl f Ns Cm strict -Implies -.Fl f Ns Cm no-ign-escape -and -.Fl f Ns Cm no-ign-macro . -.El .Ss Output Formats The .Nm @@ -189,9 +171,7 @@ See .It Fl T Ns Cm lint Parse only: produce no output. Implies -.Fl W Ns Cm all -and -.Fl f Ns Cm strict . +.Fl W Ns Cm warning . .It Fl T Ns Cm pdf Produce PDF output. See @@ -352,10 +332,51 @@ See .Sx HTML Output for details; beyond generating XHTML tags instead of HTML tags, these output modes are identical. +.Sh EXIT STATUS +The +.Nm +utility exits with one of the following values, controlled by the message +.Ar level +associated with the +.Fl W +option: +.Pp +.Bl -tag -width Ds -compact +.It 0 +No warnings or errors occurred, or those that did were ignored because +they were lower than the requested +.Ar level . +.It 2 +At least one warning occurred, but no error, and +.Fl W Ns Cm warning +was specified. +.It 3 +At least one parsing error occurred, but no fatal error, and +.Fl W Ns Cm error +or +.Fl W Ns Cm warning +was specified. +.It 4 +A fatal parsing error occurred. +.It 5 +Invalid command line arguments were specified. +No input files have been read. +.It 6 +An operating system error occurred, for example memory exhaustion or an +error accessing input files. +Such errors cause +.Nm +to exit at once, possibly in the middle of parsing or formatting a file. +.El +.Pp +Note that selecting +.Fl T Ns Cm lint +output mode implies +.Fl W Ns Cm warning . .Sh EXAMPLES To page manuals to the terminal: .Pp -.D1 $ mandoc \-Wall,error \-fstrict mandoc.1 2\*(Gt&1 | less +.D1 $ mandoc \-Wall,stop mandoc.1 2\*(Gt&1 | less .D1 $ mandoc mandoc.1 mdoc.3 mdoc.7 | less .Pp To produce HTML manuals with @@ -366,11 +387,74 @@ as the style-sheet: .Pp To check over a large set of manuals: .Pp -.Dl $ mandoc \-Tlint \-fign-errors `find /usr/src -name \e*\e.[1-9]` +.Dl $ mandoc \-Tlint `find /usr/src -name \e*\e.[1-9]` .Pp To produce a series of PostScript manuals for A4 paper: .Pp .D1 $ mandoc \-Tps \-Opaper=a4 mdoc.7 man.7 \*(Gt manuals.ps +.Sh DIAGNOSTICS +Standard error messages reporting parsing errors are prefixed by +.Pp +.Sm off +.D1 Ar file : line : column : \ level : +.Sm on +.Pp +where the fields have the following meanings: +.Bl -tag -width "column" +.It Ar file +The name of the input file causing the message. +.It Ar line +The line number in that input file. +Line numbering starts at 1. +.It Ar column +The column number in that input file. +Column numbering starts at 1. +If the issue is caused by a word, the column number usually +points to the first character of the word. +.It Ar level +The message level, printed in capital letters. +.El +.Pp +Message levels have the following meanings: +.Bl -tag -width "warning" +.It Cm fatal +The parser is unable to parse a given input file at all. +No formatted output is produced from that input file. +.It Cm error +An input file contains syntax that cannot be safely interpreted, +either because it is invalid or because +.Nm +does not implement it yet. +By discarding part of the input or inserting missing tokens, +the parser is able to continue, and the error does not prevent +generation of formatted output, but typically, preparing that +output involves information loss, broken document structure +or unintended formatting. +.It Cm warning +An input file uses obsolete, discouraged or non-portable syntax. +All the same, the meaning of the input is unambiguous and a correct +rendering can be produced. +Documents causing warnings may render poorly when using other +formatting tools instead of +.Nm . +.El +.Pp +Messages of the +.Cm warning +and +.Cm error +levels are hidden unless their level, or a lower level, is requested using a +.Fl W +option or +.Fl T Ns Cm lint +output mode. +.Pp +The +.Nm +utility may also print messages related to invalid command line arguments +or operating system errors, for example when memory is exhausted or +input files cannot be read. Such messages do not carry the prefix +described above. .Sh COMPATIBILITY This section summarises .Nm @@ -199,7 +199,7 @@ mandoc_calloc(size_t num, size_t size) ptr = calloc(num, size); if (NULL == ptr) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } return(ptr); @@ -214,7 +214,7 @@ mandoc_malloc(size_t size) ptr = malloc(size); if (NULL == ptr) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } return(ptr); @@ -228,7 +228,7 @@ mandoc_realloc(void *ptr, size_t size) ptr = realloc(ptr, size); if (NULL == ptr) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } return(ptr); @@ -243,7 +243,7 @@ mandoc_strdup(const char *ptr) p = strdup(ptr); if (NULL == p) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } return(p); @@ -26,6 +26,17 @@ __BEGIN_DECLS +enum mandoclevel { + MANDOCLEVEL_OK = 0, + MANDOCLEVEL_RESERVED, + MANDOCLEVEL_WARNING, + MANDOCLEVEL_ERROR, + MANDOCLEVEL_FATAL, + MANDOCLEVEL_BADARG, + MANDOCLEVEL_SYSERR, + MANDOCLEVEL_MAX +}; + enum mandocerr { MANDOCERR_OK, @@ -105,7 +116,7 @@ enum mandocerr { MANDOCERR_NODOCBODY, /* no document body */ MANDOCERR_NODOCPROLOG, /* no document prologue */ MANDOCERR_UTSNAME, /* utsname system call failed */ - MANDOCERR_MEM, /* memory exhausted */ + MANDOCERR_MEM, /* static buffer exhausted */ MANDOCERR_MAX }; @@ -37,7 +37,6 @@ .Fo mdoc_alloc .Fa "struct regset *regs" .Fa "void *data" -.Fa "int pflags" .Fa "mandocmsg msgs" .Fc .Ft int @@ -124,10 +123,6 @@ The .Fa data pointer is passed to .Fa msgs . -The -.Fa pflags -arguments are defined in -.Pa mdoc.h . Returns NULL on failure. If non-NULL, the pointer must be freed with .Fn mdoc_free . @@ -338,7 +333,7 @@ int line; bzero(®s, sizeof(struct regset)); line = 1; -mdoc = mdoc_alloc(®s, NULL, 0, NULL); +mdoc = mdoc_alloc(®s, NULL, NULL); buf = NULL; alloc_len = 0; @@ -98,8 +98,6 @@ static int node_append(struct mdoc *, struct mdoc_node *); static int mdoc_ptext(struct mdoc *, int, char *, int); static int mdoc_pmacro(struct mdoc *, int, char *, int); -static int macrowarn(struct mdoc *, int, - const char *, int); const struct mdoc_node * @@ -191,8 +189,7 @@ mdoc_free(struct mdoc *mdoc) * Allocate volatile and non-volatile parse resources. */ struct mdoc * -mdoc_alloc(struct regset *regs, void *data, - int pflags, mandocmsg msg) +mdoc_alloc(struct regset *regs, void *data, mandocmsg msg) { struct mdoc *p; @@ -200,7 +197,6 @@ mdoc_alloc(struct regset *regs, void *data, p->msg = msg; p->data = data; - p->pflags = pflags; p->regs = regs; mdoc_hash_init(); @@ -727,21 +723,6 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) } -static int -macrowarn(struct mdoc *m, int ln, const char *buf, int offs) -{ - int rc; - - rc = mdoc_vmsg(m, MANDOCERR_MACRO, ln, offs, - "unknown macro: %s%s", - buf, strlen(buf) > 3 ? "..." : ""); - - /* FIXME: logic should be in driver. */ - /* FIXME: broken, will error out and not omit a message. */ - return(MDOC_IGN_MACRO & m->pflags ? rc : 0); -} - - /* * Parse a macro line, that is, a line beginning with the control * character. @@ -785,15 +766,11 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) mac[j++] = buf[i++]; mac[j] = '\0'; - if (j == 4 || j < 2) { - if ( ! macrowarn(m, ln, mac, sv)) - goto err; - return(1); - } - - if (MDOC_MAX == (tok = mdoc_hash_find(mac))) { - if ( ! macrowarn(m, ln, mac, sv)) - goto err; + tok = (j > 1 || j < 4) ? mdoc_hash_find(mac) : MDOC_MAX; + if (MDOC_MAX == tok) { + mdoc_vmsg(m, MANDOCERR_MACRO, ln, sv, + "unknown macro: %s%s", + buf, strlen(buf) > 3 ? "..." : ""); return(1); } @@ -352,10 +352,6 @@ struct mdoc_node { } data; }; -#define MDOC_IGN_SCOPE (1 << 0) /* Ignore scope violations. */ -#define MDOC_IGN_ESCAPE (1 << 1) /* Ignore bad escape sequences. */ -#define MDOC_IGN_MACRO (1 << 2) /* Ignore unknown macros. */ - /* See mdoc.3 for documentation. */ extern const char *const *mdoc_macronames; @@ -368,7 +364,7 @@ struct mdoc; /* See mdoc.3 for documentation. */ void mdoc_free(struct mdoc *); -struct mdoc *mdoc_alloc(struct regset *, void *, int, mandocmsg); +struct mdoc *mdoc_alloc(struct regset *, void *, mandocmsg); void mdoc_reset(struct mdoc *); int mdoc_parseln(struct mdoc *, int, char *, int); const struct mdoc_node *mdoc_node(const struct mdoc *); diff --git a/mdoc_html.c b/mdoc_html.c index 46b4e569..53889135 100644 --- a/mdoc_html.c +++ b/mdoc_html.c @@ -1183,7 +1183,7 @@ mdoc_bl_pre(MDOC_ARGS) ord = malloc(sizeof(struct ord)); if (NULL == ord) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } ord->cookie = n; ord->pos = 1; diff --git a/mdoc_validate.c b/mdoc_validate.c index ed5988ce..c500b945 100644 --- a/mdoc_validate.c +++ b/mdoc_validate.c @@ -481,12 +481,8 @@ check_text(struct mdoc *m, int ln, int pos, char *p) if (c) { p += c - 1; pos += c - 1; - continue; - } - - c = mdoc_pmsg(m, ln, pos, MANDOCERR_BADESCAPE); - if ( ! (MDOC_IGN_ESCAPE & m->pflags) && ! c) - return(c); + } else + mdoc_pmsg(m, ln, pos, MANDOCERR_BADESCAPE); } return(1); @@ -31,8 +31,8 @@ .Ft "struct roff *" .Fo roff_alloc .Fa "struct regset *regs" -.Fa "mandocmsg msgs" .Fa "void *data" +.Fa "mandocmsg msgs" .Fc .Ft int .Fn roff_endparse "struct roff *roff" @@ -111,10 +111,6 @@ The .Fa data pointer is passed to .Fa msgs . -The -.Fa pflags -arguments are defined in -.Pa roff.h . Returns NULL on failure. If non-NULL, the pointer must be freed with .Fn roff_free . @@ -168,7 +168,7 @@ static void roff_free1(struct roff *); static enum rofft roff_hash_find(const char *); static void roff_hash_init(void); static void roffnode_cleanscope(struct roff *); -static int roffnode_push(struct roff *, +static void roffnode_push(struct roff *, enum rofft, int, int); static void roffnode_pop(struct roff *); static enum rofft roff_parse(const char *, int *); @@ -258,16 +258,12 @@ roffnode_pop(struct roff *r) * Push a roff node onto the instruction stack. This must later be * removed with roffnode_pop(). */ -static int +static void roffnode_push(struct roff *r, enum rofft tok, int line, int col) { struct roffnode *p; - if (NULL == (p = calloc(1, sizeof(struct roffnode)))) { - (*r->msg)(MANDOCERR_MEM, r->data, line, col, NULL); - return(0); - } - + p = mandoc_calloc(1, sizeof(struct roffnode)); p->tok = tok; p->parent = r->last; p->line = line; @@ -275,7 +271,6 @@ roffnode_push(struct roff *r, enum rofft tok, int line, int col) p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY; r->last = p; - return(1); } @@ -307,15 +302,11 @@ roff_free(struct roff *r) struct roff * -roff_alloc(struct regset *regs, const mandocmsg msg, void *data) +roff_alloc(struct regset *regs, void *data, const mandocmsg msg) { struct roff *r; - if (NULL == (r = calloc(1, sizeof(struct roff)))) { - (*msg)(MANDOCERR_MEM, data, 0, 0, NULL); - return(0); - } - + r = mandoc_calloc(1, sizeof(struct roff)); r->regs = regs; r->msg = msg; r->data = data; @@ -650,8 +641,7 @@ roff_block(ROFF_ARGS) pos++; } - if ( ! roffnode_push(r, tok, ln, ppos)) - return(ROFF_ERR); + roffnode_push(r, tok, ln, ppos); if ('\0' == (*bufp)[pos]) return(ROFF_IGN); @@ -673,12 +663,7 @@ roff_block(ROFF_ARGS) if (1 == sz && '.' == (*bufp)[sv]) return(ROFF_IGN); - r->last->end = malloc(sz + 1); - - if (NULL == r->last->end) { - (*r->msg)(MANDOCERR_MEM, r->data, ln, pos, NULL); - return(ROFF_ERR); - } + r->last->end = mandoc_malloc(sz + 1); memcpy(r->last->end, *bufp + sv, sz); r->last->end[(int)sz] = '\0'; @@ -905,8 +890,7 @@ roff_cond(ROFF_ARGS) return(ROFF_ERR); } - if ( ! roffnode_push(r, tok, ln, ppos)) - return(ROFF_ERR); + roffnode_push(r, tok, ln, ppos); r->last->rule = rule; @@ -29,7 +29,7 @@ __BEGIN_DECLS struct roff; void roff_free(struct roff *); -struct roff *roff_alloc(struct regset *, mandocmsg, void *); +struct roff *roff_alloc(struct regset *, void *, mandocmsg); void roff_reset(struct roff *); enum rofferr roff_parseln(struct roff *, int, char **, size_t *, int, int *); @@ -83,7 +83,7 @@ term_alloc(enum termenc enc) p = calloc(1, sizeof(struct termp)); if (NULL == p) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } p->enc = enc; @@ -577,7 +577,7 @@ adjbuf(struct termp *p, size_t sz) p->buf = realloc(p->buf, p->maxcols); if (NULL == p->buf) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } } @@ -29,6 +29,7 @@ #include <time.h> #include <unistd.h> +#include "mandoc.h" #include "out.h" #include "main.h" #include "term.h" @@ -371,7 +372,7 @@ ps_growbuf(struct termp *p, size_t sz) if (NULL == p->engine.ps.psmarg) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } } @@ -608,7 +609,7 @@ pdf_obj(struct termp *p, size_t obj) p->engine.ps.pdfobjsz * sizeof(size_t)); if (NULL == p->engine.ps.pdfobjs) { perror(NULL); - exit(EXIT_FAILURE); + exit(MANDOCLEVEL_SYSERR); } } |