=================================================================== RCS file: /cvs/mandoc/main.c,v retrieving revision 1.114 retrieving revision 1.127 diff -u -p -r1.114 -r1.127 --- mandoc/main.c 2010/12/01 17:00:05 1.114 +++ mandoc/main.c 2010/12/29 14:38:14 1.127 @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.114 2010/12/01 17:00:05 kristaps Exp $ */ +/* $Id: main.c,v 1.127 2010/12/29 14:38:14 kristaps Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons * Copyright (c) 2010 Ingo Schwarze @@ -41,6 +41,7 @@ #define MAP_FILE 0 #endif +#define REPARSE_LIMIT 1000 #define UNCONST(a) ((void *)(uintptr_t)(const void *)(a)) /* FIXME: Intel's compiler? LLVM? pcc? */ @@ -89,6 +90,7 @@ struct curparse { struct mdoc *mdoc; /* mdoc parser */ struct roff *roff; /* roff parser (!NULL) */ struct regset regs; /* roff registers */ + int reparse_count; /* finite interpolation stack */ enum outt outtype; /* which output to use */ out_mdoc outmdoc; /* mdoc output ptr */ out_man outman; /* man output ptr */ @@ -122,71 +124,87 @@ static const char * const mandocerrs[MANDOCERR_MAX] = "generic warning", + /* related to the prologue */ + "no title in document", + "document title should be all caps", + "unknown manual section", + "cannot parse date argument", + "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)", - "text should be uppercase", + "NAME section must come first", + "bad NAME section contents", + "manual name not yet set", "sections out of conventional order", - "section name repeats", - "out of order prologue", - "repeated prologue entry", - "list type must come first", - "tab in non-literal context", - "bad escape sequence", - "unterminated quoted string", - "argument requires the width argument", - "superfluous width argument", - "bad date argument", - "bad width argument", - "unknown manual section", + "duplicate section name", "section not in conventional manual section", - "end of line whitespace", + + /* related to macros and nesting */ + "skipping obsolete macro", + "skipping paragraph macro", "blocks badly nested", + "child violates parent syntax", + "nested displays are not portable", + "already in literal mode", - "generic error", + /* related to missing macro arguments */ + "skipping empty macro", + "missing display type", + "list type must come first", + "tag lists require a width argument", + "missing font type", - "NAME section must come first", + /* related to bad macro arguments */ + "skipping argument", + "duplicate argument", + "duplicate display type", + "duplicate list type", + "unknown AT&T UNIX version", "bad Boolean value", - "child violates parent syntax", - "bad AT&T symbol", - "bad standard", - "list type repeated", - "display type repeated", - "argument repeated", - "ignoring argument", - "manual name not yet set", - "obsolete macro ignored", - "empty macro ignored", - "macro not allowed in body", - "macro not allowed in prologue", - "bad character", - "bad NAME section contents", - "no blank lines", - "no text in this context", + "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 macro will be lost", + "unknown escape sequence", + "unterminated quoted string", + + "generic error", + + "bad table syntax", + "bad table option", + "bad table layout", + "no table layout cells specified", + "input stack limit exceeded, infinite loop?", + "skipping bad character", + "skipping text before the first section header", + "skipping unknown macro", "NOT IMPLEMENTED: skipping request", "line scope broken", "argument count wrong", - "request scope close w/none open", - "scope already open", + "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)", - "no title in document", "missing list type", - "missing display type", - "missing font type", "line argument(s) will be lost", "body argument(s) will be lost", - "paragraph macro ignored", "generic fatal error", "column syntax is inconsistent", - "displays may not be nested", - "unsupported display type", - "blocks badly nested", - "no such block is open", + "NOT IMPLEMENTED: .Bd -file", "line scope broken, syntax violated", "argument count wrong, violates syntax", "child violates parent syntax", @@ -194,7 +212,6 @@ static const char * const mandocerrs[MANDOCERR_MAX] = "NOT IMPLEMENTED: .so with absolute path or \"..\"", "no document body", "no document prologue", - "utsname system call failed", "static buffer exhausted", }; @@ -213,6 +230,7 @@ static void version(void) __attribute__((noreturn)) static int woptions(struct curparse *, char *); static const char *progname; +static enum mandoclevel file_status = MANDOCLEVEL_OK; static enum mandoclevel exit_status = MANDOCLEVEL_OK; int @@ -349,7 +367,7 @@ pfile(const char *file, struct curparse *curp) if (-1 == (fd = open(file, O_RDONLY, 0))) { perror(file); - exit_status = MANDOCLEVEL_SYSERR; + file_status = MANDOCLEVEL_SYSERR; return(0); } @@ -367,7 +385,7 @@ pfile(const char *file, struct curparse *curp) if (-1 == close(fd)) perror(file); - return(MANDOCLEVEL_FATAL > exit_status ? 1 : 0); + return(MANDOCLEVEL_FATAL > file_status ? 1 : 0); } @@ -375,7 +393,7 @@ static void resize_buf(struct buf *buf, size_t initial) { - buf->sz = buf->sz ? 2 * buf->sz : initial; + buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial; buf->buf = realloc(buf->buf, buf->sz); if (NULL == buf->buf) { perror(NULL); @@ -471,6 +489,7 @@ fdesc(struct curparse *curp) curp->mdoc = NULL; curp->man = NULL; + file_status = MANDOCLEVEL_OK; /* Make sure the mandotory roff parser is initialised. */ @@ -483,32 +502,32 @@ fdesc(struct curparse *curp) pdesc(curp); - if (MANDOCLEVEL_FATAL <= exit_status) + if (MANDOCLEVEL_FATAL <= file_status) goto cleanup; /* NOTE a parser may not have been assigned, yet. */ if ( ! (curp->man || curp->mdoc)) { fprintf(stderr, "%s: Not a manual\n", curp->file); - exit_status = MANDOCLEVEL_FATAL; + file_status = MANDOCLEVEL_FATAL; goto cleanup; } /* Clean up the parse routine ASTs. */ if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) { - assert(MANDOCLEVEL_FATAL <= exit_status); + assert(MANDOCLEVEL_FATAL <= file_status); goto cleanup; } if (curp->man && ! man_endparse(curp->man)) { - assert(MANDOCLEVEL_FATAL <= exit_status); + assert(MANDOCLEVEL_FATAL <= file_status); goto cleanup; } assert(curp->roff); if ( ! roff_endparse(curp->roff)) { - assert(MANDOCLEVEL_FATAL <= exit_status); + assert(MANDOCLEVEL_FATAL <= file_status); goto cleanup; } @@ -517,7 +536,7 @@ fdesc(struct curparse *curp) * the requested level, do not produce output. */ - if (MANDOCLEVEL_OK != exit_status && curp->wstop) + if (MANDOCLEVEL_OK != file_status && curp->wstop) goto cleanup; /* If unset, allocate output dev now (if applicable). */ @@ -592,6 +611,9 @@ fdesc(struct curparse *curp) assert(curp->roff); roff_reset(curp->roff); + if (exit_status < file_status) + exit_status = file_status; + return; } @@ -609,7 +631,7 @@ pdesc(struct curparse *curp) */ if ( ! read_whole_file(curp, &blk, &with_mmap)) { - exit_status = MANDOCLEVEL_SYSERR; + file_status = MANDOCLEVEL_SYSERR; return; } @@ -650,8 +672,10 @@ parsebuf(struct curparse *curp, struct buf blk, int st if (0 == pos && '\0' == blk.buf[i]) break; - if (start) + if (start) { curp->line = lnn; + curp->reparse_count = 0; + } while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) { if ('\n' == blk.buf[i]) { @@ -750,7 +774,11 @@ rerun: switch (rr) { case (ROFF_REPARSE): - parsebuf(curp, ln, 0); + if (REPARSE_LIMIT >= ++curp->reparse_count) + parsebuf(curp, ln, 0); + else + mmsg(MANDOCERR_ROFFLOOP, curp, + curp->line, pos, NULL); pos = 0; continue; case (ROFF_APPEND): @@ -762,7 +790,7 @@ rerun: pos = 0; continue; case (ROFF_ERR): - assert(MANDOCLEVEL_FATAL <= exit_status); + assert(MANDOCLEVEL_FATAL <= file_status); break; case (ROFF_SO): if (pfile(ln.buf + of, curp)) { @@ -798,7 +826,7 @@ rerun: curp->line, ln.buf, of); if ( ! rc) { - assert(MANDOCLEVEL_FATAL <= exit_status); + assert(MANDOCLEVEL_FATAL <= file_status); break; } } @@ -980,8 +1008,8 @@ mmsg(enum mandocerr t, void *arg, int ln, int col, con fprintf(stderr, ": %s", msg); fputc('\n', stderr); - if (exit_status < level) - exit_status = level; + if (file_status < level) + file_status = level; return(level < MANDOCLEVEL_FATAL); }