summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2014-09-03 23:21:47 +0000
committerIngo Schwarze <schwarze@openbsd.org>2014-09-03 23:21:47 +0000
commit34ba2d164c86804e434dc4199679b9611f18710a (patch)
tree08978b0ed256dd3adc9f4dfed4cb45a288df19cd
parentc770387f803c840900502ca28d15d35e99650baf (diff)
downloadmandoc-34ba2d164c86804e434dc4199679b9611f18710a.tar.gz
Add *.gz support to apropos(1) -a, man(1), and even mandoc(1).
Implemented by moving the zip code from makewhatis(8) to the parser lib.
-rw-r--r--main.c35
-rw-r--r--mandoc.362
-rw-r--r--mandoc.h12
-rw-r--r--mandocdb.c69
-rw-r--r--read.c97
5 files changed, 205 insertions, 70 deletions
diff --git a/main.c b/main.c
index 5a7db15e..9e896fd3 100644
--- a/main.c
+++ b/main.c
@@ -87,7 +87,7 @@ static void mmsg(enum mandocerr, enum mandoclevel,
const char *, int, int, const char *);
static void parse(struct curparse *, int,
const char *, enum mandoclevel *);
-static enum mandoclevel passthrough(const char *);
+static enum mandoclevel passthrough(const char *, int);
static void spawn_pager(void);
static int toptions(struct curparse *, char *);
static void usage(enum argmode) __attribute__((noreturn));
@@ -114,6 +114,8 @@ main(int argc, char *argv[])
#endif
enum mandoclevel rc;
enum outmode outmode;
+ pid_t child_pid;
+ int fd;
int show_usage;
int use_pager;
int options;
@@ -370,16 +372,30 @@ main(int argc, char *argv[])
while (argc) {
#if HAVE_SQLITE3
if (resp != NULL) {
- if (resp->form & FORM_SRC) {
+ rc = mparse_open(curp.mp, &fd, resp->file,
+ &child_pid);
+ if (fd == -1)
+ /* nothing */;
+ else if (resp->form & FORM_SRC) {
/* For .so only; ignore failure. */
chdir(paths.paths[resp->ipath]);
- parse(&curp, -1, resp->file, &rc);
+ parse(&curp, fd, resp->file, &rc);
} else
- rc = passthrough(resp->file);
+ rc = passthrough(resp->file, fd);
resp++;
} else
#endif
- parse(&curp, -1, *argv++, &rc);
+ {
+ rc = mparse_open(curp.mp, &fd, *argv++,
+ &child_pid);
+ if (fd != -1)
+ parse(&curp, fd, argv[-1], &rc);
+ }
+
+ if (child_pid &&
+ mparse_wait(curp.mp, child_pid) != MANDOCLEVEL_OK)
+ rc = MANDOCLEVEL_SYSERR;
+
if (MANDOCLEVEL_OK != rc && curp.wstop)
break;
argc--;
@@ -555,18 +571,11 @@ parse(struct curparse *curp, int fd, const char *file,
}
static enum mandoclevel
-passthrough(const char *file)
+passthrough(const char *file, int fd)
{
char buf[BUFSIZ];
const char *syscall;
ssize_t nr, nw, off;
- int fd;
-
- fd = open(file, O_RDONLY);
- if (fd == -1) {
- syscall = "open";
- goto fail;
- }
while ((nr = read(fd, buf, BUFSIZ)) != -1 && nr != 0)
for (off = 0; off < nr; off += nw)
diff --git a/mandoc.3 b/mandoc.3
index 9a99f9c2..0e691850 100644
--- a/mandoc.3
+++ b/mandoc.3
@@ -31,11 +31,13 @@
.Nm mparse_free ,
.Nm mparse_getkeep ,
.Nm mparse_keep ,
+.Nm mparse_open ,
.Nm mparse_readfd ,
.Nm mparse_reset ,
.Nm mparse_result ,
.Nm mparse_strerror ,
.Nm mparse_strlevel
+.Nm mparse_wait ,
.Nd mandoc macro compiler library
.Sh LIBRARY
.Lb libmandoc
@@ -74,6 +76,13 @@
.Fa "struct mparse *parse"
.Fc
.Ft "enum mandoclevel"
+.Fo mparse_open
+.Fa "struct mparse *parse"
+.Fa "int *fd"
+.Fa "const char *fname"
+.Fa "pid_t *child_pid"
+.Fc
+.Ft "enum mandoclevel"
.Fo mparse_readfd
.Fa "struct mparse *parse"
.Fa "int fd"
@@ -98,6 +107,11 @@
.Fo mparse_strlevel
.Fa "enum mandoclevel"
.Fc
+.Ft "enum mandoclevel"
+.Fo mparse_wait
+.Fa "struct mparse *parse"
+.Fa "pid_t child_pid"
+.Fc
.In sys/types.h
.In mandoc.h
.In mdoc.h
@@ -361,6 +375,33 @@ Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
+.It Fn mparse_open
+If the
+.Fa fname
+ends in
+.Pa .gz ,
+open with
+.Xr gunzip 1 ;
+otherwise, with
+.Xr open 2 .
+Return a file descriptor open for reading in
+.Fa fd ,
+or -1 on failure.
+It can be passed to
+.Fn mparse_readfd
+or used directly.
+If applicable, return the
+.Xr gunzip 1
+child process ID in
+.Fa child_pid ,
+or otherwise 0.
+If non-zero, it should be passed to
+.Fn mparse_wait
+after completing the parse sequence.
+Declared in
+.In mandoc.h ,
+implemented in
+.Pa read.c .
.It Fn mparse_readfd
Parse a file or file descriptor.
If
@@ -413,6 +454,27 @@ Declared in
.In mandoc.h ,
implemented in
.Pa read.c .
+.It Fn mparse_wait
+Bury a
+.Xr gunzip 1
+child process
+.Fa child_pid
+that was spawned with
+.Fn mparse_open .
+To be called after the parse sequence is complete.
+Returns
+.Dv MANDOCLEVEL_OK
+on success and
+.Dv MANDOCLEVEL_SYSERR
+on failure, that is, when
+.Xr wait 2
+fails, or when
+.Xr gunzip 1
+died from a signal or exited with non-zero status.
+Declared in
+.In mandoc.h ,
+implemented in
+.Pa read.c .
.El
.Ss Variables
.Bl -ohang
diff --git a/mandoc.h b/mandoc.h
index 1ef88d35..0be1feec 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -171,9 +171,16 @@ enum mandocerr {
/* ===== system errors ===== */
+ MANDOCERR_SYSDUP, /* cannot dup file descriptor */
+ MANDOCERR_SYSEXEC, /* cannot exec */
+ MANDOCERR_SYSEXIT, /* gunzip failed with code */
+ MANDOCERR_SYSFORK, /* cannot fork */
MANDOCERR_SYSOPEN, /* cannot open file */
- MANDOCERR_SYSSTAT, /* cannot stat file */
+ MANDOCERR_SYSPIPE, /* cannot open pipe */
MANDOCERR_SYSREAD, /* cannot read file */
+ MANDOCERR_SYSSIG, /* gunzip died from signal */
+ MANDOCERR_SYSSTAT, /* cannot stat file */
+ MANDOCERR_SYSWAIT, /* wait failed */
MANDOCERR_MAX
};
@@ -423,6 +430,8 @@ struct mparse *mparse_alloc(int, enum mandoclevel, mandocmsg,
const char *);
void mparse_free(struct mparse *);
void mparse_keep(struct mparse *);
+enum mandoclevel mparse_open(struct mparse *, int *, const char *,
+ pid_t *);
enum mandoclevel mparse_readfd(struct mparse *, int, const char *);
enum mandoclevel mparse_readmem(struct mparse *, const void *, size_t,
const char *);
@@ -432,6 +441,7 @@ void mparse_result(struct mparse *,
const char *mparse_getkeep(const struct mparse *);
const char *mparse_strerror(enum mandocerr);
const char *mparse_strlevel(enum mandoclevel);
+enum mandoclevel mparse_wait(struct mparse *, pid_t);
__END_DECLS
diff --git a/mandocdb.c b/mandocdb.c
index e1c744d7..de9d47cc 100644
--- a/mandocdb.c
+++ b/mandocdb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD$ */
+/* $Id$ */
/*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -17,8 +17,8 @@
*/
#include "config.h"
-#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/wait.h>
#include <assert.h>
@@ -1076,7 +1076,6 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
{
char any[] = "any";
struct ohash_info str_info;
- int fd[2];
struct mpage *mpage, *mpage_dest;
struct mlink *mlink, *mlink_dest;
struct mdoc *mdoc;
@@ -1084,7 +1083,7 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
char *sodest;
char *cp;
pid_t child_pid;
- int status;
+ int fd;
unsigned int pslot;
enum mandoclevel lvl;
@@ -1112,38 +1111,11 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
man = NULL;
sodest = NULL;
child_pid = 0;
- fd[0] = -1;
- fd[1] = -1;
-
- if (mpage->mlinks->gzip) {
- if (-1 == pipe(fd)) {
- exitcode = (int)MANDOCLEVEL_SYSERR;
- say(mpage->mlinks->file, "&pipe gunzip");
- goto nextpage;
- }
- switch (child_pid = fork()) {
- case -1:
- exitcode = (int)MANDOCLEVEL_SYSERR;
- say(mpage->mlinks->file, "&fork gunzip");
- child_pid = 0;
- close(fd[1]);
- close(fd[0]);
- goto nextpage;
- case 0:
- close(fd[0]);
- if (-1 == dup2(fd[1], STDOUT_FILENO)) {
- say(mpage->mlinks->file,
- "&dup gunzip");
- exit(1);
- }
- execlp("gunzip", "gunzip", "-c",
- mpage->mlinks->file, NULL);
- say(mpage->mlinks->file, "&exec gunzip");
- exit(1);
- default:
- close(fd[1]);
- break;
- }
+
+ mparse_open(mp, &fd, mpage->mlinks->file, &child_pid);
+ if (fd == -1) {
+ say(mpage->mlinks->file, "&open");
+ goto nextpage;
}
/*
@@ -1153,7 +1125,7 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
*/
if (FORM_CAT != mpage->mlinks->dform ||
FORM_CAT != mpage->mlinks->fform) {
- lvl = mparse_readfd(mp, fd[0], mpage->mlinks->file);
+ lvl = mparse_readfd(mp, fd, mpage->mlinks->file);
if (lvl < MANDOCLEVEL_FATAL)
mparse_result(mp, &mdoc, &man, &sodest);
}
@@ -1245,7 +1217,7 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
} else if (NULL != man)
parse_man(mpage, man_node(man));
else
- parse_cat(mpage, fd[0]);
+ parse_cat(mpage, fd);
if (NULL == mpage->desc)
mpage->desc = mandoc_strdup(mpage->mlinks->name);
@@ -1257,21 +1229,10 @@ mpages_merge(struct mchars *mc, struct mparse *mp)
dbadd(mpage, mc);
nextpage:
- if (child_pid) {
- if (-1 == waitpid(child_pid, &status, 0)) {
- exitcode = (int)MANDOCLEVEL_SYSERR;
- say(mpage->mlinks->file, "&wait gunzip");
- } else if (WIFSIGNALED(status)) {
- exitcode = (int)MANDOCLEVEL_SYSERR;
- say(mpage->mlinks->file,
- "gunzip died from signal %d",
- WTERMSIG(status));
- } else if (WEXITSTATUS(status)) {
- exitcode = (int)MANDOCLEVEL_SYSERR;
- say(mpage->mlinks->file,
- "gunzip failed with code %d",
- WEXITSTATUS(status));
- }
+ if (child_pid &&
+ mparse_wait(mp, child_pid) != MANDOCLEVEL_OK) {
+ exitcode = (int)MANDOCLEVEL_SYSERR;
+ say(mpage->mlinks->file, "&wait gunzip");
}
ohash_delete(&strings);
ohash_delete(&names);
@@ -2351,7 +2312,7 @@ prepare_statements:
"PRAGMA synchronous = OFF", NULL, NULL, NULL)) {
exitcode = (int)MANDOCLEVEL_SYSERR;
say(MANDOC_DB, "PRAGMA synchronous: %s",
- sqlite3_errmsg(db));
+ sqlite3_errmsg(db));
sqlite3_close(db);
return(0);
}
diff --git a/read.c b/read.c
index 4b614b6f..8fb220c6 100644
--- a/read.c
+++ b/read.c
@@ -20,9 +20,10 @@
#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)