1 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
2 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
28 #include <sys/types.h>
36 extern char *strerror();
39 #ifndef HAVE_STRCASECMP
40 #define strcasecmp(a,b) strcmp((a),(b))
43 #ifndef HAVE_STRNCASECMP
44 #define strncasecmp(a,b,c) strncmp((a),(b),(c))
53 #else /* not _POSIX_VERSION */
55 /* traditional Unix */
57 #define WIFEXITED(s) (((s) & 0377) == 0)
58 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
59 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
60 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
61 #define WTERMSIG(s) ((s) & 0177)
62 #define WSTOPSIG(s) (((s) >> 8) & 0377)
65 #define WCOREFLAG 0200
70 #endif /* not _POSIX_VERSION */
72 /* SVR4 uses WCOREFLG; Net 2 uses WCOREFLAG. */
75 #define WCOREFLAG WCOREFLG
77 #endif /* not WCOREFLAG */
81 #define WCOREDUMP(s) ((s) & WCOREFLAG)
82 #else /* not WCOREFLAG */
83 #define WCOREDUMP(s) (0)
84 #endif /* WCOREFLAG */
85 #endif /* not WCOREDUMP */
90 #define P(parms) parms
93 #define const /* as nothing */
97 extern void error P((const char *, const char *, const char *, const char *));
98 extern void c_fatal P((const char *, const char *, const char *, const char *));
100 static void sys_fatal P((const char *));
101 static const char *xstrsignal P((int));
102 static char *i_to_a P((int));
104 /* MSVC can support asynchronous processes, but it's unlikely to have
105 fork(). So, until someone writes an emulation, let them at least
106 have a workable groff by using the good-ole DOS pipe simulation
107 via temporary files... */
109 #if defined(__MSDOS__) \
110 || (defined(_WIN32) && !defined(_UWIN) && !defined(__CYGWIN__)) \
118 #include "nonposix.h"
120 /* A signal handler that just records that a signal has happened. */
121 static int child_interrupted;
123 static RETSIGTYPE signal_catcher (int signo)
128 static const char *sh = "sh";
129 static const char *command = "command";
132 system_shell_name (void)
134 static const char *shell_name;
136 /* We want them to be able to use a Unixy shell if they have it
137 installed. Let spawnlp try to find it, but if it fails, default
139 if (shell_name == NULL)
141 int sh_found = spawnlp (P_WAIT, sh, sh, "-c", ":", NULL) == 0;
146 shell_name = command;
152 system_shell_dash_c (void)
154 if (strcmp (system_shell_name(), sh) == 0)
161 is_system_shell (const char *shell)
164 size_t ibase = 0, idot, i;
166 if (!shell) /* paranoia */
168 idot = shlen = strlen(shell);
170 for (i = 0; i < shlen; i++)
174 else if (shell[i] == '/' || shell[i] == '\\' || shell[i] == ':')
181 /* "sh" and "sh.exe" should compare equal. */
183 (strncasecmp (shell + ibase, system_shell_name (), idot - ibase) == 0
185 || strcasecmp (shell + idot, ".exe") == 0
186 || strcasecmp (shell + idot, ".com") == 0));
189 /* MSDOS doesn't have `fork', so we need to simulate the pipe by
190 running the programs in sequence with redirected standard streams. */
192 int run_pipeline (ncommands, commands, no_pipe)
197 int save_stdin = dup(0);
198 int save_stdout = dup(1);
200 char tem1[L_tmpnam], tem2[L_tmpnam];
205 tmpfiles[0] = tmpnam(tem1);
206 tmpfiles[1] = tmpnam(tem2);
208 for (i = 0; i < ncommands; i++)
211 RETSIGTYPE (*prev_handler)(int);
215 /* redirect stdin from temp file */
216 f = open(tmpfiles[infile], O_RDONLY|O_BINARY, 0666);
218 sys_fatal("open stdin");
220 sys_fatal("dup2 stdin");
222 sys_fatal("close stdin");
224 if ((i < ncommands - 1) && !no_pipe)
226 /* redirect stdout to temp file */
227 f = open(tmpfiles[outfile], O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
229 sys_fatal("open stdout");
231 sys_fatal("dup2 stdout");
233 sys_fatal("close stdout");
235 else if (dup2(save_stdout, 1) < 0)
236 sys_fatal("restore stdout");
238 /* run the program */
239 child_interrupted = 0;
240 prev_handler = signal(SIGINT, signal_catcher);
241 exit_status = spawnvp(P_WAIT, commands[i][0], commands[i]);
242 signal(SIGINT, prev_handler);
243 if (child_interrupted)
245 error("%1: Interrupted", commands[i][0], (char *)0, (char *)0);
248 else if (exit_status < 0)
250 error("couldn't exec %1: %2", commands[i][0],
251 strerror(errno), (char *)0);
252 fflush(stderr); /* just in case error() doesn't */
255 if (exit_status != 0)
258 /* There's no sense to continue with the pipe if one of the
259 programs has ended abnormally, is there? */
263 /* swap temp files: make output of this program be input for the next */
265 outfile = 1 - outfile;
268 if (dup2(save_stdin, 0) < 0)
269 sys_fatal("restore stdin");
277 #else /* not __MSDOS__, not _WIN32 */
279 int run_pipeline(ncommands, commands, no_pipe)
286 PID_T pids[MAX_COMMANDS];
288 int proc_count = ncommands;
290 for (i = 0; i < ncommands; i++) {
293 if ((i != ncommands - 1) && !no_pipe) {
302 if (last_input != 0) {
305 if (dup(last_input) < 0)
307 if (close(last_input) < 0)
310 if ((i != ncommands - 1) && !no_pipe) {
313 if (dup(pdes[1]) < 0)
315 if (close(pdes[1]) < 0)
320 execvp(commands[i][0], commands[i]);
321 error("couldn't exec %1: %2", commands[i][0],
322 strerror(errno), (char *)0);
323 fflush(stderr); /* just in case error() doesn't */
324 _exit(EXEC_FAILED_EXIT_STATUS);
327 if (last_input != 0) {
328 if (close(last_input) < 0)
331 if ((i != ncommands - 1) && !no_pipe) {
332 if (close(pdes[1]) < 0)
334 last_input = pdes[0];
338 while (proc_count > 0) {
340 PID_T pid = wait(&status);
343 for (i = 0; i < ncommands; i++)
344 if (pids[i] == pid) {
347 if (WIFSIGNALED(status)) {
348 int sig = WTERMSIG(status);
350 if (sig == SIGPIPE) {
351 if (i == ncommands - 1) {
353 /* This works around a problem that occurred when using the
354 rerasterize action in gxditview. What seemed to be
355 happening (on SunOS 4.1.1) was that pclose() closed the
356 pipe and waited for groff, gtroff got a SIGPIPE, but
357 gpic blocked writing to gtroff, and so groff blocked
358 waiting for gpic and gxditview blocked waiting for
359 groff. I don't understand why gpic wasn't getting a
362 for (j = 0; j < ncommands; j++)
364 (void)kill(pids[j], SIGPIPE);
373 WCOREDUMP(status) ? " (core dumped)" : "");
377 else if (WIFEXITED(status)) {
378 int exit_status = WEXITSTATUS(status);
379 if (exit_status == EXEC_FAILED_EXIT_STATUS)
381 else if (exit_status != 0)
385 error("unexpected status %1",
386 i_to_a(status), (char *)0, (char *)0);
393 #endif /* not __MSDOS__, not _WIN32 */
395 static void sys_fatal(s)
398 c_fatal("%1: %2", s, strerror(errno), (char *)0);
401 static char *i_to_a(n)
405 sprintf(buf, "%d", n);
409 static const char *xstrsignal(n)
412 static char buf[sizeof("Signal ") + 1 + sizeof(int)*3];
414 #ifdef SYS_SIGLIST_DECLARED
415 if (n >= 0 && n < NSIG && sys_siglist[n] != 0)
416 return sys_siglist[n];
417 #endif /* SYS_SIGLIST_DECLARED */
419 sprintf(buf, "Signal %d", n);