summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwlemb <wlemb>2004-02-29 00:07:06 +0000
committerwlemb <wlemb>2004-02-29 00:07:06 +0000
commitcf49e6d5f5c047f7c37c7fb09e3a06a5adbb696e (patch)
treea03f65f4af4967e7217a31a6ea3226f2a51582c2
parentcf22bfa85b2e85b72bc2de8dc3353f7cec1e3828 (diff)
downloadgroff-cf49e6d5f5c047f7c37c7fb09e3a06a5adbb696e.tar.gz
* src/include/nonposix.h (write, dup, dup2, close) [_MSC_VER]:
New macros. * src/roff/groff/pipeline.c: Declare strcasecmp. (run_pipeline) [_WIN32]: Use function name variants which don't start with `_'. Fix stream handling. * src/include/nonposix.h: Fix declaration of `system_shell_name'. Declare `spawnvp_wrapper' and macro definitions of spawnvp only for platforms which use the native Win32 runtime libraries. (FLUSH_INPUT_PIPE) [_UWIN]: Provide non-empty version. * src/libs/libgroff/quotearg.c (QUOTE_ARG_MALLOC_ERROR, QUOTE_ARG_REALLOC_ERROR): Fix string. * src/preproc/html/pre-html.cpp: Remove declaration of `spawnvp_wrapper'. Don't use __MINGW32__. s/DEBUG_FILE/DEBUG_FILE_DIR/. (DEBUG_TEXT, DEBUG_NAME, DEBUG_FILE) [DEBUGGING]: New macros. (OUTPUT_STREAM, PS_OUTPUT_STREAM, REGION_OUTPUT_STREAM): New macros. (char_buffer::run_output_filter) [MAY_FORK_CHILD_PROCESS]: Fix calls to `set_redirection' and `WAIT'. [MAY_SPAWN_ASYNCHRONOUS_CHILD]: Remove unused variable `i' and `j'. Fix calls to `set_redirection' and `save_and_redirect'. (char_buffer::do_html, char_buffer::do_image) [DEBUGGING]: Fix calls to `set_redirection' and `save_and_redirect'. (usage): Fix message. (makeTempFiles, main): Use `DEBUG_FILE'.
-rw-r--r--ChangeLog35
-rw-r--r--src/include/nonposix.h45
-rw-r--r--src/libs/libgroff/quotearg.c10
-rw-r--r--src/libs/libgroff/spawnvp.c14
-rw-r--r--src/preproc/html/pre-html.cpp129
-rw-r--r--src/roff/groff/pipeline.c64
6 files changed, 209 insertions, 88 deletions
diff --git a/ChangeLog b/ChangeLog
index e0e00e43..c1f270d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2004-02-27 Jeff Conrad <jeff_conrad@msn.com>
+
+ * src/include/nonposix.h (write, dup, dup2, close) [_MSC_VER]:
+ New macros.
+
+ * src/roff/groff/pipeline.c: Declare strcasecmp.
+ (run_pipeline) [_WIN32]: Use function name variants which don't
+ start with `_'.
+ Fix stream handling.
+
+2004-02-27 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ * src/include/nonposix.h: Fix declaration of `system_shell_name'.
+ Declare `spawnvp_wrapper' and macro definitions of spawnvp only
+ for platforms which use the native Win32 runtime libraries.
+ (FLUSH_INPUT_PIPE) [_UWIN]: Provide non-empty version.
+
+ * src/libs/libgroff/quotearg.c (QUOTE_ARG_MALLOC_ERROR,
+ QUOTE_ARG_REALLOC_ERROR): Fix string.
+
+ * src/preproc/html/pre-html.cpp: Remove declaration of
+ `spawnvp_wrapper'.
+ Don't use __MINGW32__.
+ s/DEBUG_FILE/DEBUG_FILE_DIR/.
+ (DEBUG_TEXT, DEBUG_NAME, DEBUG_FILE) [DEBUGGING]: New macros.
+ (OUTPUT_STREAM, PS_OUTPUT_STREAM, REGION_OUTPUT_STREAM): New macros.
+ (char_buffer::run_output_filter) [MAY_FORK_CHILD_PROCESS]: Fix
+ calls to `set_redirection' and `WAIT'.
+ [MAY_SPAWN_ASYNCHRONOUS_CHILD]: Remove unused variable `i' and `j'.
+ Fix calls to `set_redirection' and `save_and_redirect'.
+ (char_buffer::do_html, char_buffer::do_image) [DEBUGGING]: Fix calls
+ to `set_redirection' and `save_and_redirect'.
+ (usage): Fix message.
+ (makeTempFiles, main): Use `DEBUG_FILE'.
+
2004-02-21 Werner LEMBERG <wl@gnu.org>
* src/roff/troff/troff.h (WARN_TOTAL): Fix value.
diff --git a/src/include/nonposix.h b/src/include/nonposix.h
index dfbe6d0a..706729d0 100644
--- a/src/include/nonposix.h
+++ b/src/include/nonposix.h
@@ -59,17 +59,11 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
# define WAIT(s,p,m) _cwait(s,p,m)
# define creat(p,m) _creat(p,m)
# define read(f,b,s) _read(f,b,s)
+# define write(f,b,s) _write(f,b,s)
+# define dup(f) _dup(f)
+# define dup2(f1,f2) _dup2(f1,f2)
+# define close(f) _close(f)
# define isatty(f) _isatty(f)
-
-/* Workaround for broken argument parsing
- in child process invoked through MSVC `spawnvp()' function. */
-# ifndef SPAWNVP_C
-# undef spawnvp
-# define spawnvp spawnvp_wrapper
-# undef _spawnvp
-# define _spawnvp spawnvp
-# endif
-
# endif
# define SET_BINARY(f) do {if (!isatty(f)) setmode(f,O_BINARY);} while(0)
# define FOPEN_RB "rb"
@@ -123,17 +117,19 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
# ifdef __cplusplus
extern "C" {
# endif
- const char * system_shell_name(void);
+ char * system_shell_name(void);
const char * system_shell_dash_c(void);
int is_system_shell(const char *);
- int spawnvp_wrapper(int, char *, char **);
# ifdef __cplusplus
}
# endif
#endif
-#if defined(_WIN32) && !defined(__CYGWIN__)
+#if defined(_WIN32) && !defined(_UWIN) && !defined(__CYGWIN__)
+/* Win32 implementations which use the Microsoft runtime library
+ * are prone to hanging when a pipe reader quits with unread data in the pipe.
+ * `gtroff' avoids this, by invoking `FLUSH_INPUT_PIPE()', defined as ... */
# define FLUSH_INPUT_PIPE(fd) \
do if (!isatty(fd)) \
{ \
@@ -141,7 +137,30 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
while (read(fd, drain, sizeof(drain)) > 0) \
; \
} while (0)
+
+/* The Microsoft runtime library also has a broken argument passing mechanism,
+ * which may result in improper grouping of arguments passed to a child process
+ * by the `spawn()' family of functions. In `groff', only the `spawnvp()'
+ * function is affected; we work around this defect, by substituting a
+ * wrapper function in place of `spawnvp()' calls. */
+
+# ifdef __cplusplus
+ extern "C" {
+# endif
+ int spawnvp_wrapper(int, char *, char **);
+# ifdef __cplusplus
+ }
+# endif
+# ifndef SPAWN_FUNCTION_WRAPPERS
+# undef spawnvp
+# define spawnvp spawnvp_wrapper
+# undef _spawnvp
+# define _spawnvp spawnvp
+# endif /* SPAWN_FUNCTION_WRAPPERS */
+
#else
+/* Other implementations do not suffer from Microsoft runtime bugs,
+ * but `gtroff' requires a dummy definition for FLUSH_INPUT_PIPE() */
# define FLUSH_INPUT_PIPE(fd) do {} while(0)
#endif
diff --git a/src/libs/libgroff/quotearg.c b/src/libs/libgroff/quotearg.c
index 62edfd27..728a29ea 100644
--- a/src/libs/libgroff/quotearg.c
+++ b/src/libs/libgroff/quotearg.c
@@ -28,7 +28,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* Define the default mechanism, and messages, for error reporting
* (user may substitute a preferred alternative, by defining his own
* implementation of the macros REPORT_ERROR, QUOTE_ARG_MALLOC_FAILED
- * and QUOTE_ARG_REALLOC_FAILED, in a header file called 'nonposix.h').
+ * and QUOTE_ARG_REALLOC_FAILED, in the header file `nonposix.h').
*/
#include "nonposix.h"
@@ -37,10 +37,10 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
# define REPORT_ERROR(WHY) fprintf(stderr, "%s:%s\n", program_name, WHY)
#endif
#ifndef QUOTE_ARG_MALLOC_ERROR
-# define QUOTE_ARG_MALLOC_ERROR "malloc:buffer allocation failed"
+# define QUOTE_ARG_MALLOC_ERROR "malloc: Buffer allocation failed"
#endif
#ifndef QUOTE_ARG_REALLOC_ERROR
-# define QUOTE_ARG_REALLOC_ERROR "realloc:buffer resize failed"
+# define QUOTE_ARG_REALLOC_ERROR "realloc: Buffer resize failed"
#endif
extern char *program_name; /* main program must define this */
@@ -58,8 +58,8 @@ needs_quoting(const char *string)
if (string == NULL) /* ignore NULL strings */
return FALSE;
- if (*string == '\0') /* preserve explicit null arguments */
- return TRUE;
+ if (*string == '\0') /* explicit arguments of zero length */
+ return TRUE; /* need quoting, so they aren't discarded */
while (*string) {
/* Scan non-NULL strings, up to '\0' terminator,
diff --git a/src/libs/libgroff/spawnvp.c b/src/libs/libgroff/spawnvp.c
index 3022fdbd..e185ec30 100644
--- a/src/libs/libgroff/spawnvp.c
+++ b/src/libs/libgroff/spawnvp.c
@@ -29,12 +29,12 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
# include <process.h>
#endif
-#define SPAWNVP_C 1
+#define SPAWN_FUNCTION_WRAPPERS 1
/* Define the default mechanism, and messages, for error reporting
* (user may substitute a preferred alternative, by defining his own
- * implementation of the macros REPORT_ERROR, QUOTE_ARG_MALLOC_FAILED
- * and QUOTE_ARG_REALLOC_FAILED, in a header file called 'nonposix.h').
+ * implementation of the macros REPORT_ERROR and ARGV_MALLOC_ERROR,
+ * in the header file `nonposix.h').
*/
#include "nonposix.h"
@@ -42,8 +42,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef REPORT_ERROR
# define REPORT_ERROR(WHY) fprintf(stderr, "%s:%s\n", program_name, WHY)
#endif
-#ifndef SPAWNVP_MALLOC_ERROR
-# define SPAWNVP_MALLOC_ERROR "malloc:allocation for 'argv' failed"
+#ifndef ARGV_MALLOC_ERROR
+# define ARGV_MALLOC_ERROR "malloc: Allocation for 'argv' failed"
#endif
extern char *program_name;
@@ -84,12 +84,12 @@ spawnvp_wrapper(int mode, char *path, char **argv)
/* If we didn't get enough space,
* then complain, and bail out gracefully. */
- REPORT_ERROR(SPAWNVP_MALLOC_ERROR);
+ REPORT_ERROR(ARGV_MALLOC_ERROR);
exit(1);
}
/* Now copy the passed `argv' into our new vector,
- * quoting it contents as required. */
+ * quoting its contents as required. */
for (i = 0; i < argc; i++)
quoted_argv[i] = quote_arg(argv[i]);
diff --git a/src/preproc/html/pre-html.cpp b/src/preproc/html/pre-html.cpp
index 604547d1..0eb0772e 100644
--- a/src/preproc/html/pre-html.cpp
+++ b/src/preproc/html/pre-html.cpp
@@ -70,28 +70,23 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
# include <process.h> // for `spawn...'
# include <fcntl.h> // for attributes of pipes
-# if defined(__CYGWIN__) || defined(_UWIN) \
- || defined(__MINGW32__) || defined(_WIN32)
+# if defined(__CYGWIN__) || defined(_UWIN) || defined(_WIN32)
// These Win32 implementations allow parent and `spawn...'ed child to
// multitask asynchronously.
-# ifdef __cplusplus
-extern "C" spawnvp_wrapper(int, char *, char **);
-# endif
-
# define MAY_SPAWN_ASYNCHRONOUS_CHILD 1
# else
// Others may adopt MS-DOS behaviour where parent must sleep,
-// from `spawn...' until child terminates. */
+// from `spawn...' until child terminates.
# define MAY_SPAWN_ASYNCHRONOUS_CHILD 0
-# endif /* not defined __CYGWIN__, _UWIN, or __MINGW32__ */
+# endif /* not defined __CYGWIN__, _UWIN, or _WIN32 */
-# if defined(DEBUGGING) && !defined(DEBUG_FILE)
+# if defined(DEBUGGING) && !defined(DEBUG_FILE_DIR)
/* When we are building a DEBUGGING version we need to tell pre-grohtml
where to put intermediate files (the DEBUGGING version will preserve
these on exit).
@@ -101,11 +96,11 @@ extern "C" spawnvp_wrapper(int, char *, char **);
`c:/temp' instead. (Note that user may choose to override this by
supplying a definition such as
- -DDEBUG_FILE="d:/path/to/debug/files/"
+ -DDEBUG_FILE_DIR=d:/path/to/debug/files
+
+ in the CPPFLAGS to `make'.) */
- in the CPPFLAGS to `make'. If overriding in this manner, the trailing
- `/' MUST be included in the definition.) */
-# define DEBUG_FILE "c:/temp/"
+# define DEBUG_FILE_DIR c:/temp
# endif
#else /* not __MSDOS__ or _WIN32 */
@@ -115,20 +110,31 @@ extern "C" spawnvp_wrapper(int, char *, char **);
# define MAY_FORK_CHILD_PROCESS 1
# define MAY_SPAWN_ASYNCHRONOUS_CHILD 1
-# if defined(DEBUGGING) && !defined(DEBUG_FILE)
+# if defined(DEBUGGING) && !defined(DEBUG_FILE_DIR)
/* For a DEBUGGING version, on the UNIX host, we can also usually rely
on being able to use `/tmp' for temporary file storage. (Note that,
as in the __MSDOS__ or _WIN32 case above, the user may override this
by defining
- -DDEBUG_FILE="/path/to/debug/files/"
+ -DDEBUG_FILE_DIR=/path/to/debug/files
- in the CPPFLAGS, again noting that the trailing `/' is REQUIRED.) */
-# define DEBUG_FILE "/tmp/"
+ in the CPPFLAGS.) */
+
+# define DEBUG_FILE_DIR /tmp
# endif
#endif /* not __MSDOS__ or _WIN32 */
+#ifdef DEBUGGING
+// For a DEBUGGING version, we need some additional macros,
+// to direct the captured debug mode output to appropriately named files
+// in the specified DEBUG_FILE_DIR.
+
+# define DEBUG_TEXT(text) #text
+# define DEBUG_NAME(text) DEBUG_TEXT(text)
+# define DEBUG_FILE(name) DEBUG_NAME(DEBUG_FILE_DIR) "/" name
+#endif
+
extern "C" const char *Version_string;
#include "pre-html.h"
@@ -744,8 +750,11 @@ void char_buffer::skip_until_newline(char_block **t, int *i)
}
#define DEVICE_FORMAT(filter) (filter == HTML_OUTPUT_FILTER)
-#define HTML_OUTPUT_FILTER 0
-#define IMAGE_OUTPUT_FILTER 1
+#define HTML_OUTPUT_FILTER 0
+#define IMAGE_OUTPUT_FILTER 1
+#define OUTPUT_STREAM(name) creat((name), S_IWUSR | S_IRUSR)
+#define PS_OUTPUT_STREAM OUTPUT_STREAM(psFileName)
+#define REGION_OUTPUT_STREAM OUTPUT_STREAM(regionFileName)
/*
* emit_troff_output - Write formatted buffer content to the troff
@@ -1276,7 +1285,6 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv)
sys_fatal("pipe");
#if MAY_FORK_CHILD_PROCESS
-
// This is the UNIX process model. To invoke our post-processor,
// we must `fork' the current process.
@@ -1290,8 +1298,8 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv)
set_redirection(STDIN_FILENO, pipedes[0]);
- // The parent process will be writing this data so we should release
- // the child's writeable handle on the pipe.
+ // The parent process will be writing this data, so we should release
+ // the child's writeable handle on the pipe, since we have no use for it.
if (close(pipedes[1]) < 0)
sys_fatal("close");
@@ -1301,10 +1309,8 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv)
if (filter == IMAGE_OUTPUT_FILTER) {
// with BOTH `stdout' AND `stderr' diverted to files.
- set_redirection(STDOUT_FILENO,
- creat(psFileName, S_IWUSR | S_IRUSR));
- set_redirection(STDERR_FILENO,
- creat(regionFileName, S_IWUSR | S_IRUSR));
+ set_redirection(STDOUT_FILENO, PS_OUTPUT_STREAM);
+ set_redirection(STDERR_FILENO, REGION_OUTPUT_STREAM);
}
// Now we are ready to launch the output filter.
@@ -1321,14 +1327,14 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv)
else {
// This is the parent process fork. We will be writing data to the
- // filter pipeline but we can close our handle on the output end of
- // the pipe so we don't block the output data stream.
+ // filter pipeline, and the child will be reading it. We have no further
+ // use for our read handle on the pipe, and should close it.
if (close(pipedes[0]) < 0)
sys_fatal("close");
- // Now we redirect the `stdout' stream to the inlet end of the pipe.
- // Push out the appropiately formatted data to the filter.
+ // Now we redirect the `stdout' stream to the inlet end of the pipe,
+ // and push out the appropiately formatted data to the filter.
pipedes[1] = save_and_redirect(STDOUT_FILENO, pipedes[1]);
emit_troff_output(DEVICE_FORMAT(filter));
@@ -1338,16 +1344,16 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv)
set_redirection(STDOUT_FILENO, pipedes[1]);
- // Finally we must wait for the child process to complete.
+ // Finally, we must wait for the child process to complete.
- if (WAIT(&status, &child_pid, _WAIT_CHILD) != child_pid)
+ if (WAIT(&status, child_pid, _WAIT_CHILD) != child_pid)
sys_fatal("wait");
}
#elif MAY_SPAWN_ASYNCHRONOUS_CHILD
- int i, j;
-
+ // We do not have `fork', (or we prefer not to use it),
+ // but asynchronous processes are allowed, passing data through pipes.
// This should be ok for most Win32 systems and is preferred to `fork'
// for starting child processes under Cygwin.
@@ -1357,6 +1363,9 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv)
pipedes[0] = save_and_redirect(STDIN_FILENO, pipedes[0]);
+ // for the Win32 model,
+ // we need special provision for saving BOTH `stdout' and `stderr'.
+
int saved_stdout = dup(STDOUT_FILENO);
int saved_stderr = STDERR_FILENO;
@@ -1366,10 +1375,8 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv)
// with BOTH `stdout' AND `stderr' diverted to files while saving a
// duplicate handle for `stderr'.
- set_redirection(STDOUT_FILENO, creat(psFileName, S_IWUSR | S_IRUSR));
- saved_stderr =
- save_and_redirect(STDERR_FILENO,
- creat(regionFileName, S_IWUSR | S_IRUSR));
+ set_redirection(STDOUT_FILENO, PS_OUTPUT_STREAM);
+ saved_stderr = save_and_redirect(STDERR_FILENO, REGION_OUTPUT_STREAM);
}
// We then use an asynchronous spawn request to start the post-processor.
@@ -1382,20 +1389,38 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv)
}
// Once the post-processor has been started we revert our `stdin'
- // to its original saved source which also closes the readable handle
+ // to its original saved source, which also closes the readable handle
// for the pipe.
set_redirection(STDIN_FILENO, pipedes[0]);
- set_redirection(STDERR_FILENO, saved_stderr);
+ // if we redirected `stderr', for use by the image post-processor,
+ // then we also need to reinstate its original assignment.
+
+ if (filter == IMAGE_OUTPUT_FILTER)
+ set_redirection(STDERR_FILENO, saved_stderr);
+
+ // Now we redirect the `stdout' stream to the inlet end of the pipe,
+ // and push out the appropiately formatted data to the filter.
+
set_redirection(STDOUT_FILENO, pipedes[1]);
emit_troff_output(DEVICE_FORMAT(filter));
+ // After emitting all the data we close our connection to the inlet
+ // end of the pipe so the child process will detect end of data.
+
set_redirection(STDOUT_FILENO, saved_stdout);
+ // And finally, we must wait for the child process to complete.
+
if (WAIT(&status, child_pid, _WAIT_CHILD) != child_pid)
sys_fatal("wait");
+#else /* can't do asynchronous pipes! */
+
+ // TODO: code to support an MS-DOS style process model
+ // should go here
+
#endif /* MAY_FORK_CHILD_PROCESS or MAY_SPAWN_ASYNCHRONOUS_CHILD */
return 0;
@@ -1424,10 +1449,12 @@ int char_buffer::do_html(int argc, char *argv[])
argc++;
#if defined(DEBUGGING)
+# define HTML_DEBUG_STREAM OUTPUT_STREAM(htmlFileName)
// slight security risk so only enabled if compiled with defined(DEBUGGING)
if (debug) {
- set_redirection(STDOUT_FILENO, creat(htmlFileName, S_IWUSR | S_IRUSR));
+ int saved_stdout = save_and_redirect(STDOUT_FILENO, HTML_DEBUG_STREAM);
emit_troff_output(DEVICE_FORMAT(HTML_OUTPUT_FILTER));
+ set_redirection(STDOUT_FILENO, saved_stdout);
}
#endif
@@ -1459,10 +1486,12 @@ int char_buffer::do_image(int argc, char *argv[])
argc++;
#if defined(DEBUGGING)
+# define IMAGE_DEBUG_STREAM OUTPUT_STREAM(troffFileName)
// slight security risk so only enabled if compiled with defined(DEBUGGING)
if (debug) {
- set_redirection(STDOUT_FILENO, creat(troffFileName, S_IWUSR | S_IRUSR));
+ int saved_stdout = save_and_redirect(STDOUT_FILENO, IMAGE_DEBUG_STREAM);
emit_troff_output(DEVICE_FORMAT(IMAGE_OUTPUT_FILTER));
+ set_redirection(STDOUT_FILENO, saved_stdout);
}
#endif
@@ -1480,7 +1509,7 @@ static void usage(FILE *stream)
fprintf(stream,
"usage: %s troffname [-Iimage_name] [-Dimage_directory]\n"
" [-P-o vertical_image_offset] [-P-i image_resolution]\n"
- " [troff flags] [files]\n",
+ " [troff flags]\n",
program_name);
fprintf(stream,
" vertical_image_offset (default %d/72 of an inch)\n",
@@ -1602,12 +1631,12 @@ static int scanArguments(int argc, char **argv)
static int makeTempFiles(void)
{
#if defined(DEBUGGING)
- psFileName = DEBUG_FILE"prehtml-ps";
- regionFileName = DEBUG_FILE"prehtml-region";
- imagePageName = DEBUG_FILE"prehtml-page";
- psPageName = DEBUG_FILE"prehtml-psn";
- troffFileName = DEBUG_FILE"prehtml-troff";
- htmlFileName = DEBUG_FILE"prehtml-html";
+ psFileName = DEBUG_FILE("prehtml-ps");
+ regionFileName = DEBUG_FILE("prehtml-region");
+ imagePageName = DEBUG_FILE("prehtml-page");
+ psPageName = DEBUG_FILE("prehtml-psn");
+ troffFileName = DEBUG_FILE("prehtml-troff");
+ htmlFileName = DEBUG_FILE("prehtml-html");
#else /* not DEBUGGING */
FILE *f;
@@ -1667,7 +1696,7 @@ int main(int argc, char **argv)
fprintf(stderr, "%s: invoked with %d arguments ...\n", argv[0], argc);
for (i = 0; i < argc; i++)
fprintf(stderr, "%2d: %s\n", i, argv[i]);
- if ((dump = fopen(DEBUG_FILE"pre-html-data", "wb")) != NULL) {
+ if ((dump = fopen(DEBUG_FILE("pre-html-data"), "wb")) != NULL) {
while((i = fgetc(stdin)) >= 0)
fputc(i, dump);
fclose(dump);
diff --git a/src/roff/groff/pipeline.c b/src/roff/groff/pipeline.c
index 2d7ba362..b51ed50e 100644
--- a/src/roff/groff/pipeline.c
+++ b/src/roff/groff/pipeline.c
@@ -102,6 +102,8 @@ static const char *sh = "sh";
static const char *cmd = "cmd";
static const char *command = "command";
+extern int strcasecmp(const char *, const char *);
+
char *sbasename(const char *path)
{
char *base;
@@ -189,13 +191,22 @@ int is_system_shell(const char *prog)
#ifdef _WIN32
-/* Windows 32 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 save_stdin, save_stdout;
int i;
- int last_input = 0;
+ int last_input;
+ int save_stdin;
+ int save_stdout;
int ret = 0;
char err_str[BUFSIZ];
PID_T pids[MAX_COMMANDS];
@@ -209,18 +220,22 @@ int 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) {
+ 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(STDOUT_FILENO)) < 0)
+ if ((save_stdout = dup(STDOUT_FILENO)) < 0)
sys_fatal("dup stdout");
+
/* connect stdout to write end of pipe */
- if (_dup2(pdes[1], STDOUT_FILENO) < 0) {
+ if (dup2(pdes[1], STDOUT_FILENO) < 0) {
sprintf(err_str, "%s: dup2(stdout)", commands[i][0]);
sys_fatal(err_str);
}
@@ -228,17 +243,26 @@ int 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, STDIN_FILENO) < 0) {
+ if (dup2(last_input, STDIN_FILENO) < 0) {
sprintf(err_str, " %s: dup2(stdin)", commands[i][0]);
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], STDOUT_FILENO) < 0) {
+ if (dup2(pdes[1], STDOUT_FILENO) < 0) {
sprintf(err_str, "%s: dup2(stdout)", commands[i][0]);
sys_fatal(err_str);
}
@@ -251,7 +275,7 @@ int 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, STDIN_FILENO) < 0) {
+ if (dup2(last_input, STDIN_FILENO) < 0) {
sprintf(err_str, "%s: dup2(stdin)", commands[i][0]);
sys_fatal(err_str);
}
@@ -260,7 +284,7 @@ int run_pipeline(int ncommands, char ***commands, int no_pipe)
sys_fatal(err_str);
}
/* restore original stdout */
- if (_dup2(save_stdout, STDOUT_FILENO) < 0) {
+ if (dup2(save_stdout, STDOUT_FILENO) < 0) {
sprintf(err_str, "%s: dup2(save_stdout))", commands[i][0]);
sys_fatal(err_str);
}
@@ -271,7 +295,7 @@ int run_pipeline(int ncommands, char ***commands, int no_pipe)
}
}
}
- 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 */
@@ -279,13 +303,27 @@ int 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 = WAIT(&status, pid, _WAIT_CHILD)) < 0) {
- sprintf(err_str, "%s: cwait", commands[i][0]);
+ sprintf(err_str, "%s: wait", commands[i][0]);
sys_fatal(err_str);
}
else if (status != 0)