+ *with_mmap = 0;
+ off = 0;
+ fb->sz = 0;
+ fb->buf = NULL;
+ for (;;) {
+ if (off == fb->sz) {
+ if (fb->sz == (1U << 31)) {
+ fprintf(stderr, "%s: input too large\n",
+ curp->file);
+ break;
+ }
+ resize_buf(fb, 65536);
+ }
+ ssz = read(curp->fd, fb->buf + (int)off, fb->sz - off);
+ if (ssz == 0) {
+ fb->sz = off;
+ return(1);
+ }
+ if (ssz == -1) {
+ perror(curp->file);
+ break;
+ }
+ off += (size_t)ssz;
+ }
+
+ free(fb->buf);
+ fb->buf = NULL;
+ return(0);
+}
+
+
+static void
+fdesc(struct curparse *curp)
+{
+
+ /*
+ * Called once per file with an opened file descriptor. All
+ * pre-file-parse operations (whether stdin or a file) should go
+ * here.
+ *
+ * This calls down into the nested parser, which drills down and
+ * fully parses a file and all its dependences (i.e., `so'). It
+ * then runs the cleanup validators and pushes to output.
+ */
+
+ /* Zero the parse type. */
+
+ curp->mdoc = NULL;
+ curp->man = NULL;
+
+ /* Make sure the mandotory roff parser is initialised. */
+
+ if (NULL == curp->roff) {
+ curp->roff = roff_alloc(&curp->regs, curp, mmsg);
+ assert(curp->roff);
+ }
+
+ /* Fully parse the file. */
+
+ pdesc(curp);
+
+ if (MANDOCLEVEL_FATAL <= exit_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);
+ exit_status = MANDOCLEVEL_FATAL;
+ goto cleanup;
+ }
+
+ /* Clean up the parse routine ASTs. */
+
+ if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
+ assert(MANDOCLEVEL_FATAL <= exit_status);
+ goto cleanup;
+ }
+
+ if (curp->man && ! man_endparse(curp->man)) {
+ assert(MANDOCLEVEL_FATAL <= exit_status);
+ goto cleanup;
+ }
+
+ assert(curp->roff);
+ if ( ! roff_endparse(curp->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;
+ 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 (curp->man && curp->outman)
+ (*curp->outman)(curp->outdata, curp->man);
+ if (curp->mdoc && curp->outmdoc)
+ (*curp->outmdoc)(curp->outdata, curp->mdoc);
+
+ cleanup:
+
+ memset(&curp->regs, 0, sizeof(struct regset));
+
+ /* Reset the current-parse compilers. */
+
+ if (curp->mdoc)
+ mdoc_reset(curp->mdoc);
+ if (curp->man)
+ man_reset(curp->man);
+
+ assert(curp->roff);
+ roff_reset(curp->roff);
+
+ return;
+}
+
+static void
+pdesc(struct curparse *curp)
+{
+ struct buf blk;
+ int with_mmap;
+
+ /*
+ * Run for each opened file; may be called more than once for
+ * each full parse sequence if the opened file is nested (i.e.,
+ * from `so'). Simply sucks in the whole file and moves into
+ * the parse phase for the file.
+ */
+
+ if ( ! read_whole_file(curp, &blk, &with_mmap)) {
+ exit_status = MANDOCLEVEL_SYSERR;
+ return;
+ }
+
+ /* Line number is per-file. */
+
+ 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, of, rc;
+ int pos; /* byte number in the ln buffer */
+ 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;
+ pos = 0;
+
+ for (i = 0; i < (int)blk.sz; ) {
+ if (0 == pos && '\0' == blk.buf[i])