diff options
-rw-r--r-- | main.c | 342 | ||||
-rw-r--r-- | roff.h | 3 |
2 files changed, 216 insertions, 129 deletions
@@ -79,6 +79,7 @@ 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 intt inttype; /* which parser to use */ @@ -193,8 +194,11 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "static buffer exhausted", }; +static void parsebuf(struct curparse *, struct buf, int); +static void pdesc(struct curparse *); 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 *, int, int, const char *); @@ -320,6 +324,35 @@ ffile(const char *file, struct curparse *curp) perror(curp->file); } +static int +pfile(const char *file, struct curparse *curp) +{ + const char *savefile; + int fd, savefd; + + if (-1 == (fd = open(file, O_RDONLY, 0))) { + perror(file); + exit_status = MANDOCLEVEL_SYSERR; + return(0); + } + + savefile = curp->file; + savefd = curp->fd; + + curp->file = file; + curp->fd = fd; + + pdesc(curp); + + curp->file = savefile; + curp->fd = savefd; + + if (-1 == close(fd)) + perror(file); + + return(MANDOCLEVEL_FATAL > exit_status ? 1 : 0); +} + static void resize_buf(struct buf *buf, size_t initial) @@ -406,25 +439,127 @@ read_whole_file(struct curparse *curp, struct buf *fb, int *with_mmap) static void fdesc(struct curparse *curp) { - struct buf ln, blk; - int i, pos, lnn, lnn_start, with_mmap, of; - enum rofferr re; - unsigned char c; struct man *man; struct mdoc *mdoc; struct roff *roff; - man = NULL; - mdoc = NULL; - roff = NULL; + pdesc(curp); - memset(&ln, 0, sizeof(struct buf)); + man = curp->man; + mdoc = curp->mdoc; + roff = curp->roff; + + if (MANDOCLEVEL_FATAL <= exit_status) + goto cleanup; + + /* NOTE a parser may not have been assigned, yet. */ + + if ( ! (man || mdoc)) { + fprintf(stderr, "%s: Not a manual\n", curp->file); + exit_status = MANDOCLEVEL_FATAL; + goto cleanup; + } + + /* Clean up the parse routine ASTs. */ + + 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; + } /* - * Two buffers: ln and buf. buf is the input file and may be - * memory mapped. ln is a line buffer and grows on-demand. + * 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; + + /* If unset, allocate output dev now (if applicable). */ + + if ( ! (curp->outman && curp->outmdoc)) { + switch (curp->outtype) { + case (OUTT_XHTML): + curp->outdata = xhtml_alloc(curp->outopts); + break; + case (OUTT_HTML): + curp->outdata = html_alloc(curp->outopts); + break; + case (OUTT_ASCII): + curp->outdata = ascii_alloc(curp->outopts); + curp->outfree = ascii_free; + break; + case (OUTT_PDF): + curp->outdata = pdf_alloc(curp->outopts); + curp->outfree = pspdf_free; + break; + case (OUTT_PS): + curp->outdata = ps_alloc(curp->outopts); + curp->outfree = pspdf_free; + break; + default: + break; + } + + switch (curp->outtype) { + case (OUTT_HTML): + /* FALLTHROUGH */ + case (OUTT_XHTML): + curp->outman = html_man; + curp->outmdoc = html_mdoc; + curp->outfree = html_free; + break; + case (OUTT_TREE): + curp->outman = tree_man; + curp->outmdoc = tree_mdoc; + break; + case (OUTT_PDF): + /* FALLTHROUGH */ + case (OUTT_ASCII): + /* FALLTHROUGH */ + case (OUTT_PS): + curp->outman = terminal_man; + curp->outmdoc = terminal_mdoc; + break; + default: + break; + } + } + + /* Execute the out device, if it exists. */ + + if (man && curp->outman) + (*curp->outman)(curp->outdata, man); + if (mdoc && curp->outmdoc) + (*curp->outmdoc)(curp->outdata, mdoc); + + cleanup: + memset(&curp->regs, 0, sizeof(struct regset)); + if (mdoc) + mdoc_reset(mdoc); + if (man) + man_reset(man); + if (roff) + roff_reset(roff); + + return; +} + + +static void +pdesc(struct curparse *curp) +{ + struct buf blk; + int with_mmap; + if ( ! read_whole_file(curp, &blk, &with_mmap)) { exit_status = MANDOCLEVEL_SYSERR; return; @@ -433,12 +568,42 @@ fdesc(struct curparse *curp) if (NULL == curp->roff) curp->roff = roff_alloc(&curp->regs, curp, mmsg); assert(curp->roff); + + curp->line = 1; + parsebuf(curp, blk, 1); + + if (with_mmap) + munmap(blk.buf, blk.sz); + else + free(blk.buf); +} + +static void +parsebuf(struct curparse *curp, struct buf blk, int start) +{ + struct buf ln; + int i, pos, lnn, of; + unsigned char c; + struct man *man; + struct mdoc *mdoc; + struct roff *roff; + + man = curp->man; + mdoc = curp->mdoc; roff = curp->roff; - for (i = 0, lnn = 1; i < (int)blk.sz;) { - pos = 0; - lnn_start = lnn; - while (i < (int)blk.sz) { + memset(&ln, 0, sizeof(struct buf)); + + lnn = curp->line; /* line number in the real file */ + pos = 0; /* byte number in the ln buffer */ + + for (i = 0; i < (int)blk.sz;) { + if (0 == pos && '\0' == blk.buf[i]) + break; + if (start) + curp->line = lnn; + + while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) { if ('\n' == blk.buf[i]) { ++i; ++lnn; @@ -457,7 +622,7 @@ fdesc(struct curparse *curp) c = (unsigned char) blk.buf[i]; if ( ! (isascii(c) && (isgraph(c) || isblank(c)))) { mmsg(MANDOCERR_BADCHAR, curp, - lnn_start, pos, "ignoring byte"); + curp->line, pos, "ignoring byte"); i++; continue; } @@ -517,16 +682,32 @@ fdesc(struct curparse *curp) */ of = 0; - do { - re = roff_parseln(roff, lnn_start, - &ln.buf, &ln.sz, of, &of); - } while (ROFF_RERUN == re); - - if (ROFF_IGN == re) { +rerun: + switch (roff_parseln(roff, curp->line, &ln.buf, &ln.sz, + of, &of)) { + case (ROFF_REPARSE): + parsebuf(curp, ln, 0); + pos = 0; + continue; + case (ROFF_APPEND): + pos = strlen(ln.buf); continue; - } else if (ROFF_ERR == re) { + case (ROFF_RERUN): + goto rerun; + case (ROFF_IGN): + pos = 0; + continue; + case (ROFF_ERR): assert(MANDOCLEVEL_FATAL <= exit_status); - goto cleanup; + break; + case (ROFF_SO): + if (pfile(ln.buf + of, curp)) { + pos = 0; + continue; + } else + break; + case (ROFF_CONT): + break; } /* @@ -541,121 +722,24 @@ fdesc(struct curparse *curp) /* Lastly, push down into the parsers themselves. */ - if (man && ! man_parseln(man, lnn_start, ln.buf, of)) { + if (man && ! man_parseln(man, curp->line, ln.buf, of)) { assert(MANDOCLEVEL_FATAL <= exit_status); - goto cleanup; + break; } - if (mdoc && ! mdoc_parseln(mdoc, lnn_start, ln.buf, of)) { + if (mdoc && ! mdoc_parseln(mdoc, curp->line, ln.buf, of)) { assert(MANDOCLEVEL_FATAL <= exit_status); - goto cleanup; - } - } - - /* NOTE a parser may not have been assigned, yet. */ - - if ( ! (man || mdoc)) { - fprintf(stderr, "%s: Not a manual\n", curp->file); - exit_status = MANDOCLEVEL_FATAL; - goto cleanup; - } - - /* Clean up the parse routine ASTs. */ - - 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; - } - - /* - * 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; - - /* If unset, allocate output dev now (if applicable). */ - - if ( ! (curp->outman && curp->outmdoc)) { - switch (curp->outtype) { - case (OUTT_XHTML): - curp->outdata = xhtml_alloc(curp->outopts); - break; - case (OUTT_HTML): - curp->outdata = html_alloc(curp->outopts); - break; - case (OUTT_ASCII): - curp->outdata = ascii_alloc(curp->outopts); - curp->outfree = ascii_free; - break; - case (OUTT_PDF): - curp->outdata = pdf_alloc(curp->outopts); - curp->outfree = pspdf_free; - break; - case (OUTT_PS): - curp->outdata = ps_alloc(curp->outopts); - curp->outfree = pspdf_free; - break; - default: break; } - switch (curp->outtype) { - case (OUTT_HTML): - /* FALLTHROUGH */ - case (OUTT_XHTML): - curp->outman = html_man; - curp->outmdoc = html_mdoc; - curp->outfree = html_free; - break; - case (OUTT_TREE): - curp->outman = tree_man; - curp->outmdoc = tree_mdoc; + /* Temporary buffers typically are not full. */ + if (0 == start && '\0' == blk.buf[i]) break; - case (OUTT_PDF): - /* FALLTHROUGH */ - case (OUTT_ASCII): - /* FALLTHROUGH */ - case (OUTT_PS): - curp->outman = terminal_man; - curp->outmdoc = terminal_mdoc; - break; - default: - break; - } - } - - /* Execute the out device, if it exists. */ - - if (man && curp->outman) - (*curp->outman)(curp->outdata, man); - if (mdoc && curp->outmdoc) - (*curp->outmdoc)(curp->outdata, mdoc); - cleanup: - memset(&curp->regs, 0, sizeof(struct regset)); - if (mdoc) - mdoc_reset(mdoc); - if (man) - man_reset(man); - if (roff) - roff_reset(roff); - if (ln.buf) - free(ln.buf); - if (with_mmap) - munmap(blk.buf, blk.sz); - else - free(blk.buf); + /* Start the next input line. */ + pos = 0; + } - return; + free(ln.buf); } @@ -20,6 +20,9 @@ enum rofferr { ROFF_CONT, /* continue processing line */ ROFF_RERUN, /* re-run roff interpreter with offset */ + ROFF_APPEND, /* re-run main parser, appending next line */ + ROFF_REPARSE, /* re-run main parser on the result */ + ROFF_SO, /* include another file */ ROFF_IGN, /* ignore current line */ ROFF_ERR /* badness: puke and stop */ }; |