summaryrefslogtreecommitdiffstats
path: root/read.c
diff options
context:
space:
mode:
authorbapt <bapt@FreeBSD.org>2014-11-22 18:08:25 +0000
committerbapt <bapt@FreeBSD.org>2014-11-22 18:08:25 +0000
commiteb03421ddbdfb35eb3ab61dbe59c906ce9e5db96 (patch)
tree7ef9f92f249a503d1c005f88d483481725db364a /read.c
parentb49854de09bb4b52f85ad49a19474ae51aa6a33d (diff)
downloadFreeBSD-src-eb03421ddbdfb35eb3ab61dbe59c906ce9e5db96.zip
FreeBSD-src-eb03421ddbdfb35eb3ab61dbe59c906ce9e5db96.tar.gz
Import mandoc 1.13.1
Diffstat (limited to 'read.c')
-rw-r--r--read.c365
1 files changed, 211 insertions, 154 deletions
diff --git a/read.c b/read.c
index 511ba7d..9466838 100644
--- a/read.c
+++ b/read.c
@@ -1,7 +1,8 @@
-/* $Id: read.c,v 1.39 2013/09/16 00:25:07 schwarze Exp $ */
+/* $Id: read.c,v 1.79 2014/08/06 15:09:05 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2014 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
* purpose with or without fee is hereby granted, provided that the above
@@ -26,6 +27,7 @@
#include <assert.h>
#include <ctype.h>
+#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdint.h>
@@ -35,6 +37,7 @@
#include <unistd.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#include "mdoc.h"
#include "man.h"
@@ -43,7 +46,7 @@
#define REPARSE_LIMIT 1000
struct buf {
- char *buf; /* binary input buffer */
+ char *buf; /* binary input buffer */
size_t sz; /* size of binary buffer */
};
@@ -51,24 +54,25 @@ struct mparse {
enum mandoclevel file_status; /* status of current parse */
enum mandoclevel wlevel; /* ignore messages below this */
int line; /* line number in the file */
- enum mparset inttype; /* which parser to use */
+ int options; /* parser options */
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) */
+ char *sodest; /* filename pointed to by .so */
int reparse_count; /* finite interp. stack */
mandocmsg mmsg; /* warning/error message handler */
- void *arg; /* argument to mmsg */
- const char *file;
+ const char *file;
struct buf *secondary;
- char *defos; /* default operating system */
+ const char *defos; /* default operating system */
};
static void resize_buf(struct buf *, size_t);
static void mparse_buf_r(struct mparse *, struct buf, int);
static void pset(const char *, int, struct mparse *);
-static int read_whole_file(const char *, int, struct buf *, int *);
+static int read_whole_file(struct mparse *, const char *, int,
+ struct buf *, int *);
static void mparse_end(struct mparse *);
static void mparse_parse_buffer(struct mparse *, struct buf,
const char *);
@@ -89,67 +93,79 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"generic warning",
/* related to the prologue */
- "no title in document",
- "document title should be all caps",
+ "missing manual title, using UNTITLED",
+ "missing manual title, using \"\"",
+ "lower case character in document title",
+ "missing manual section, using \"\"",
"unknown manual section",
"unknown manual volume or arch",
- "date missing, using today's date",
+ "missing date, using today's date",
"cannot parse date, using it verbatim",
- "prologue macros out of order",
+ "missing Os macro, using \"\"",
"duplicate prologue macro",
- "macro not allowed in prologue",
- "macro not allowed in body",
+ "late prologue macro",
+ "skipping late title macro",
+ "prologue macros out of order",
/* related to document structure */
".so is fragile, better use ln(1)",
- "NAME section must come first",
+ "no document body",
+ "content before first section header",
+ "first section is not \"NAME\"",
"bad NAME section contents",
"sections out of conventional order",
- "duplicate section name",
- "section header suited to sections 2, 3, and 9 only",
+ "duplicate section title",
+ "unexpected section",
/* related to macros and nesting */
- "skipping obsolete macro",
+ "obsolete macro",
"skipping paragraph macro",
"moving paragraph macro out of list",
"skipping no-space macro",
"blocks badly nested",
- "child violates parent syntax",
"nested displays are not portable",
- "already in literal mode",
+ "moving content out of list",
+ ".Vt block has child macro",
+ "fill mode already enabled, skipping",
+ "fill mode already disabled, skipping",
"line scope broken",
/* related to missing macro arguments */
+ "skipping empty request",
+ "conditional request controls empty scope",
"skipping empty macro",
+ "empty argument, using 0n",
"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",
+ "missing display type, using -ragged",
+ "list type is not the first argument",
+ "missing -width in -tag list, using 8n",
+ "missing utility name, using \"\"",
+ "empty head in list item",
+ "empty list item",
+ "missing font type, using \\fR",
+ "unknown font type, using \\fR",
+ "missing -std argument, adding it",
/* related to bad macro arguments */
- "skipping argument",
+ "unterminated quoted argument",
"duplicate argument",
- "duplicate display type",
- "duplicate list type",
+ "skipping duplicate argument",
+ "skipping duplicate display type",
+ "skipping duplicate list type",
+ "skipping -width argument",
"unknown AT&T UNIX version",
- "bad Boolean value",
- "unknown font",
- "unknown standard specifier",
- "bad width argument",
+ "invalid content in Rs block",
+ "invalid Boolean argument",
+ "unknown font, skipping request",
/* related to plain text */
- "blank line in non-literal context",
- "tab in non-literal context",
- "end of line whitespace",
+ "blank line in fill mode, using .sp",
+ "tab in filled text",
+ "whitespace at end of input line",
"bad comment style",
- "bad escape sequence",
- "unterminated quoted string",
+ "invalid escape sequence",
+ "undefined string, using \"\"",
- /* related to equations */
- "unexpected literal in equation",
-
"generic error",
/* related to equations */
@@ -169,39 +185,38 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"data block still open",
"ignoring extra data cells",
+ /* related to document structure and macros */
"input stack limit exceeded, infinite loop?",
"skipping bad character",
- "escaped character not allowed in a name",
- "manual name not yet set",
- "skipping text before the first section header",
"skipping unknown macro",
- "NOT IMPLEMENTED, please use groff: skipping request",
- "argument count wrong",
+ "skipping item outside list",
"skipping column outside column list",
"skipping end of block that is not open",
- "missing end of block",
- "scope open on exit",
- "uname(3) system call failed",
- "macro requires line argument(s)",
- "macro requires body argument(s)",
- "macro requires argument(s)",
- "request requires a numeric argument",
- "missing list type",
- "line argument(s) will be lost",
- "body argument(s) will be lost",
+ "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",
+ "missing list type, using -item",
+ "missing manual name, using \"\"",
+ "uname(3) system call failed, using UNKNOWN",
+ "unknown standard specifier",
+ "skipping request without numeric argument",
+ "skipping all arguments",
+ "skipping excess arguments",
"generic fatal error",
- "not a manual",
- "column syntax is inconsistent",
- "NOT IMPLEMENTED: .Bd -file",
- "argument count wrong, violates syntax",
- "child violates parent syntax",
- "argument count wrong, violates syntax",
+ "input too large",
+ "NOT IMPLEMENTED: Bd -file",
"NOT IMPLEMENTED: .so with absolute path or \"..\"",
- "no document body",
- "no document prologue",
- "static buffer exhausted",
+ ".so request failed",
+
+ /* system errors */
+ NULL,
+ "cannot stat file",
+ "cannot read file",
};
static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
@@ -214,6 +229,7 @@ static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
"SYSERR"
};
+
static void
resize_buf(struct buf *buf, size_t initial)
{
@@ -246,35 +262,27 @@ pset(const char *buf, int pos, struct mparse *curp)
return;
}
- switch (curp->inttype) {
- case (MPARSE_MDOC):
- if (NULL == curp->pmdoc)
- curp->pmdoc = mdoc_alloc(curp->roff, curp,
- curp->defos);
- assert(curp->pmdoc);
+ if (MPARSE_MDOC & curp->options) {
curp->mdoc = curp->pmdoc;
return;
- case (MPARSE_MAN):
- if (NULL == curp->pman)
- curp->pman = man_alloc(curp->roff, curp);
- assert(curp->pman);
+ } else if (MPARSE_MAN & curp->options) {
curp->man = curp->pman;
return;
- default:
- break;
}
if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) {
- if (NULL == curp->pmdoc)
- curp->pmdoc = mdoc_alloc(curp->roff, curp,
- curp->defos);
+ if (NULL == curp->pmdoc)
+ curp->pmdoc = mdoc_alloc(
+ curp->roff, curp, curp->defos,
+ MPARSE_QUICK & curp->options ? 1 : 0);
assert(curp->pmdoc);
curp->mdoc = curp->pmdoc;
return;
- }
+ }
- if (NULL == curp->pman)
- curp->pman = man_alloc(curp->roff, curp);
+ if (NULL == curp->pman)
+ curp->pman = man_alloc(curp->roff, curp,
+ MPARSE_QUICK & curp->options ? 1 : 0);
assert(curp->pman);
curp->man = curp->pman;
}
@@ -297,8 +305,8 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
memset(&ln, 0, sizeof(struct buf));
- lnn = curp->line;
- pos = 0;
+ lnn = curp->line;
+ pos = 0;
for (i = 0; i < (int)blk.sz; ) {
if (0 == pos && '\0' == blk.buf[i])
@@ -335,7 +343,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
if (pos + 2 >= (int)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,
@@ -346,10 +354,10 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
c = (unsigned char) blk.buf[i];
- if ( ! (isascii(c) &&
- (isgraph(c) || isblank(c)))) {
- mandoc_msg(MANDOCERR_BADCHAR, curp,
- curp->line, pos, NULL);
+ if ( ! (isascii(c) &&
+ (isgraph(c) || isblank(c)))) {
+ mandoc_vmsg(MANDOCERR_BADCHAR, curp,
+ curp->line, pos, "0x%x", c);
i++;
ln.buf[pos++] = '?';
continue;
@@ -403,10 +411,10 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
c = (unsigned char) blk.buf[i+1];
- if ( ! (isascii(c) &&
- (isgraph(c) || isblank(c)))) {
- mandoc_msg(MANDOCERR_BADCHAR, curp,
- curp->line, pos, NULL);
+ if ( ! (isascii(c) &&
+ (isgraph(c) || isblank(c)))) {
+ mandoc_vmsg(MANDOCERR_BADCHAR, curp,
+ curp->line, pos, "0x%x", c);
i += 2;
ln.buf[pos++] = '?';
continue;
@@ -418,7 +426,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
ln.buf[pos++] = blk.buf[i++];
}
- if (pos >= (int)ln.sz)
+ if (pos >= (int)ln.sz)
resize_buf(&ln, 256);
ln.buf[pos] = '\0';
@@ -441,13 +449,12 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
*/
if (curp->secondary) {
- curp->secondary->buf =
- mandoc_realloc
- (curp->secondary->buf,
- curp->secondary->sz + pos + 2);
- memcpy(curp->secondary->buf +
- curp->secondary->sz,
- ln.buf, pos);
+ curp->secondary->buf = mandoc_realloc(
+ curp->secondary->buf,
+ curp->secondary->sz + pos + 2);
+ memcpy(curp->secondary->buf +
+ curp->secondary->sz,
+ ln.buf, pos);
curp->secondary->sz += pos;
curp->secondary->buf
[curp->secondary->sz] = '\n';
@@ -456,41 +463,50 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
[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.buf, &ln.sz, of, &of);
switch (rr) {
- case (ROFF_REPARSE):
+ case ROFF_REPARSE:
if (REPARSE_LIMIT >= ++curp->reparse_count)
mparse_buf_r(curp, ln, 0);
else
mandoc_msg(MANDOCERR_ROFFLOOP, curp,
- curp->line, pos, NULL);
+ curp->line, pos, NULL);
pos = 0;
continue;
- case (ROFF_APPEND):
+ case ROFF_APPEND:
pos = (int)strlen(ln.buf);
continue;
- case (ROFF_RERUN):
+ case ROFF_RERUN:
goto rerun;
- case (ROFF_IGN):
+ case ROFF_IGN:
pos = 0;
continue;
- case (ROFF_ERR):
+ case ROFF_ERR:
assert(MANDOCLEVEL_FATAL <= curp->file_status);
break;
- case (ROFF_SO):
+ case ROFF_SO:
+ if (0 == (MPARSE_SO & curp->options) &&
+ (i >= (int)blk.sz || '\0' == blk.buf[i])) {
+ curp->sodest = mandoc_strdup(ln.buf + of);
+ free(ln.buf);
+ return;
+ }
/*
* We remove `so' clauses from our lookaside
* buffer because we're going to descend into
* the file recursively.
*/
- if (curp->secondary)
+ if (curp->secondary)
curp->secondary->sz -= pos + 1;
mparse_readfd(curp, -1, ln.buf + of);
- if (MANDOCLEVEL_FATAL <= curp->file_status)
+ if (MANDOCLEVEL_FATAL <= curp->file_status) {
+ mandoc_vmsg(MANDOCERR_SO_FAIL,
+ curp, curp->line, pos,
+ ".so %s", ln.buf + of);
break;
+ }
pos = 0;
continue;
default:
@@ -515,7 +531,7 @@ rerun:
if ( ! (curp->man || curp->mdoc))
pset(ln.buf + of, pos - of, curp);
- /*
+ /*
* Lastly, push down into the parsers themselves. One
* of these will have already been set in the pset()
* routine.
@@ -531,28 +547,29 @@ rerun:
if (ROFF_TBL == rr)
while (NULL != (span = roff_span(curp->roff))) {
rc = curp->man ?
- man_addspan(curp->man, span) :
- mdoc_addspan(curp->mdoc, span);
+ 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));
+ 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);
+ 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;
/* Temporary buffers typically are not full. */
@@ -568,7 +585,8 @@ rerun:
}
static int
-read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
+read_whole_file(struct mparse *curp, const char *file, int fd,
+ struct buf *fb, int *with_mmap)
{
size_t off;
ssize_t ssz;
@@ -576,7 +594,10 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
#ifdef HAVE_MMAP
struct stat st;
if (-1 == fstat(fd, &st)) {
- perror(file);
+ curp->file_status = MANDOCLEVEL_SYSERR;
+ if (curp->mmsg)
+ (*curp->mmsg)(MANDOCERR_SYSSTAT, curp->file_status,
+ file, 0, 0, strerror(errno));
return(0);
}
@@ -589,7 +610,10 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
if (S_ISREG(st.st_mode)) {
if (st.st_size >= (1U << 31)) {
- fprintf(stderr, "%s: input too large\n", file);
+ curp->file_status = MANDOCLEVEL_FATAL;
+ if (curp->mmsg)
+ (*curp->mmsg)(MANDOCERR_TOOLARGE,
+ curp->file_status, file, 0, 0, NULL);
return(0);
}
*with_mmap = 1;
@@ -612,7 +636,11 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
for (;;) {
if (off == fb->sz) {
if (fb->sz == (1U << 31)) {
- fprintf(stderr, "%s: input too large\n", file);
+ curp->file_status = MANDOCLEVEL_FATAL;
+ if (curp->mmsg)
+ (*curp->mmsg)(MANDOCERR_TOOLARGE,
+ curp->file_status,
+ file, 0, 0, NULL);
break;
}
resize_buf(fb, 65536);
@@ -623,7 +651,11 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
return(1);
}
if (ssz == -1) {
- perror(file);
+ curp->file_status = MANDOCLEVEL_SYSERR;
+ if (curp->mmsg)
+ (*curp->mmsg)(MANDOCERR_SYSREAD,
+ curp->file_status, file, 0, 0,
+ strerror(errno));
break;
}
off += (size_t)ssz;
@@ -641,6 +673,19 @@ mparse_end(struct mparse *curp)
if (MANDOCLEVEL_FATAL <= curp->file_status)
return;
+ if (curp->mdoc == NULL &&
+ curp->man == NULL &&
+ curp->sodest == NULL) {
+ if (curp->options & MPARSE_MDOC)
+ curp->mdoc = curp->pmdoc;
+ else {
+ if (curp->pman == NULL)
+ curp->pman = man_alloc(curp->roff, curp,
+ curp->options & MPARSE_QUICK ? 1 : 0);
+ curp->man = curp->pman;
+ }
+ }
+
if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
assert(MANDOCLEVEL_FATAL <= curp->file_status);
return;
@@ -651,12 +696,6 @@ mparse_end(struct mparse *curp)
return;
}
- if ( ! (curp->man || curp->mdoc)) {
- mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL);
- curp->file_status = MANDOCLEVEL_FATAL;
- return;
- }
-
roff_endparse(curp->roff);
}
@@ -704,12 +743,15 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
struct buf blk;
int with_mmap;
- if (-1 == fd)
- if (-1 == (fd = open(file, O_RDONLY, 0))) {
- perror(file);
- curp->file_status = MANDOCLEVEL_SYSERR;
- goto out;
- }
+ 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));
+ goto out;
+ }
+
/*
* Run for each opened file; may be called more than once for
* each full parse sequence if the opened file is nested (i.e.,
@@ -717,10 +759,8 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
* the parse phase for the file.
*/
- if ( ! read_whole_file(file, fd, &blk, &with_mmap)) {
- curp->file_status = MANDOCLEVEL_SYSERR;
+ if ( ! read_whole_file(curp, file, fd, &blk, &with_mmap))
goto out;
- }
mparse_parse_buffer(curp, blk, file);
@@ -738,8 +778,8 @@ out:
}
struct mparse *
-mparse_alloc(enum mparset inttype, enum mandoclevel wlevel,
- mandocmsg mmsg, void *arg, char *defos)
+mparse_alloc(int options, enum mandoclevel wlevel,
+ mandocmsg mmsg, const char *defos)
{
struct mparse *curp;
@@ -747,13 +787,20 @@ mparse_alloc(enum mparset inttype, enum mandoclevel wlevel,
curp = mandoc_calloc(1, sizeof(struct mparse));
+ curp->options = options;
curp->wlevel = wlevel;
curp->mmsg = mmsg;
- curp->arg = arg;
- curp->inttype = inttype;
curp->defos = defos;
- curp->roff = roff_alloc(inttype, curp);
+ curp->roff = roff_alloc(curp, 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->options & MPARSE_QUICK ? 1 : 0);
+
return(curp);
}
@@ -773,6 +820,9 @@ mparse_reset(struct mparse *curp)
curp->file_status = MANDOCLEVEL_OK;
curp->mdoc = NULL;
curp->man = NULL;
+
+ free(curp->sodest);
+ curp->sodest = NULL;
}
void
@@ -789,13 +839,20 @@ mparse_free(struct mparse *curp)
free(curp->secondary->buf);
free(curp->secondary);
+ free(curp->sodest);
free(curp);
}
void
-mparse_result(struct mparse *curp, struct mdoc **mdoc, struct man **man)
+mparse_result(struct mparse *curp,
+ struct mdoc **mdoc, struct man **man, char **sodest)
{
+ if (sodest && NULL != (*sodest = curp->sodest)) {
+ *mdoc = NULL;
+ *man = NULL;
+ return;
+ }
if (mdoc)
*mdoc = curp->mdoc;
if (man)
@@ -810,14 +867,14 @@ mandoc_vmsg(enum mandocerr t, struct mparse *m,
va_list ap;
va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
+ (void)vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
mandoc_msg(t, m, ln, pos, buf);
}
void
-mandoc_msg(enum mandocerr er, struct mparse *m,
+mandoc_msg(enum mandocerr er, struct mparse *m,
int ln, int col, const char *msg)
{
enum mandoclevel level;
OpenPOWER on IntegriCloud