=================================================================== RCS file: /cvs/mandoc/main.c,v retrieving revision 1.121 retrieving revision 1.147 diff -u -p -r1.121 -r1.147 --- mandoc/main.c 2010/12/06 16:55:35 1.121 +++ mandoc/main.c 2011/03/07 01:35:51 1.147 @@ -1,7 +1,7 @@ -/* $Id: main.c,v 1.121 2010/12/06 16:55:35 kristaps Exp $ */ +/* $Id: main.c,v 1.147 2011/03/07 01:35:51 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons - * Copyright (c) 2010 Ingo Schwarze + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2010, 2011 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -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 */ @@ -126,7 +128,8 @@ static const char * const mandocerrs[MANDOCERR_MAX] = "no title in document", "document title should be all caps", "unknown manual section", - "cannot parse date argument", + "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", @@ -144,6 +147,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = /* 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", @@ -151,10 +155,12 @@ static const char * const mandocerrs[MANDOCERR_MAX] = /* 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", @@ -174,13 +180,25 @@ static const char * const mandocerrs[MANDOCERR_MAX] = "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: skipping request", + "NOT IMPLEMENTED, please use groff: skipping request", "line scope broken", "argument count wrong", "skipping end of block that is not open", @@ -386,7 +404,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); @@ -519,10 +537,7 @@ fdesc(struct curparse *curp) } assert(curp->roff); - if ( ! roff_endparse(curp->roff)) { - assert(MANDOCLEVEL_FATAL <= file_status); - goto cleanup; - } + roff_endparse(curp->roff); /* * With -Wstop and warnings or errors of at least @@ -643,6 +658,7 @@ pdesc(struct curparse *curp) static void parsebuf(struct curparse *curp, struct buf blk, int start) { + const struct tbl_span *span; struct buf ln; enum rofferr rr; int i, of, rc; @@ -665,10 +681,22 @@ 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])) { + + /* + * When finding an unescaped newline character, + * leave the character loop to process the line. + * Skip a preceding carriage return, if any. + */ + + if ('\r' == blk.buf[i] && i + 1 < (int)blk.sz && + '\n' == blk.buf[i + 1]) + ++i; if ('\n' == blk.buf[i]) { ++i; ++lnn; @@ -703,11 +731,18 @@ parsebuf(struct curparse *curp, struct buf blk, int st continue; } - /* Found escape & at least one other char. */ + /* + * 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 < (int)blk.sz && + '\n' == blk.buf[i + 2]) + ++i; if ('\n' == blk.buf[i + 1]) { i += 2; - /* Escaped newlines are skipped over */ ++lnn; continue; } @@ -765,7 +800,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): @@ -785,11 +824,19 @@ rerun: continue; } else break; - case (ROFF_CONT): + default: break; } /* + * If we encounter errors in the recursive parsebuf() + * call, make sure we don't continue parsing. + */ + + if (MANDOCLEVEL_FATAL <= file_status) + break; + + /* * If input parsers have not been allocated, do so now. * We keep these instanced betwen parsers, but set them * locally per parse routine since we can use different @@ -803,19 +850,39 @@ rerun: * Lastly, push down into the parsers themselves. One * of these will have already been set in the pset() * routine. + * If libroff returns ROFF_TBL, then add it to the + * currently open parse. Since we only get here if + * there does exist data (see tbl_data.c), we're + * guaranteed that something's been allocated. + * Do the same for ROFF_EQN. */ - if (curp->man || curp->mdoc) { + rc = -1; + + if (ROFF_TBL == rr) + while (NULL != (span = roff_span(curp->roff))) { + rc = curp->man ? + man_addspan(curp->man, span) : + mdoc_addspan(curp->mdoc, span); + if (0 == rc) + break; + } + else if (ROFF_EQN == rr) + rc = curp->mdoc ? + mdoc_addeqn(curp->mdoc, + roff_eqn(curp->roff)) : + man_addeqn(curp->man, + roff_eqn(curp->roff)); + else if (curp->man || curp->mdoc) rc = curp->man ? man_parseln(curp->man, curp->line, ln.buf, of) : mdoc_parseln(curp->mdoc, curp->line, ln.buf, of); - if ( ! rc) { - assert(MANDOCLEVEL_FATAL <= file_status); - break; - } + if (0 == rc) { + assert(MANDOCLEVEL_FATAL <= file_status); + break; } /* Temporary buffers typically are not full. */