=================================================================== RCS file: /cvs/mandoc/read.c,v retrieving revision 1.154 retrieving revision 1.186 diff -u -p -r1.154 -r1.186 --- mandoc/read.c 2016/12/07 22:59:29 1.154 +++ mandoc/read.c 2017/07/03 13:40:19 1.186 @@ -1,7 +1,7 @@ -/* $Id: read.c,v 1.154 2016/12/07 22:59:29 schwarze Exp $ */ +/* $Id: read.c,v 1.186 2017/07/03 13:40:19 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2010-2016 Ingo Schwarze + * Copyright (c) 2010-2017 Ingo Schwarze * Copyright (c) 2010, 2012 Joerg Sonnenberger * * Permission to use, copy, modify, and distribute this software for any @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -48,16 +47,16 @@ #define REPARSE_LIMIT 1000 struct mparse { - struct roff_man *man; /* man parser */ struct roff *roff; /* roff parser (!NULL) */ + struct roff_man *man; /* man parser */ char *sodest; /* filename pointed to by .so */ const char *file; /* filename of current input file */ struct buf *primary; /* buffer currently being parsed */ struct buf *secondary; /* preprocessed copy of input */ - const char *defos; /* default operating system */ + const char *os_s; /* default operating system */ mandocmsg mmsg; /* warning/error message handler */ enum mandoclevel file_status; /* status of current parse */ - enum mandoclevel wlevel; /* ignore messages below this */ + enum mandocerr mmin; /* ignore messages below this */ int options; /* parser options */ int gzip; /* current input file is gzipped */ int filenc; /* encoding of the current file */ @@ -67,7 +66,7 @@ struct mparse { static void choose_parser(struct mparse *); static void resize_buf(struct buf *, size_t); -static void mparse_buf_r(struct mparse *, struct buf, size_t, int); +static int mparse_buf_r(struct mparse *, struct buf, size_t, int); static int read_whole_file(struct mparse *, const char *, int, struct buf *, int *); static void mparse_end(struct mparse *); @@ -76,8 +75,8 @@ static void mparse_parse_buffer(struct mparse *, str static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = { MANDOCERR_OK, + MANDOCERR_STYLE, MANDOCERR_WARNING, - MANDOCERR_WARNING, MANDOCERR_ERROR, MANDOCERR_UNSUPP, MANDOCERR_MAX, @@ -87,6 +86,28 @@ static const enum mandocerr mandoclimits[MANDOCLEVEL_M static const char * const mandocerrs[MANDOCERR_MAX] = { "ok", + "base system convention", + + "Mdocdate found", + "Mdocdate missing", + "unknown architecture", + "operating system explicitly specified", + "RCS id missing", + "referenced manual not found", + + "generic style suggestion", + + "legacy man(7) date format", + "duplicate RCS id", + "typo in section name", + "useless macro", + "consider using OS macro", + "errnos out of order", + "duplicate errno", + "description line ends with a full stop", + "no blank before trailing delimiter", + "function name without markup", + "generic warning", /* related to the prologue */ @@ -97,6 +118,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = "unknown manual section", "missing date, using today's date", "cannot parse date, using it verbatim", + "date in the future, using it anyway", "missing Os macro, using \"\"", "duplicate prologue macro", "late prologue macro", @@ -108,14 +130,17 @@ static const char * const mandocerrs[MANDOCERR_MAX] = "no document body", "content before first section header", "first section is not \"NAME\"", - "NAME section without name", + "NAME section without Nm before Nd", "NAME section without description", "description not at the end of NAME", "bad NAME section content", + "missing comma before name", "missing description line, using \"\"", + "description line outside NAME section", "sections out of conventional order", "duplicate section title", "unexpected section", + "cross reference to self", "unusual Xr order", "unusual Xr punctuation", "AUTHORS section without An macro", @@ -129,9 +154,11 @@ static const char * const mandocerrs[MANDOCERR_MAX] = "blocks badly nested", "nested displays are not portable", "moving content out of list", + "first macro on line", "fill mode already enabled, skipping", "fill mode already disabled, skipping", "line scope broken", + "skipping blank line in line scope", /* related to missing macro arguments */ "skipping empty request", @@ -146,10 +173,12 @@ static const char * const mandocerrs[MANDOCERR_MAX] = "missing function name, using \"\"", "empty head in list item", "empty list item", + "missing argument, using next line", "missing font type, using \\fR", "unknown font type, using \\fR", "nothing follows prefix", "empty reference block", + "missing section argument", "missing -std argument, adding it", "missing option string, using \"\"", "missing resource identifier, using \"\"", @@ -166,6 +195,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = "unknown AT&T UNIX version", "comma in function argument", "parenthesis in function name", + "unknown library name", "invalid content in Rs block", "invalid Boolean argument", "unknown font, skipping request", @@ -175,6 +205,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = "blank line in fill mode, using .sp", "tab in filled text", "whitespace at end of input line", + "new sentence, new line", "bad comment style", "invalid escape sequence", "undefined string, using \"\"", @@ -217,6 +248,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = "NOT IMPLEMENTED: Bd -file", "skipping display without arguments", "missing list type, using -item", + "argument is not numeric, using 1", "missing manual name, using \"\"", "uname(3) system call failed, using UNKNOWN", "unknown standard specifier", @@ -238,7 +270,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = static const char * const mandoclevels[MANDOCLEVEL_MAX] = { "SUCCESS", - "RESERVED", + "STYLE", "WARNING", "ERROR", "UNSUPP", @@ -290,14 +322,15 @@ choose_parser(struct mparse *curp) } if (format == MPARSE_MDOC) { - mdoc_hash_init(); curp->man->macroset = MACROSET_MDOC; - curp->man->first->tok = TOKEN_NONE; + if (curp->man->mdocmac == NULL) + curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX); } else { - man_hash_init(); curp->man->macroset = MACROSET_MAN; - curp->man->first->tok = TOKEN_NONE; + if (curp->man->manmac == NULL) + curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX); } + curp->man->first->tok = TOKEN_NONE; } /* @@ -307,7 +340,7 @@ choose_parser(struct mparse *curp) * macros, inline equations, and input line traps) * and indirectly (for .so file inclusion). */ -static void +static int mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) { const struct tbl_span *span; @@ -315,7 +348,6 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size const char *save_file; char *cp; size_t pos; /* byte number in the ln buffer */ - size_t j; /* auxiliary byte number in the blk buffer */ enum rofferr rr; int of; int lnn; /* line number in the real file */ @@ -397,79 +429,14 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size continue; } - /* Trailing backslash = a plain char. */ - - if (blk.buf[i] != '\\' || i + 1 == blk.sz) { - ln.buf[pos++] = blk.buf[i++]; - continue; - } - - /* - * Found escape and at least one other character. - * When it's a newline character, skip it. - * When there is a carriage return in between, - * skip that one as well. - */ - - if ('\r' == blk.buf[i + 1] && i + 2 < blk.sz && - '\n' == blk.buf[i + 2]) - ++i; - if ('\n' == blk.buf[i + 1]) { - i += 2; - ++lnn; - continue; - } - - if ('"' == blk.buf[i + 1] || '#' == blk.buf[i + 1]) { - j = i; - i += 2; - /* Comment, skip to end of line */ - for (; i < blk.sz; ++i) { - if (blk.buf[i] != '\n') - continue; - if (blk.buf[i - 1] == ' ' || - blk.buf[i - 1] == '\t') - mandoc_msg( - MANDOCERR_SPACE_EOL, - curp, curp->line, - pos + i-1 - j, NULL); - ++i; - ++lnn; - break; - } - - /* Backout trailing whitespaces */ - for (; pos > 0; --pos) { - if (ln.buf[pos - 1] != ' ') - break; - if (pos > 2 && ln.buf[pos - 2] == '\\') - break; - } - break; - } - - /* Catch escaped bogus characters. */ - - c = (unsigned char) blk.buf[i+1]; - - if ( ! (isascii(c) && - (isgraph(c) || isblank(c)))) { - mandoc_vmsg(MANDOCERR_CHAR_BAD, curp, - curp->line, pos, "0x%x", c); - i += 2; - ln.buf[pos++] = '?'; - continue; - } - - /* Some other escape sequence, copy & cont. */ - ln.buf[pos++] = blk.buf[i++]; - ln.buf[pos++] = blk.buf[i++]; } - if (pos >= ln.sz) + if (pos + 1 >= ln.sz) resize_buf(&ln, 256); + if (i == blk.sz || blk.buf[i] == '\0') + ln.buf[pos++] = '\n'; ln.buf[pos] = '\0'; /* @@ -508,13 +475,16 @@ rerun: switch (rr) { case ROFF_REPARSE: - if (REPARSE_LIMIT >= ++curp->reparse_count) - mparse_buf_r(curp, ln, of, 0); - else + if (++curp->reparse_count > REPARSE_LIMIT) mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, pos, NULL); - pos = 0; - continue; + else if (mparse_buf_r(curp, ln, of, 0) == 1 || + start == 1) { + pos = 0; + continue; + } + free(ln.buf); + return 0; case ROFF_APPEND: pos = strlen(ln.buf); continue; @@ -528,7 +498,7 @@ rerun: (i >= blk.sz || blk.buf[i] == '\0')) { curp->sodest = mandoc_strdup(ln.buf + of); free(ln.buf); - return; + return 1; } /* * We remove `so' clauses from our lookaside @@ -594,18 +564,18 @@ rerun: } free(ln.buf); + return 1; } static int read_whole_file(struct mparse *curp, const char *file, int fd, struct buf *fb, int *with_mmap) { + struct stat st; gzFile gz; size_t off; ssize_t ssz; - struct stat st; - if (fstat(fd, &st) == -1) err((int)MANDOCLEVEL_SYSERR, "%s", file); @@ -796,29 +766,32 @@ mparse_open(struct mparse *curp, const char *file) } struct mparse * -mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg, - const char *defos) +mparse_alloc(int options, enum mandocerr mmin, mandocmsg mmsg, + enum mandoc_os os_e, const char *os_s) { struct mparse *curp; curp = mandoc_calloc(1, sizeof(struct mparse)); curp->options = options; - curp->wlevel = wlevel; + curp->mmin = mmin; curp->mmsg = mmsg; - curp->defos = defos; + curp->os_s = os_s; curp->roff = roff_alloc(curp, options); - curp->man = roff_man_alloc( curp->roff, curp, curp->defos, + curp->man = roff_man_alloc(curp->roff, curp, curp->os_s, curp->options & MPARSE_QUICK ? 1 : 0); if (curp->options & MPARSE_MDOC) { - mdoc_hash_init(); curp->man->macroset = MACROSET_MDOC; + if (curp->man->mdocmac == NULL) + curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX); } else if (curp->options & MPARSE_MAN) { - man_hash_init(); curp->man->macroset = MACROSET_MAN; + if (curp->man->manmac == NULL) + curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX); } curp->man->first->tok = TOKEN_NONE; + curp->man->meta.os_e = os_e; return curp; } @@ -827,22 +800,25 @@ mparse_reset(struct mparse *curp) { roff_reset(curp->roff); roff_man_reset(curp->man); + + free(curp->sodest); + curp->sodest = NULL; + if (curp->secondary) curp->secondary->sz = 0; curp->file_status = MANDOCLEVEL_OK; - - free(curp->sodest); - curp->sodest = NULL; + curp->gzip = 0; } void mparse_free(struct mparse *curp) { + roffhash_free(curp->man->mdocmac); + roffhash_free(curp->man->manmac); roff_man_free(curp->man); - if (curp->roff) - roff_free(curp->roff); + roff_free(curp->roff); if (curp->secondary) free(curp->secondary->buf); @@ -865,6 +841,13 @@ mparse_result(struct mparse *curp, struct roff_man **m } void +mparse_updaterc(struct mparse *curp, enum mandoclevel *rc) +{ + if (curp->file_status > *rc) + *rc = curp->file_status; +} + +void mandoc_vmsg(enum mandocerr t, struct mparse *m, int ln, int pos, const char *fmt, ...) { @@ -884,12 +867,12 @@ mandoc_msg(enum mandocerr er, struct mparse *m, { enum mandoclevel level; + if (er < m->mmin && er != MANDOCERR_FILE) + return; + level = MANDOCLEVEL_UNSUPP; while (er < mandoclimits[level]) level--; - - if (level < m->wlevel && er != MANDOCERR_FILE) - return; if (m->mmsg) (*m->mmsg)(er, level, m->file, ln, col, msg);