]> 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 0c8f6eac0ef65feaa29974a06d076b3f4ecaffc7..3b9ce545377620e1c6e88aa25cdf69de3e35702d 100644 (file)
--- a/read.c
+++ b/read.c
@@ -1,4 +1,4 @@
-/*     $Id: read.c,v 1.81 2014/08/16 19:00:01 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>
 
 #include <sys/types.h>
 #if HAVE_MMAP
-#include <sys/stat.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
 #endif
+#include <sys/wait.h>
 
 #include <assert.h>
 #include <ctype.h>
@@ -213,9 +214,16 @@ static     const char * const      mandocerrs[MANDOCERR_MAX] = {
        ".so request failed",
 
        /* 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] = {
@@ -776,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)