-/* $Id: read.c,v 1.91 2014/10/18 15:57:34 schwarze Exp $ */
+/* $Id: read.c,v 1.116 2015/01/26 00:57:22 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2012 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
#include "libmandoc.h"
#include "mdoc.h"
#include "man.h"
-#include "main.h"
#define REPARSE_LIMIT 1000
-struct buf {
- char *buf; /* binary input buffer */
- size_t sz; /* size of binary buffer */
-};
-
struct mparse {
struct man *pman; /* persistent man parser */
struct mdoc *pmdoc; /* persistent mdoc parser */
struct man *man; /* man parser */
struct mdoc *mdoc; /* mdoc parser */
struct roff *roff; /* roff parser (!NULL) */
+ const struct mchars *mchars; /* character table */
char *sodest; /* filename pointed to by .so */
const char *file; /* filename of current input file */
struct buf *primary; /* buffer currently being parsed */
enum mandoclevel file_status; /* status of current parse */
enum mandoclevel wlevel; /* ignore messages below this */
int options; /* parser options */
+ int filenc; /* encoding of the current file */
int reparse_count; /* finite interp. stack */
int line; /* line number in the file */
+ pid_t child; /* the gunzip(1) process */
};
static void choose_parser(struct mparse *);
static void resize_buf(struct buf *, size_t);
-static void mparse_buf_r(struct mparse *, struct buf, int);
+static void mparse_buf_r(struct mparse *, struct buf, size_t, int);
static int read_whole_file(struct mparse *, const char *, int,
struct buf *, int *);
static void mparse_end(struct mparse *);
MANDOCERR_WARNING,
MANDOCERR_WARNING,
MANDOCERR_ERROR,
- MANDOCERR_FATAL,
+ MANDOCERR_UNSUPP,
MANDOCERR_MAX,
MANDOCERR_MAX
};
"lower case character in document title",
"missing manual section, using \"\"",
"unknown manual section",
- "unknown manual volume or arch",
"missing date, using today's date",
"cannot parse date, using it verbatim",
"missing Os macro, using \"\"",
/* related to macros and nesting */
"obsolete macro",
+ "macro neither callable nor escaped",
"skipping paragraph macro",
"moving paragraph macro out of list",
"skipping no-space macro",
"empty list item",
"missing font type, using \\fR",
"unknown font type, using \\fR",
+ "nothing follows prefix",
"missing -std argument, adding it",
"missing eqn box, using \"\"",
"unexpected end of equation",
/* related to tables */
- "bad table syntax",
- "bad table option",
- "bad table layout",
+ "non-alphabetic character in tbl options",
+ "skipping unknown tbl option",
+ "missing tbl option argument",
+ "wrong tbl option argument size",
"no table layout cells specified",
"no table data cells specified",
"ignore data in cell",
"ignoring extra data cells",
/* related to document structure and macros */
+ NULL,
"input stack limit exceeded, infinite loop?",
"skipping bad character",
"skipping unknown macro",
+ "skipping insecure request",
"skipping item outside list",
"skipping column outside column list",
"skipping end of block that is not open",
+ "fewer RS blocks open, skipping",
"inserting missing end of block",
"appending missing end of block",
/* related to request and macro arguments */
"escaped character not allowed in a name",
"argument count wrong",
+ "NOT IMPLEMENTED: Bd -file",
"missing list type, using -item",
"missing manual name, using \"\"",
"uname(3) system call failed, using UNKNOWN",
"unknown standard specifier",
"skipping request without numeric argument",
+ "NOT IMPLEMENTED: .so with absolute path or \"..\"",
+ ".so request failed",
"skipping all arguments",
"skipping excess arguments",
+ "divide by zero",
- "generic fatal error",
-
+ "unsupported feature",
"input too large",
- "NOT IMPLEMENTED: Bd -file",
- "NOT IMPLEMENTED: .so with absolute path or \"..\"",
- ".so request failed",
-
- /* system errors */
- "cannot dup file descriptor",
- "cannot exec",
- "gunzip failed with code",
- "cannot fork",
- NULL,
- "cannot open pipe",
- "cannot read file",
- "gunzip died from signal",
- "cannot stat file",
- "wait failed",
+ "unsupported control character",
+ "unsupported roff request",
+ "unsupported table layout",
+ "ignoring macro in table",
};
static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
"RESERVED",
"WARNING",
"ERROR",
- "FATAL",
+ "UNSUPP",
"BADARG",
"SYSERR"
};
/* Fall back to man(7) as a last resort. */
if (NULL == curp->pman)
- curp->pman = man_alloc(curp->roff, curp,
+ curp->pman = man_alloc(
+ curp->roff, curp, curp->defos,
MPARSE_QUICK & curp->options ? 1 : 0);
assert(curp->pman);
curp->man = curp->pman;
}
/*
- * 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').
+ * Main parse routine for a buffer.
+ * It assumes encoding and line numbering are already set up.
+ * It can recurse directly (for invocations of user-defined
+ * macros, inline equations, and input line traps)
+ * and indirectly (for .so file inclusion).
*/
static void
-mparse_buf_r(struct mparse *curp, struct buf blk, int start)
+mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
{
const struct tbl_span *span;
struct buf ln;
+ const char *save_file;
+ char *cp;
+ size_t pos; /* byte number in the ln buffer */
enum rofferr rr;
- int i, of, rc;
- int pos; /* byte number in the ln buffer */
+ int of;
int lnn; /* line number in the real file */
+ int fd;
+ pid_t save_child;
unsigned char c;
- memset(&ln, 0, sizeof(struct buf));
+ memset(&ln, 0, sizeof(ln));
lnn = curp->line;
pos = 0;
- for (i = 0; i < (int)blk.sz; ) {
+ while (i < blk.sz) {
if (0 == pos && '\0' == blk.buf[i])
break;
if (start) {
curp->line = lnn;
curp->reparse_count = 0;
+
+ if (lnn < 3 &&
+ curp->filenc & MPARSE_UTF8 &&
+ curp->filenc & MPARSE_LATIN1)
+ curp->filenc = preconv_cue(&blk, i);
}
- while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) {
+ while (i < blk.sz && (start || blk.buf[i] != '\0')) {
/*
* When finding an unescaped newline character,
* Skip a preceding carriage return, if any.
*/
- if ('\r' == blk.buf[i] && i + 1 < (int)blk.sz &&
+ if ('\r' == blk.buf[i] && i + 1 < blk.sz &&
'\n' == blk.buf[i + 1])
++i;
if ('\n' == blk.buf[i]) {
}
/*
- * Make sure we have space for at least
- * one backslash and one other character
- * and the trailing NUL byte.
+ * Make sure we have space for the worst
+ * case of 11 bytes: "\\[u10ffff]\0"
*/
- if (pos + 2 >= (int)ln.sz)
+ if (pos + 11 > ln.sz)
resize_buf(&ln, 256);
/*
- * Warn about bogus characters. If you're using
- * non-ASCII encoding, you're screwing your
- * readers. Since I'd rather this not happen,
- * I'll be helpful and replace these characters
- * with "?", so we don't display gibberish.
- * Note to manual writers: use special characters.
+ * Encode 8-bit input.
*/
- c = (unsigned char) blk.buf[i];
+ c = blk.buf[i];
+ if (c & 0x80) {
+ if ( ! (curp->filenc && preconv_encode(
+ &blk, &i, &ln, &pos, &curp->filenc))) {
+ mandoc_vmsg(MANDOCERR_CHAR_BAD, curp,
+ curp->line, pos, "0x%x", c);
+ ln.buf[pos++] = '?';
+ i++;
+ }
+ continue;
+ }
- if ( ! (isascii(c) &&
- (isgraph(c) || isblank(c)))) {
- mandoc_vmsg(MANDOCERR_BADCHAR, curp,
- curp->line, pos, "0x%x", c);
+ /*
+ * Exclude control characters.
+ */
+
+ if (c == 0x7f || (c < 0x20 && c != 0x09)) {
+ mandoc_vmsg(c == 0x00 || c == 0x04 ||
+ c > 0x0a ? MANDOCERR_CHAR_BAD :
+ MANDOCERR_CHAR_UNSUPP,
+ curp, curp->line, pos, "0x%x", c);
i++;
ln.buf[pos++] = '?';
continue;
/* Trailing backslash = a plain char. */
- if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
+ if (blk.buf[i] != '\\' || i + 1 == blk.sz) {
ln.buf[pos++] = blk.buf[i++];
continue;
}
* skip that one as well.
*/
- if ('\r' == blk.buf[i + 1] && i + 2 < (int)blk.sz &&
+ if ('\r' == blk.buf[i + 1] && i + 2 < blk.sz &&
'\n' == blk.buf[i + 2])
++i;
if ('\n' == blk.buf[i + 1]) {
if ('"' == blk.buf[i + 1] || '#' == blk.buf[i + 1]) {
i += 2;
/* Comment, skip to end of line */
- for (; i < (int)blk.sz; ++i) {
+ for (; i < blk.sz; ++i) {
if ('\n' == blk.buf[i]) {
++i;
++lnn;
if ( ! (isascii(c) &&
(isgraph(c) || isblank(c)))) {
- mandoc_vmsg(MANDOCERR_BADCHAR, curp,
+ mandoc_vmsg(MANDOCERR_CHAR_BAD, curp,
curp->line, pos, "0x%x", c);
i += 2;
ln.buf[pos++] = '?';
ln.buf[pos++] = blk.buf[i++];
}
- if (pos >= (int)ln.sz)
+ if (pos >= ln.sz)
resize_buf(&ln, 256);
ln.buf[pos] = '\0';
[curp->secondary->sz] = '\0';
}
rerun:
- rr = roff_parseln(curp->roff, curp->line,
- &ln.buf, &ln.sz, of, &of);
+ rr = roff_parseln(curp->roff, curp->line, &ln, &of);
switch (rr) {
case ROFF_REPARSE:
if (REPARSE_LIMIT >= ++curp->reparse_count)
- mparse_buf_r(curp, ln, 0);
+ mparse_buf_r(curp, ln, of, 0);
else
mandoc_msg(MANDOCERR_ROFFLOOP, curp,
curp->line, pos, NULL);
pos = 0;
continue;
case ROFF_APPEND:
- pos = (int)strlen(ln.buf);
+ pos = strlen(ln.buf);
continue;
case ROFF_RERUN:
goto rerun;
case ROFF_IGN:
pos = 0;
continue;
- case ROFF_ERR:
- assert(MANDOCLEVEL_FATAL <= curp->file_status);
- break;
case ROFF_SO:
- if (0 == (MPARSE_SO & curp->options) &&
- (i >= (int)blk.sz || '\0' == blk.buf[i])) {
+ if ( ! (curp->options & MPARSE_SO) &&
+ (i >= blk.sz || blk.buf[i] == '\0')) {
curp->sodest = mandoc_strdup(ln.buf + of);
free(ln.buf);
return;
*/
if (curp->secondary)
curp->secondary->sz -= pos + 1;
- mparse_readfd(curp, -1, ln.buf + of);
- if (MANDOCLEVEL_FATAL <= curp->file_status) {
+ save_file = curp->file;
+ save_child = curp->child;
+ if (mparse_open(curp, &fd, ln.buf + of) ==
+ MANDOCLEVEL_OK) {
+ mparse_readfd(curp, fd, ln.buf + of);
+ curp->file = save_file;
+ } else {
+ curp->file = save_file;
mandoc_vmsg(MANDOCERR_SO_FAIL,
curp, curp->line, pos,
".so %s", ln.buf + of);
- break;
+ ln.sz = mandoc_asprintf(&cp,
+ ".sp\nSee the file %s.\n.sp",
+ ln.buf + of);
+ free(ln.buf);
+ ln.buf = cp;
+ of = 0;
+ mparse_buf_r(curp, ln, of, 0);
}
+ curp->child = save_child;
pos = 0;
continue;
default:
break;
}
- /*
- * If we encounter errors in the recursive parse, 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 between parsers, but set them
* Do the same for ROFF_EQN.
*/
- 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 (0 == rc) {
- assert(MANDOCLEVEL_FATAL <= curp->file_status);
- break;
- } else if (2 == rc)
- break;
+ if (rr == ROFF_TBL) {
+ while ((span = roff_span(curp->roff)) != NULL)
+ if (curp->man == NULL)
+ mdoc_addspan(curp->mdoc, span);
+ else
+ man_addspan(curp->man, span);
+ } else if (rr == ROFF_EQN) {
+ if (curp->man == NULL)
+ mdoc_addeqn(curp->mdoc, roff_eqn(curp->roff));
+ else
+ man_addeqn(curp->man, roff_eqn(curp->roff));
+ } else if ((curp->man == NULL ?
+ mdoc_parseln(curp->mdoc, curp->line, ln.buf, of) :
+ man_parseln(curp->man, curp->line, ln.buf, of)) == 2)
+ break;
/* Temporary buffers typically are not full. */
#if HAVE_MMAP
struct stat st;
if (-1 == fstat(fd, &st)) {
- curp->file_status = MANDOCLEVEL_SYSERR;
- if (curp->mmsg)
- (*curp->mmsg)(MANDOCERR_SYSSTAT, curp->file_status,
- file, 0, 0, strerror(errno));
- return(0);
+ perror(file);
+ exit((int)MANDOCLEVEL_SYSERR);
}
/*
if (S_ISREG(st.st_mode)) {
if (st.st_size >= (1U << 31)) {
- curp->file_status = MANDOCLEVEL_FATAL;
- if (curp->mmsg)
- (*curp->mmsg)(MANDOCERR_TOOLARGE,
- curp->file_status, file, 0, 0, NULL);
+ mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL);
return(0);
}
*with_mmap = 1;
for (;;) {
if (off == fb->sz) {
if (fb->sz == (1U << 31)) {
- curp->file_status = MANDOCLEVEL_FATAL;
- if (curp->mmsg)
- (*curp->mmsg)(MANDOCERR_TOOLARGE,
- curp->file_status,
- file, 0, 0, NULL);
+ mandoc_msg(MANDOCERR_TOOLARGE, curp,
+ 0, 0, NULL);
break;
}
resize_buf(fb, 65536);
return(1);
}
if (ssz == -1) {
- curp->file_status = MANDOCLEVEL_SYSERR;
- if (curp->mmsg)
- (*curp->mmsg)(MANDOCERR_SYSREAD,
- curp->file_status, file, 0, 0,
- strerror(errno));
- break;
+ perror(file);
+ exit((int)MANDOCLEVEL_SYSERR);
}
off += (size_t)ssz;
}
mparse_end(struct mparse *curp)
{
- if (MANDOCLEVEL_FATAL <= curp->file_status)
- return;
-
if (curp->mdoc == NULL &&
curp->man == NULL &&
curp->sodest == NULL) {
curp->mdoc = curp->pmdoc;
else {
if (curp->pman == NULL)
- curp->pman = man_alloc(curp->roff, curp,
+ curp->pman = man_alloc(
+ curp->roff, curp, curp->defos,
curp->options & MPARSE_QUICK ? 1 : 0);
curp->man = curp->pman;
}
}
-
- if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
- assert(MANDOCLEVEL_FATAL <= curp->file_status);
- return;
- }
-
- if (curp->man && ! man_endparse(curp->man)) {
- assert(MANDOCLEVEL_FATAL <= curp->file_status);
- return;
- }
-
+ if (curp->mdoc)
+ mdoc_endparse(curp->mdoc);
+ if (curp->man)
+ man_endparse(curp->man);
roff_endparse(curp->roff);
}
{
struct buf *svprimary;
const char *svfile;
+ size_t offset;
static int recursion_depth;
if (64 < recursion_depth) {
curp->line = 1;
recursion_depth++;
- mparse_buf_r(curp, blk, 1);
+ /* Skip an UTF-8 byte order mark. */
+ if (curp->filenc & MPARSE_UTF8 && blk.sz > 2 &&
+ (unsigned char)blk.buf[0] == 0xef &&
+ (unsigned char)blk.buf[1] == 0xbb &&
+ (unsigned char)blk.buf[2] == 0xbf) {
+ offset = 3;
+ curp->filenc &= ~MPARSE_LATIN1;
+ } else
+ offset = 0;
- if (0 == --recursion_depth && MANDOCLEVEL_FATAL > curp->file_status)
+ mparse_buf_r(curp, blk, offset, 1);
+
+ if (--recursion_depth == 0)
mparse_end(curp);
curp->primary = svprimary;
}
enum mandoclevel
-mparse_readmem(struct mparse *curp, const void *buf, size_t len,
+mparse_readmem(struct mparse *curp, void *buf, size_t len,
const char *file)
{
struct buf blk;
- blk.buf = UNCONST(buf);
+ blk.buf = buf;
blk.sz = len;
mparse_parse_buffer(curp, blk, file);
return(curp->file_status);
}
+/*
+ * Read the whole file into memory and call the parsers.
+ * Called recursively when an .so request is encountered.
+ */
enum mandoclevel
mparse_readfd(struct mparse *curp, int fd, const char *file)
{
struct buf blk;
int with_mmap;
-
- if (-1 == fd && -1 == (fd = open(file, O_RDONLY, 0))) {
- curp->file_status = MANDOCLEVEL_SYSERR;
- if (curp->mmsg)
- (*curp->mmsg)(MANDOCERR_SYSOPEN,
- curp->file_status,
- file, 0, 0, strerror(errno));
- return(curp->file_status);
- }
-
- /*
- * 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.
- */
+ int save_filenc;
if (read_whole_file(curp, file, fd, &blk, &with_mmap)) {
+ save_filenc = curp->filenc;
+ curp->filenc = curp->options &
+ (MPARSE_UTF8 | MPARSE_LATIN1);
mparse_parse_buffer(curp, blk, file);
+ curp->filenc = save_filenc;
#if HAVE_MMAP
if (with_mmap)
munmap(blk.buf, blk.sz);
free(blk.buf);
}
- if (STDIN_FILENO != fd && -1 == close(fd))
+ if (fd != STDIN_FILENO && close(fd) == -1)
perror(file);
+ mparse_wait(curp);
return(curp->file_status);
}
enum mandoclevel
-mparse_open(struct mparse *curp, int *fd, const char *file,
- pid_t *child_pid)
+mparse_open(struct mparse *curp, int *fd, const char *file)
{
int pfd[2];
+ int save_errno;
char *cp;
- enum mandocerr err;
- pfd[1] = -1;
curp->file = file;
+
+ /* Unless zipped, try to just open the file. */
+
if ((cp = strrchr(file, '.')) == NULL ||
strcmp(cp + 1, "gz")) {
- *child_pid = 0;
- if ((*fd = open(file, O_RDONLY)) == -1) {
- err = MANDOCERR_SYSOPEN;
- goto out;
- }
- return(MANDOCLEVEL_OK);
+ curp->child = 0;
+ if ((*fd = open(file, O_RDONLY)) != -1)
+ return(MANDOCLEVEL_OK);
+
+ /* Open failed; try to append ".gz". */
+
+ mandoc_asprintf(&cp, "%s.gz", file);
+ file = cp;
+ } else
+ cp = NULL;
+
+ /* Before forking, make sure the file can be read. */
+
+ save_errno = errno;
+ if (access(file, R_OK) == -1) {
+ if (cp != NULL)
+ errno = save_errno;
+ free(cp);
+ *fd = -1;
+ curp->child = 0;
+ mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno));
+ return(MANDOCLEVEL_ERROR);
}
+ /* Run gunzip(1). */
+
if (pipe(pfd) == -1) {
- err = MANDOCERR_SYSPIPE;
- goto out;
+ perror("pipe");
+ exit((int)MANDOCLEVEL_SYSERR);
}
- switch (*child_pid = fork()) {
+ switch (curp->child = fork()) {
case -1:
- err = MANDOCERR_SYSFORK;
- close(pfd[0]);
- close(pfd[1]);
- pfd[1] = -1;
- break;
+ perror("fork");
+ exit((int)MANDOCLEVEL_SYSERR);
case 0:
close(pfd[0]);
if (dup2(pfd[1], STDOUT_FILENO) == -1) {
- err = MANDOCERR_SYSDUP;
- break;
+ perror("dup");
+ exit((int)MANDOCLEVEL_SYSERR);
}
execlp("gunzip", "gunzip", "-c", file, NULL);
- err = MANDOCERR_SYSEXEC;
- break;
+ perror("exec");
+ exit((int)MANDOCLEVEL_SYSERR);
default:
close(pfd[1]);
*fd = pfd[0];
return(MANDOCLEVEL_OK);
}
-
-out:
- *fd = -1;
- *child_pid = 0;
- curp->file_status = MANDOCLEVEL_SYSERR;
- if (curp->mmsg)
- (*curp->mmsg)(err, curp->file_status, file,
- 0, 0, strerror(errno));
- if (pfd[1] != -1)
- exit(1);
- return(curp->file_status);
}
enum mandoclevel
-mparse_wait(struct mparse *curp, pid_t child_pid)
+mparse_wait(struct mparse *curp)
{
int status;
- if (waitpid(child_pid, &status, 0) == -1) {
- mandoc_msg(MANDOCERR_SYSWAIT, curp, 0, 0,
- strerror(errno));
- curp->file_status = MANDOCLEVEL_SYSERR;
- return(curp->file_status);
+ if (curp->child == 0)
+ return(MANDOCLEVEL_OK);
+
+ if (waitpid(curp->child, &status, 0) == -1) {
+ perror("wait");
+ exit((int)MANDOCLEVEL_SYSERR);
}
if (WIFSIGNALED(status)) {
- mandoc_vmsg(MANDOCERR_SYSSIG, curp, 0, 0,
- "%d", WTERMSIG(status));
- curp->file_status = MANDOCLEVEL_SYSERR;
- return(curp->file_status);
+ mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
+ "gunzip died from signal %d", WTERMSIG(status));
+ return(MANDOCLEVEL_ERROR);
}
if (WEXITSTATUS(status)) {
- mandoc_vmsg(MANDOCERR_SYSEXIT, curp, 0, 0,
- "%d", WEXITSTATUS(status));
- curp->file_status = MANDOCLEVEL_SYSERR;
- return(curp->file_status);
+ mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
+ "gunzip failed with code %d", WEXITSTATUS(status));
+ return(MANDOCLEVEL_ERROR);
}
return(MANDOCLEVEL_OK);
}
struct mparse *
-mparse_alloc(int options, enum mandoclevel wlevel,
- mandocmsg mmsg, const char *defos)
+mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
+ const struct mchars *mchars, const char *defos)
{
struct mparse *curp;
- assert(wlevel <= MANDOCLEVEL_FATAL);
-
curp = mandoc_calloc(1, sizeof(struct mparse));
curp->options = options;
curp->mmsg = mmsg;
curp->defos = defos;
- curp->roff = roff_alloc(curp, options);
+ curp->mchars = mchars;
+ curp->roff = roff_alloc(curp, curp->mchars, options);
if (curp->options & MPARSE_MDOC)
curp->pmdoc = mdoc_alloc(
curp->roff, curp, curp->defos,
curp->options & MPARSE_QUICK ? 1 : 0);
if (curp->options & MPARSE_MAN)
- curp->pman = man_alloc(curp->roff, curp,
+ curp->pman = man_alloc(
+ curp->roff, curp, curp->defos,
curp->options & MPARSE_QUICK ? 1 : 0);
return(curp);
{
enum mandoclevel level;
- level = MANDOCLEVEL_FATAL;
+ level = MANDOCLEVEL_UNSUPP;
while (er < mandoclimits[level])
level--;
- if (level < m->wlevel)
+ if (level < m->wlevel && er != MANDOCERR_FILE)
return;
if (m->mmsg)