]> git.cameronkatri.com Git - mandoc.git/blobdiff - read.c
Add *.gz support to apropos(1) -a, man(1), and even mandoc(1).
[mandoc.git] / read.c
diff --git a/read.c b/read.c
index cf568077d922ad107c9dd9986d45a0ab674126f3..3b9ce545377620e1c6e88aa25cdf69de3e35702d 100644 (file)
--- a/read.c
+++ b/read.c
@@ -1,4 +1,4 @@
-/*     $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>
@@ -93,16 +93,19 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "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)",
@@ -123,8 +126,8 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "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 */
@@ -136,7 +139,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "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",
@@ -144,11 +147,12 @@ static    const char * const      mandocerrs[MANDOCERR_MAX] = {
        "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",
@@ -185,6 +189,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "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",
@@ -193,31 +198,32 @@ static    const char * const      mandocerrs[MANDOCERR_MAX] = {
        /* 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] = {
@@ -264,18 +270,9 @@ pset(const char *buf, int pos, struct mparse *curp)
        }
 
        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;
        }
@@ -366,8 +363,8 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
 
                        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;
@@ -423,8 +420,8 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
 
                        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;
@@ -601,7 +598,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
        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;
@@ -683,6 +680,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;
@@ -693,12 +703,6 @@ mparse_end(struct mparse *curp)
                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);
 }
 
@@ -767,7 +771,7 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
 
        mparse_parse_buffer(curp, blk, file);
 
-#ifdef HAVE_MMAP
+#if HAVE_MMAP
        if (with_mmap)
                munmap(blk.buf, blk.sz);
        else
@@ -780,6 +784,91 @@ out:
        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)
@@ -796,6 +885,14 @@ mparse_alloc(int options, enum mandoclevel wlevel,
        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);
 }