summaryrefslogtreecommitdiffstats
path: root/read.c
diff options
context:
space:
mode:
Diffstat (limited to 'read.c')
-rw-r--r--read.c114
1 files changed, 32 insertions, 82 deletions
diff --git a/read.c b/read.c
index 40fb15a4..11b24ac1 100644
--- a/read.c
+++ b/read.c
@@ -23,19 +23,18 @@
#include <sys/mman.h>
#include <sys/stat.h>
#endif
-#include <sys/wait.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
-#include <signal.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <zlib.h>
#include "mandoc_aux.h"
#include "mandoc.h"
@@ -60,10 +59,10 @@ struct mparse {
enum mandoclevel file_status; /* status of current parse */
enum mandoclevel wlevel; /* ignore messages below this */
int options; /* parser options */
+ int gzip; /* current input file is gzipped */
int filenc; /* encoding of the current file */
int reparse_count; /* finite interp. stack */
int line; /* line number in the file */
- pid_t child; /* the gunzip(1) process */
};
static void choose_parser(struct mparse *);
@@ -327,7 +326,6 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
int of;
int lnn; /* line number in the real file */
int fd;
- pid_t save_child;
unsigned char c;
memset(&ln, 0, sizeof(ln));
@@ -539,7 +537,6 @@ rerun:
if (curp->secondary)
curp->secondary->sz -= pos + 1;
save_file = curp->file;
- save_child = curp->child;
if (mparse_open(curp, &fd, ln.buf + of) ==
MANDOCLEVEL_OK) {
mparse_readfd(curp, fd, ln.buf + of);
@@ -557,7 +554,6 @@ rerun:
of = 0;
mparse_buf_r(curp, ln, of, 0);
}
- curp->child = save_child;
pos = 0;
continue;
default:
@@ -611,6 +607,7 @@ static int
read_whole_file(struct mparse *curp, const char *file, int fd,
struct buf *fb, int *with_mmap)
{
+ gzFile gz;
size_t off;
ssize_t ssz;
@@ -628,7 +625,7 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
* concerned that this is going to tank any machines.
*/
- if (S_ISREG(st.st_mode)) {
+ if (curp->gzip == 0 && S_ISREG(st.st_mode)) {
if (st.st_size > 0x7fffffff) {
mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL);
return(0);
@@ -641,6 +638,14 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
}
#endif
+ if (curp->gzip) {
+ if ((gz = gzdopen(fd, "rb")) == NULL) {
+ perror(file);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ } else
+ gz = NULL;
+
/*
* If this isn't a regular file (like, say, stdin), then we must
* go the old way and just read things in bit by bit.
@@ -659,7 +664,9 @@ read_whole_file(struct mparse *curp, const char *file, int fd,
}
resize_buf(fb, 65536);
}
- ssz = read(fd, fb->buf + (int)off, fb->sz - off);
+ ssz = curp->gzip ?
+ gzread(gz, fb->buf + (int)off, fb->sz - off) :
+ read(fd, fb->buf + (int)off, fb->sz - off);
if (ssz == 0) {
fb->sz = off;
return(1);
@@ -773,99 +780,42 @@ mparse_readfd(struct mparse *curp, int fd, const char *file)
if (fd != STDIN_FILENO && close(fd) == -1)
perror(file);
- mparse_wait(curp);
return(curp->file_status);
}
enum mandoclevel
mparse_open(struct mparse *curp, int *fd, const char *file)
{
- int pfd[2];
- int save_errno;
char *cp;
curp->file = file;
+ cp = strrchr(file, '.');
+ curp->gzip = (cp != NULL && ! strcmp(cp + 1, "gz"));
- /* Unless zipped, try to just open the file. */
+ /* First try to use the filename as it is. */
- if ((cp = strrchr(file, '.')) == NULL ||
- strcmp(cp + 1, "gz")) {
- curp->child = 0;
- if ((*fd = open(file, O_RDONLY)) != -1)
- return(MANDOCLEVEL_OK);
+ if ((*fd = open(file, O_RDONLY)) != -1)
+ return(MANDOCLEVEL_OK);
- /* Open failed; try to append ".gz". */
+ /*
+ * If that doesn't work and the filename doesn't
+ * already end in .gz, try appending .gz.
+ */
+ if ( ! curp->gzip) {
mandoc_asprintf(&cp, "%s.gz", file);
- file = cp;
- } else
- cp = NULL;
-
- /* Before forking, make sure the file can be read. */
-
- save_errno = errno;
- if (access(file, R_OK) == -1) {
- if (cp != NULL)
- errno = save_errno;
+ *fd = open(file, O_RDONLY);
free(cp);
- *fd = -1;
- curp->child = 0;
- mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno));
- return(MANDOCLEVEL_ERROR);
- }
-
- /* Run gunzip(1). */
-
- if (pipe(pfd) == -1) {
- perror("pipe");
- exit((int)MANDOCLEVEL_SYSERR);
- }
-
- switch (curp->child = fork()) {
- case -1:
- perror("fork");
- exit((int)MANDOCLEVEL_SYSERR);
- case 0:
- close(pfd[0]);
- if (dup2(pfd[1], STDOUT_FILENO) == -1) {
- perror("dup");
- exit((int)MANDOCLEVEL_SYSERR);
+ if (*fd != -1) {
+ curp->gzip = 1;
+ return(MANDOCLEVEL_OK);
}
- signal(SIGPIPE, SIG_DFL);
- execlp("gunzip", "gunzip", "-c", file, NULL);
- perror("exec");
- exit((int)MANDOCLEVEL_SYSERR);
- default:
- close(pfd[1]);
- *fd = pfd[0];
- return(MANDOCLEVEL_OK);
}
-}
-enum mandoclevel
-mparse_wait(struct mparse *curp)
-{
- int status;
-
- if (curp->child == 0)
- return(MANDOCLEVEL_OK);
+ /* Neither worked, give up. */
- if (waitpid(curp->child, &status, 0) == -1) {
- perror("wait");
- exit((int)MANDOCLEVEL_SYSERR);
- }
- curp->child = 0;
- if (WIFSIGNALED(status)) {
- mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
- "gunzip died from signal %d", WTERMSIG(status));
- return(MANDOCLEVEL_ERROR);
- }
- if (WEXITSTATUS(status)) {
- mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
- "gunzip failed with code %d", WEXITSTATUS(status));
- return(MANDOCLEVEL_ERROR);
- }
- return(MANDOCLEVEL_OK);
+ mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno));
+ return(MANDOCLEVEL_ERROR);
}
struct mparse *