+enum mandoclevel
+mparse_open(struct mparse *curp, int *fd, const char *file)
+{
+ int pfd[2];
+ int save_errno;
+ char *cp;
+ enum mandocerr err;
+
+ pfd[1] = -1;
+ curp->file = file;
+
+ /* Unless zipped, try to just open the file. */
+
+ if ((cp = strrchr(file, '.')) == NULL ||
+ strcmp(cp + 1, "gz")) {
+ curp->child = 0;
+ if ((*fd = open(file, O_RDONLY)) != -1)
+ return(MANDOCLEVEL_OK);
+
+ /* Open failed; try to append ".gz". */
+
+ 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;
+ err = MANDOCERR_SYSOPEN;
+ goto out;
+ }
+
+ /* Run gunzip(1). */
+
+ if (pipe(pfd) == -1) {
+ err = MANDOCERR_SYSPIPE;
+ goto out;
+ }
+
+ switch (curp->child = 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:
+ free(cp);
+ *fd = -1;
+ curp->child = 0;
+ curp->file_status = MANDOCLEVEL_SYSERR;
+ if (curp->mmsg)
+ (*curp->mmsg)(err, curp->file_status, curp->file,
+ 0, 0, strerror(errno));
+ if (pfd[1] != -1)
+ exit(1);
+ return(curp->file_status);
+}
+
+enum mandoclevel
+mparse_wait(struct mparse *curp)
+{
+ int status;
+
+ if (curp->child == 0)
+ return(MANDOCLEVEL_OK);
+
+ if (waitpid(curp->child, &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);
+}
+