aboutsummaryrefslogtreecommitdiff
path: root/contrib/groff/src/roff/groff/pipeline.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/groff/src/roff/groff/pipeline.c')
-rw-r--r--contrib/groff/src/roff/groff/pipeline.c329
1 files changed, 191 insertions, 138 deletions
diff --git a/contrib/groff/src/roff/groff/pipeline.c b/contrib/groff/src/roff/groff/pipeline.c
index 985b24fd274f..d067ae93016b 100644
--- a/contrib/groff/src/roff/groff/pipeline.c
+++ b/contrib/groff/src/roff/groff/pipeline.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
@@ -16,7 +16,7 @@ for more details.
You should have received a copy of the GNU General Public License along
with groff; see the file COPYING. If not, write to the Free Software
-Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -39,7 +39,6 @@ extern char *strerror();
#ifdef _POSIX_VERSION
#include <sys/wait.h>
-
#define PID_T pid_t
#else /* not _POSIX_VERSION */
@@ -78,27 +77,23 @@ extern char *strerror();
#include "pipeline.h"
-#ifdef __STDC__
-#define P(parms) parms
-#else
-#define P(parms) ()
-#ifndef _WIN32
-#define const /* as nothing */
-#endif
+#define error c_error
+
+#ifdef __cplusplus
+extern "C" {
#endif
-#define error c_error
-extern void error P((const char *, const char *, const char *, const char *));
-extern void c_fatal P((const char *, const char *, const char *, const char *));
+extern void error(const char *, const char *, const char *, const char *);
+extern void c_fatal(const char *, const char *, const char *, const char *);
+extern const char *i_to_a(int); /* from libgroff */
+
+#ifdef __cplusplus
+}
+#endif
-static void sys_fatal P((const char *));
-static const char *xstrsignal P((int));
-static char *i_to_a P((int));
+static void sys_fatal(const char *);
+static const char *xstrsignal(int);
-/* MSVC can support asynchronous processes, but it's unlikely to have
- fork(). So, until someone writes an emulation, let them at least
- have a workable groff by using the good-ole DOS pipe simulation
- via temporary files... */
#if defined(__MSDOS__) \
|| (defined(_WIN32) && !defined(_UWIN) && !defined(__CYGWIN__)) \
@@ -106,87 +101,120 @@ static char *i_to_a P((int));
#include <process.h>
#include <fcntl.h>
-#include <ctype.h>
#include <string.h>
+#include <stdlib.h>
#include "nonposix.h"
-/* A signal handler that just records that a signal has happened. */
-static int child_interrupted;
+static const char *sh = "sh";
+static const char *cmd = "cmd";
+static const char *command = "command";
-static RETSIGTYPE signal_catcher(int signo)
+extern int strcasecmp(const char *, const char *);
+
+char *sbasename(const char *path)
{
- child_interrupted++;
-}
+ char *base;
+ const char *p1, *p2;
+
+ p1 = path;
+ if ((p2 = strrchr(p1, '\\'))
+ || (p2 = strrchr(p1, '/'))
+ || (p2 = strrchr(p1, ':')))
+ p1 = p2 + 1;
+ if ((p2 = strrchr(p1, '.'))
+ && ((strcasecmp(p2, ".exe") == 0)
+ || (strcasecmp(p2, ".com") == 0)))
+ ;
+ else
+ p2 = p1 + strlen(p1);
-static const char *sh = "sh";
-static const char *command = "command";
+ base = malloc((size_t)(p2 - p1));
+ strncpy(base, p1, p2 - p1);
+ *(base + (p2 - p1)) = '\0';
-const char *
-system_shell_name(void)
+ return(base);
+}
+
+/* Get the name of the system shell */
+char *system_shell_name(void)
{
- static const char *shell_name;
-
- /* We want them to be able to use a Unixy shell if they have it
- installed. Let spawnlp try to find it, but if it fails, default
- to COMMAND.COM. */
- if (shell_name == NULL) {
- int sh_found = spawnlp(P_WAIT, sh, sh, "-c", ":", NULL) == 0;
-
- if (sh_found)
- shell_name = sh;
- else
- shell_name = command;
- }
- return shell_name;
+ const char *shell_name;
+
+ /*
+ Use a Unixy shell if it's installed. Use SHELL if set; otherwise,
+ let spawnlp try to find sh; if that fails, use COMSPEC if set; if
+ not, try cmd.exe; if that fails, default to command.com.
+ */
+
+ if ((shell_name = getenv("SHELL")) != NULL)
+ ;
+ else if (spawnlp(_P_WAIT, sh, sh, "-c", ":", NULL) == 0)
+ shell_name = sh;
+ else if ((shell_name = getenv("COMSPEC")) != NULL)
+ ;
+ else if (spawnlp(_P_WAIT, cmd, cmd, "/c", ";", NULL) == 0)
+ shell_name = cmd;
+ else
+ shell_name = command;
+
+ return sbasename(shell_name);
}
-const char *
-system_shell_dash_c(void)
+const char *system_shell_dash_c(void)
{
- if (strcmp(system_shell_name(), sh) == 0)
- return "-c";
+ char *shell_name;
+ const char *dash_c;
+
+ shell_name = system_shell_name();
+
+ /* Assume that if the shell name ends in "sh", it's Unixy */
+ if (strcasecmp(shell_name + strlen(shell_name) - strlen("sh"), "sh") == 0)
+ dash_c = "-c";
else
- return "/c";
+ dash_c = "/c";
+
+ free(shell_name);
+ return dash_c;
}
-int
-is_system_shell(const char *shell)
+int is_system_shell(const char *prog)
{
- size_t shlen;
- size_t ibase = 0, idot, i;
+ int result;
+ char *this_prog, *system_shell;
- if (!shell) /* paranoia */
+ if (!prog) /* paranoia */
return 0;
- idot = shlen = strlen(shell);
-
- for (i = 0; i < shlen; i++) {
- if (shell[i] == '.')
- idot = i;
- else if (shell[i] == '/' || shell[i] == '\\' || shell[i] == ':') {
- ibase = i + 1;
- idot = shlen;
- }
- }
- /* "sh" and "sh.exe" should compare equal. */
- return (strncasecmp(shell + ibase, system_shell_name(), idot - ibase) == 0
- && (idot == shlen
- || strcasecmp(shell + idot, ".exe") == 0
- || strcasecmp(shell + idot, ".com") == 0));
+ this_prog = sbasename(prog);
+ system_shell = system_shell_name();
+
+ result = strcasecmp(this_prog, system_shell) == 0;
+
+ free(this_prog);
+ free(system_shell);
+
+ return result;
}
#ifdef _WIN32
-/* Win32 doesn't have fork() */
+/*
+ Windows 32 doesn't have fork(), so we need to start asynchronous child
+ processes with spawn() rather than exec(). If there is more than one
+ command, i.e., a pipeline, the parent must set up each child's I/O
+ redirection prior to the spawn. The original stdout must be restored
+ before spawning the last process in the pipeline, and the original
+ stdin must be restored in the parent after spawning the last process
+ and before waiting for any of the children.
+*/
-int
-run_pipeline(int ncommands, char ***commands, int no_pipe)
+int run_pipeline(int ncommands, char ***commands, int no_pipe)
{
- int save_stdin, save_stdout;
int i;
- int last_input = 0;
- int proc_count = ncommands;
+ int last_input = 0; /* pacify some compilers */
+ int save_stdin = 0;
+ int save_stdout = 0;
int ret = 0;
char err_str[BUFSIZ];
PID_T pids[MAX_COMMANDS];
@@ -200,16 +228,22 @@ run_pipeline(int ncommands, char ***commands, int no_pipe)
if (ncommands > 1 && !no_pipe) {
/* last command doesn't need a new pipe */
if (i < ncommands - 1) {
- if (_pipe(pdes, BUFSIZ, O_BINARY | O_NOINHERIT) < 0)
- sys_fatal("pipe");
+ if (pipe(pdes) < 0) {
+ sprintf(err_str, "%s: pipe", commands[i][0]);
+ sys_fatal(err_str);
+ }
}
/* 1st command; writer */
if (i == 0) {
+ /* save stdin */
+ if ((save_stdin = dup(STDIN_FILENO)) < 0)
+ sys_fatal("dup stdin");
/* save stdout */
- if ((save_stdout = _dup(1)) < 0)
+ if ((save_stdout = dup(STDOUT_FILENO)) < 0)
sys_fatal("dup stdout");
+
/* connect stdout to write end of pipe */
- if (_dup2(pdes[1], 1) < 0) {
+ if (dup2(pdes[1], STDOUT_FILENO) < 0) {
sprintf(err_str, "%s: dup2(stdout)", commands[i][0]);
sys_fatal(err_str);
}
@@ -217,19 +251,28 @@ run_pipeline(int ncommands, char ***commands, int no_pipe)
sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]);
sys_fatal(err_str);
}
+ /*
+ Save the read end of the pipe so that it can be connected to
+ stdin of the next program in the pipeline during the next
+ pass through the loop.
+ */
last_input = pdes[0];
}
/* reader and writer */
else if (i < ncommands - 1) {
/* connect stdin to read end of last pipe */
- if (_dup2(last_input, 0) < 0) {
+ if (dup2(last_input, STDIN_FILENO) < 0) {
sprintf(err_str, " %s: dup2(stdin)", commands[i][0]);
- sys_fatal("err_str");
+ sys_fatal(err_str);
+ }
+ if (close(last_input) < 0) {
+ sprintf(err_str, "%s: close(last_input)", commands[i][0]);
+ sys_fatal(err_str);
}
/* connect stdout to write end of new pipe */
- if (_dup2(pdes[1], 1) < 0) {
+ if (dup2(pdes[1], STDOUT_FILENO) < 0) {
sprintf(err_str, "%s: dup2(stdout)", commands[i][0]);
- sys_fatal("err_str");
+ sys_fatal(err_str);
}
if (close(pdes[1]) < 0) {
sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]);
@@ -240,22 +283,27 @@ run_pipeline(int ncommands, char ***commands, int no_pipe)
/* last command; reader */
else {
/* connect stdin to read end of last pipe */
- if (_dup2(last_input, 0) < 0) {
+ if (dup2(last_input, STDIN_FILENO) < 0) {
sprintf(err_str, "%s: dup2(stdin)", commands[i][0]);
- sys_fatal("err_str");
+ sys_fatal(err_str);
}
if (close(last_input) < 0) {
- sprintf(err_str, "%s: close(pipe[READ])", commands[i][0]);
+ sprintf(err_str, "%s: close(last_input)", commands[i][0]);
sys_fatal(err_str);
}
/* restore original stdout */
- if (_dup2(save_stdout, 1) < 0) {
- sprintf(err_str, "%s: dup2(stdout))", "groff");
+ if (dup2(save_stdout, STDOUT_FILENO) < 0) {
+ sprintf(err_str, "%s: dup2(save_stdout))", commands[i][0]);
sys_fatal(err_str);
}
+ /* close stdout copy */
+ if (close(save_stdout) < 0) {
+ sprintf(err_str, "%s: close(save_stdout)", commands[i][0]);
+ sys_fatal(err_str);
+ }
}
}
- if ((pid = _spawnvp(_P_NOWAIT, commands[i][0], commands[i])) < 0) {
+ if ((pid = spawnvp(_P_NOWAIT, commands[i][0], commands[i])) < 0) {
error("couldn't exec %1: %2",
commands[i][0], strerror(errno), (char *)0);
fflush(stderr); /* just in case error() doesn't */
@@ -263,65 +311,81 @@ run_pipeline(int ncommands, char ***commands, int no_pipe)
}
pids[i] = pid;
}
+
+ if (ncommands > 1 && !no_pipe) {
+ /* restore original stdin if it was redirected */
+ if (dup2(save_stdin, STDIN_FILENO) < 0) {
+ sprintf(err_str, "dup2(save_stdin))");
+ sys_fatal(err_str);
+ }
+ /* close stdin copy */
+ if (close(save_stdin) < 0) {
+ sprintf(err_str, "close(save_stdin)");
+ sys_fatal(err_str);
+ }
+ }
+
for (i = 0; i < ncommands; i++) {
int status;
- int pid;
+ PID_T pid;
pid = pids[i];
- if ((pid = _cwait(&status, pid, _WAIT_CHILD)) < 0) {
- perror(NULL);
- sys_fatal("wait");
- if (WIFSIGNALED(status)) {
- int sig = WTERMSIG(status);
-
- error("%1: %2%3",
- commands[i][0],
- xstrsignal(sig),
- WCOREDUMP(status) ? " (core dumped)" : "");
- ret |= 2;
- }
- else if (WIFEXITED(status)) {
- int exit_status = WEXITSTATUS(status);
-
- if (exit_status == EXEC_FAILED_EXIT_STATUS)
- ret |= 4;
- else if (exit_status != 0)
- ret |= 1;
- }
- else
- error("unexpected status %1", itoa(status), (char *)0, (char *)0);
- break;
+ if ((pid = WAIT(&status, pid, _WAIT_CHILD)) < 0) {
+ sprintf(err_str, "%s: wait", commands[i][0]);
+ sys_fatal(err_str);
}
+ else if (status != 0)
+ ret |= 1;
}
return ret;
}
-#else /* _WIN32 */
+#else /* not _WIN32 */
/* MSDOS doesn't have `fork', so we need to simulate the pipe by running
- the programs in sequence with standard streams redirected fot and
+ the programs in sequence with standard streams redirected to and
from temporary files.
*/
-int
-run_pipeline(int ncommands, char ***commands, int no_pipe)
+
+/* A signal handler that just records that a signal has happened. */
+static int child_interrupted;
+
+static RETSIGTYPE signal_catcher(int signo)
+{
+ child_interrupted++;
+}
+
+int run_pipeline(int ncommands, char ***commands, int no_pipe)
{
int save_stdin = dup(0);
int save_stdout = dup(1);
char *tmpfiles[2];
- char tem1[L_tmpnam], tem2[L_tmpnam];
int infile = 0;
int outfile = 1;
int i, f, ret = 0;
- tmpfiles[0] = tmpnam(tem1);
- tmpfiles[1] = tmpnam(tem2);
+ /* Choose names for a pair of temporary files to implement the pipeline.
+ Microsoft's `tempnam' uses the directory specified by `getenv("TMP")'
+ if it exists; in case it doesn't, try the GROFF alternatives, or
+ `getenv("TEMP")' as last resort -- at least one of these had better
+ be set, since Microsoft's default has a high probability of failure. */
+ char *tmpdir;
+ if ((tmpdir = getenv("GROFF_TMPDIR")) == NULL
+ && (tmpdir = getenv("TMPDIR")) == NULL)
+ tmpdir = getenv("TEMP");
+
+ /* Don't use `tmpnam' here: Microsoft's implementation yields unusable
+ file names if current directory is on network share with read-only
+ root. */
+ tmpfiles[0] = tempnam(tmpdir, NULL);
+ tmpfiles[1] = tempnam(tmpdir, NULL);
for (i = 0; i < ncommands; i++) {
int exit_status;
RETSIGTYPE (*prev_handler)(int);
- if (i) {
+ if (i && !no_pipe) {
/* redirect stdin from temp file */
f = open(tmpfiles[infile], O_RDONLY|O_BINARY, 0666);
if (f < 0)
@@ -376,12 +440,11 @@ run_pipeline(int ncommands, char ***commands, int no_pipe)
return ret;
}
-#endif /* MS-DOS */
+#endif /* not _WIN32 */
#else /* not __MSDOS__, not _WIN32 */
-int
-run_pipeline(int ncommands, char ***commands, int no_pipe)
+int run_pipeline(int ncommands, char ***commands, int no_pipe)
{
int i;
int last_input = 0;
@@ -496,30 +559,20 @@ run_pipeline(int ncommands, char ***commands, int no_pipe)
#endif /* not __MSDOS__, not _WIN32 */
-static void
-sys_fatal(const char *s)
+static void sys_fatal(const char *s)
{
c_fatal("%1: %2", s, strerror(errno), (char *)0);
}
-static char *
-i_to_a(int n)
-{
- static char buf[12];
- sprintf(buf, "%d", n);
- return buf;
-}
-
-static const char *
-xstrsignal(int n)
+static const char *xstrsignal(int n)
{
static char buf[sizeof("Signal ") + 1 + sizeof(int) * 3];
#ifdef NSIG
-#ifdef SYS_SIGLIST_DECLARED
+#if HAVE_DECL_SYS_SIGLIST
if (n >= 0 && n < NSIG && sys_siglist[n] != 0)
return sys_siglist[n];
-#endif /* SYS_SIGLIST_DECLARED */
+#endif /* HAVE_DECL_SYS_SIGLIST */
#endif /* NSIG */
sprintf(buf, "Signal %d", n);
return buf;