=================================================================== RCS file: /cvs/mandoc/main.c,v retrieving revision 1.127 retrieving revision 1.153 diff -u -p -r1.127 -r1.153 --- mandoc/main.c 2010/12/29 14:38:14 1.127 +++ mandoc/main.c 2011/03/17 12:08:01 1.153 @@ -1,7 +1,7 @@ -/* $Id: main.c,v 1.127 2010/12/29 14:38:14 kristaps Exp $ */ +/* $Id: main.c,v 1.153 2011/03/17 12:08:01 kristaps 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 @@ -42,7 +42,6 @@ #endif #define REPARSE_LIMIT 1000 -#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a)) /* FIXME: Intel's compiler? LLVM? pcc? */ @@ -78,11 +77,13 @@ enum outt { }; struct curparse { - const char *file; /* Current parse. */ - int fd; /* Current parse. */ - int line; /* Line number in the file. */ - enum mandoclevel wlevel; /* Ignore messages below this. */ - int wstop; /* Stop after a file with a warning. */ + enum mandoclevel exit_status; /* status of all file parses */ + const char *file; /* current file-name */ + enum mandoclevel file_status; /* error status of current parse */ + int fd; /* current file-descriptor */ + int line; /* line number in the file */ + 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 *pman; /* persistent man parser */ struct mdoc *pmdoc; /* persistent mdoc parser */ @@ -128,7 +129,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", @@ -146,6 +148,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", @@ -153,10 +156,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", @@ -176,18 +181,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", @@ -221,7 +233,7 @@ static void fdesc(struct curparse *); static void ffile(const char *, struct curparse *); static int pfile(const char *, struct curparse *); static int moptions(enum intt *, char *); -static int mmsg(enum mandocerr, void *, +static void mmsg(enum mandocerr, void *, int, int, const char *); static void pset(const char *, int, struct curparse *); static int toptions(struct curparse *, char *); @@ -230,8 +242,6 @@ 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 main(int argc, char *argv[]) @@ -250,6 +260,7 @@ main(int argc, char *argv[]) curp.inttype = INTT_AUTO; curp.outtype = OUTT_ASCII; curp.wlevel = MANDOCLEVEL_FATAL; + curp.exit_status = MANDOCLEVEL_OK; /* LINTED */ while (-1 != (c = getopt(argc, argv, "m:O:T:VW:"))) @@ -290,7 +301,7 @@ main(int argc, char *argv[]) while (*argv) { ffile(*argv, &curp); - if (MANDOCLEVEL_OK != exit_status && curp.wstop) + if (MANDOCLEVEL_OK != curp.exit_status && curp.wstop) break; ++argv; } @@ -304,7 +315,7 @@ main(int argc, char *argv[]) if (curp.roff) roff_free(curp.roff); - return((int)exit_status); + return((int)curp.exit_status); } @@ -349,7 +360,7 @@ ffile(const char *file, struct curparse *curp) if (-1 == (curp->fd = open(curp->file, O_RDONLY, 0))) { perror(curp->file); - exit_status = MANDOCLEVEL_SYSERR; + curp->exit_status = MANDOCLEVEL_SYSERR; return; } @@ -367,7 +378,7 @@ pfile(const char *file, struct curparse *curp) if (-1 == (fd = open(file, O_RDONLY, 0))) { perror(file); - file_status = MANDOCLEVEL_SYSERR; + curp->file_status = MANDOCLEVEL_SYSERR; return(0); } @@ -385,7 +396,7 @@ pfile(const char *file, struct curparse *curp) if (-1 == close(fd)) perror(file); - return(MANDOCLEVEL_FATAL > file_status ? 1 : 0); + return(MANDOCLEVEL_FATAL > curp->file_status ? 1 : 0); } @@ -394,11 +405,7 @@ resize_buf(struct buf *buf, size_t initial) { buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial; - buf->buf = realloc(buf->buf, buf->sz); - if (NULL == buf->buf) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } + buf->buf = mandoc_realloc(buf->buf, buf->sz); } @@ -489,7 +496,7 @@ fdesc(struct curparse *curp) curp->mdoc = NULL; curp->man = NULL; - file_status = MANDOCLEVEL_OK; + curp->file_status = MANDOCLEVEL_OK; /* Make sure the mandotory roff parser is initialised. */ @@ -502,41 +509,38 @@ fdesc(struct curparse *curp) pdesc(curp); - if (MANDOCLEVEL_FATAL <= file_status) + if (MANDOCLEVEL_FATAL <= curp->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); - file_status = MANDOCLEVEL_FATAL; + curp->file_status = MANDOCLEVEL_FATAL; goto cleanup; } /* Clean up the parse routine ASTs. */ if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) { - assert(MANDOCLEVEL_FATAL <= file_status); + assert(MANDOCLEVEL_FATAL <= curp->file_status); goto cleanup; } if (curp->man && ! man_endparse(curp->man)) { - assert(MANDOCLEVEL_FATAL <= file_status); + assert(MANDOCLEVEL_FATAL <= curp->file_status); goto cleanup; } 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 * the requested level, do not produce output. */ - if (MANDOCLEVEL_OK != file_status && curp->wstop) + if (MANDOCLEVEL_OK != curp->file_status && curp->wstop) goto cleanup; /* If unset, allocate output dev now (if applicable). */ @@ -611,8 +615,8 @@ fdesc(struct curparse *curp) assert(curp->roff); roff_reset(curp->roff); - if (exit_status < file_status) - exit_status = file_status; + if (curp->exit_status < curp->file_status) + curp->exit_status = curp->file_status; return; } @@ -631,7 +635,7 @@ pdesc(struct curparse *curp) */ if ( ! read_whole_file(curp, &blk, &with_mmap)) { - file_status = MANDOCLEVEL_SYSERR; + curp->file_status = MANDOCLEVEL_SYSERR; return; } @@ -647,9 +651,15 @@ pdesc(struct curparse *curp) free(blk.buf); } +/* + * Main parse routine for an opened file. This is called for each + * opened file and simply loops around the full input file, possibly + * nesting (i.e., with `so'). + */ 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; @@ -657,12 +667,6 @@ parsebuf(struct curparse *curp, struct buf blk, int st int lnn; /* line number in the real file */ unsigned char c; - /* - * Main parse routine for an opened file. This is called for - * each opened file and simply loops around the full input file, - * possibly nesting (i.e., with `so'). - */ - memset(&ln, 0, sizeof(struct buf)); lnn = curp->line; @@ -678,6 +682,16 @@ parsebuf(struct curparse *curp, struct buf blk, int st } 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; @@ -712,11 +726,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; } @@ -782,7 +803,7 @@ rerun: pos = 0; continue; case (ROFF_APPEND): - pos = strlen(ln.buf); + pos = (int)strlen(ln.buf); continue; case (ROFF_RERUN): goto rerun; @@ -790,7 +811,7 @@ rerun: pos = 0; continue; case (ROFF_ERR): - assert(MANDOCLEVEL_FATAL <= file_status); + assert(MANDOCLEVEL_FATAL <= curp->file_status); break; case (ROFF_SO): if (pfile(ln.buf + of, curp)) { @@ -798,11 +819,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 <= curp->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 @@ -816,19 +845,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 <= curp->file_status); + break; } /* Temporary buffers typically are not full. */ @@ -987,7 +1036,7 @@ woptions(struct curparse *curp, char *arg) return(1); } -static int +static void mmsg(enum mandocerr t, void *arg, int ln, int col, const char *msg) { struct curparse *cp; @@ -1000,7 +1049,7 @@ mmsg(enum mandocerr t, void *arg, int ln, int col, con cp = (struct curparse *)arg; if (level < cp->wlevel) - return(1); + return; fprintf(stderr, "%s:%d:%d: %s: %s", cp->file, ln, col + 1, mandoclevels[level], mandocerrs[t]); @@ -1008,8 +1057,6 @@ mmsg(enum mandocerr t, void *arg, int ln, int col, con fprintf(stderr, ": %s", msg); fputc('\n', stderr); - if (file_status < level) - file_status = level; - - return(level < MANDOCLEVEL_FATAL); + if (cp->file_status < level) + cp->file_status = level; }