summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--main.c342
-rw-r--r--roff.h3
2 files changed, 216 insertions, 129 deletions
diff --git a/main.c b/main.c
index dab4b450..574b7c68 100644
--- a/main.c
+++ b/main.c
@@ -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);
}
diff --git a/roff.h b/roff.h
index b15d64f7..bad27799 100644
--- a/roff.h
+++ b/roff.h
@@ -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 */
};