-/* $Id: read.c,v 1.70 2014/07/30 00:19:16 schwarze Exp $ */
+/* $Id: read.c,v 1.82 2014/09/03 23:21:47 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#ifdef HAVE_MMAP
-# include <sys/stat.h>
-# include <sys/mman.h>
+#include <sys/types.h>
+#if HAVE_MMAP
+#include <sys/mman.h>
+#include <sys/stat.h>
#endif
+#include <sys/wait.h>
#include <assert.h>
#include <ctype.h>
"generic warning",
/* related to the prologue */
- "missing .TH macro, using \"unknown 1\"",
+ "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",
"missing date, using today's date",
"cannot parse date, using it verbatim",
- "prologue macros out of order",
+ "missing Os macro, using \"\"",
"duplicate prologue macro",
- "incomplete prologue, terminated by",
- "skipping prologue macro 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)",
"nested displays are not portable",
"moving content out of list",
".Vt block has child macro",
- "fill mode already enabled, skipping .fi",
- "fill mode already disabled, skipping .nf",
+ "fill mode already enabled, skipping",
+ "fill mode already disabled, skipping",
"line scope broken",
/* related to missing macro arguments */
"missing display type, using -ragged",
"list type is not the first argument",
"missing -width in -tag list, using 8n",
- "missing name for .Ex, using \"\"",
+ "missing utility name, using \"\"",
"empty head in list item",
"empty list item",
"missing font type, using \\fR",
"missing -std argument, adding it",
/* related to bad macro arguments */
- "skipping argument",
"unterminated quoted argument",
"duplicate argument",
+ "skipping duplicate argument",
"skipping duplicate display type",
"skipping duplicate list type",
+ "skipping -width argument",
"unknown AT&T UNIX version",
"invalid content in Rs block",
"invalid Boolean argument",
"input stack limit exceeded, infinite loop?",
"skipping bad character",
"skipping unknown macro",
+ "skipping item outside list",
"skipping column outside column list",
"skipping end of block that is not open",
"inserting 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",
- "uname(3) system call failed",
- "request requires a numeric argument",
- "missing list type, using -item",
+ "skipping request without numeric argument",
"skipping all arguments",
"skipping excess arguments",
"generic fatal error",
"input too large",
- "not a manual",
- "column syntax is inconsistent",
- "NOT IMPLEMENTED: .Bd -file",
- "child violates parent syntax",
- "argument count wrong, violates syntax",
+ "NOT IMPLEMENTED: Bd -file",
"NOT IMPLEMENTED: .so with absolute path or \"..\"",
".so request failed",
- "no document prologue",
- "static buffer exhausted",
/* system errors */
+ "cannot dup file descriptor",
+ "cannot exec",
+ "gunzip failed with code",
+ "cannot fork",
NULL,
- "cannot stat file",
+ "cannot open pipe",
"cannot read file",
+ "gunzip died from signal",
+ "cannot stat file",
+ "wait failed",
};
static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
}
if (MPARSE_MDOC & curp->options) {
- 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;
} else if (MPARSE_MAN & curp->options) {
- if (NULL == curp->pman)
- curp->pman = man_alloc(curp->roff, curp,
- MPARSE_QUICK & curp->options ? 1 : 0);
- assert(curp->pman);
curp->man = curp->pman;
return;
}
if ( ! (isascii(c) &&
(isgraph(c) || isblank(c)))) {
- mandoc_msg(MANDOCERR_BADCHAR, curp,
- curp->line, pos, NULL);
+ mandoc_vmsg(MANDOCERR_BADCHAR, curp,
+ curp->line, pos, "0x%x", c);
i++;
ln.buf[pos++] = '?';
continue;
if ( ! (isascii(c) &&
(isgraph(c) || isblank(c)))) {
- mandoc_msg(MANDOCERR_BADCHAR, curp,
- curp->line, pos, NULL);
+ mandoc_vmsg(MANDOCERR_BADCHAR, curp,
+ curp->line, pos, "0x%x", c);
i += 2;
ln.buf[pos++] = '?';
continue;
size_t off;
ssize_t ssz;
-#ifdef HAVE_MMAP
+#if HAVE_MMAP
struct stat st;
if (-1 == fstat(fd, &st)) {
curp->file_status = MANDOCLEVEL_SYSERR;
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;
return;
}
- if ( ! (curp->mdoc || curp->man || curp->sodest)) {
- mandoc_msg(MANDOCERR_NOTMANUAL, curp, 0, 0, NULL);
- curp->file_status = MANDOCLEVEL_FATAL;
- return;
- }
-
roff_endparse(curp->roff);
}
mparse_parse_buffer(curp, blk, file);
-#ifdef HAVE_MMAP
+#if HAVE_MMAP
if (with_mmap)
munmap(blk.buf, blk.sz);
else
return(curp->file_status);
}
+enum mandoclevel
+mparse_open(struct mparse *curp, int *fd, const char *file,
+ pid_t *child_pid)
+{
+ int pfd[2];
+ char *cp;
+ enum mandocerr err;
+
+ pfd[1] = -1;
+ curp->file = 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);
+ }
+
+ if (pipe(pfd) == -1) {
+ err = MANDOCERR_SYSPIPE;
+ goto out;
+ }
+
+ switch (*child_pid = fork()) {
+ case -1:
+ err = MANDOCERR_SYSFORK;
+ close(pfd[0]);
+ close(pfd[1]);
+ pfd[1] = -1;
+ break;
+ case 0:
+ close(pfd[0]);
+ if (dup2(pfd[1], STDOUT_FILENO) == -1) {
+ err = MANDOCERR_SYSDUP;
+ break;
+ }
+ execlp("gunzip", "gunzip", "-c", file, NULL);
+ err = MANDOCERR_SYSEXEC;
+ break;
+ 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)
+{
+ 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 (WIFSIGNALED(status)) {
+ mandoc_vmsg(MANDOCERR_SYSSIG, curp, 0, 0,
+ "%d", WTERMSIG(status));
+ curp->file_status = MANDOCLEVEL_SYSERR;
+ return(curp->file_status);
+ }
+ if (WEXITSTATUS(status)) {
+ mandoc_vmsg(MANDOCERR_SYSEXIT, curp, 0, 0,
+ "%d", WEXITSTATUS(status));
+ curp->file_status = MANDOCLEVEL_SYSERR;
+ return(curp->file_status);
+ }
+ return(MANDOCLEVEL_OK);
+}
+
struct mparse *
mparse_alloc(int options, enum mandoclevel wlevel,
mandocmsg mmsg, const char *defos)
curp->defos = defos;
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);
}