summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2006-03-31 01:17:06 +0000
committerMark Mitchell <mark@codesourcery.com>2006-03-31 01:17:06 +0000
commit0ad151e1126c675e6f1ddd877c154011e862f19f (patch)
tree6667bc7f6dbbc59ad4188025f00b9bc7d76496be
parent075ca7ec4e94f3691541141551269e7a98f912b5 (diff)
downloadgdb-0ad151e1126c675e6f1ddd877c154011e862f19f.tar.gz
* libiberty/configure.ac: Add cygpath for mingw hosts.
* libiberty.configure: Rebuilt. * libiberty/Makefile.in: Add cygpath. * libiberty/cygpath.c: New. * include/libiberty.h (pex_write_input): New declaration. * libiberty/pex-common.c (pex_write_input): New function. * libiberty/pexecute.txh (pex_write_input): Document it. * libiberty/pex-common.h (struct pex_funcs): New function ptr fdopenw. * libiberty/pex-unix.c (pex_unix_fdopenw): New function. (funcs): List it as our fdopenw function. * libiberty/pex-win32.c (pex_win32_fdopenw): New function. (funcs): List it as our fdopenw function. * libiberty/pex-djgpp.c (funcs): Leave fdopenw null. * libiberty/pex-msdos (funcs): Same. * libiberty/functions.texi: Regenerated. * libiberty/pex-common.h (struct pex_obj): Doc fixes. * libiberty/functions.texi: Regenerate.
-rw-r--r--ChangeLog.csl26
-rw-r--r--include/libiberty.h27
-rw-r--r--libiberty/Makefile.in10
-rwxr-xr-xlibiberty/configure14
-rw-r--r--libiberty/configure.ac7
-rw-r--r--libiberty/cygpath.c270
-rw-r--r--libiberty/functions.texi67
-rw-r--r--libiberty/pex-common.c50
-rw-r--r--libiberty/pex-common.h5
-rw-r--r--libiberty/pex-djgpp.c1
-rw-r--r--libiberty/pex-msdos.c1
-rw-r--r--libiberty/pex-unix.c11
-rw-r--r--libiberty/pex-win32.c14
-rw-r--r--libiberty/pexecute.txh29
14 files changed, 521 insertions, 11 deletions
diff --git a/ChangeLog.csl b/ChangeLog.csl
index 739f40f07c4..b139379d734 100644
--- a/ChangeLog.csl
+++ b/ChangeLog.csl
@@ -1,3 +1,29 @@
+2006-03-30 Mark Mitchell <mark@codesourcery.com>
+
+ * libiberty/configure.ac: Add cygpath for mingw hosts.
+ * libiberty.configure: Rebuilt.
+ * libiberty/Makefile.in: Add cygpath.
+ * libiberty/cygpath.c: New.
+
+2006-03-30 Jim Blandy <jimb@codesourcery.com>
+
+ * include/libiberty.h (pex_write_input): New declaration.
+
+ * libiberty/pex-common.c (pex_write_input): New function.
+ * libiberty/pexecute.txh (pex_write_input): Document it.
+ * libiberty/pex-common.h (struct pex_funcs): New function ptr fdopenw.
+ * libiberty/pex-unix.c (pex_unix_fdopenw): New function.
+ (funcs): List it as our fdopenw function.
+ * libiberty/pex-win32.c (pex_win32_fdopenw): New function.
+ (funcs): List it as our fdopenw function.
+ * libiberty/pex-djgpp.c (funcs): Leave fdopenw null.
+ * libiberty/pex-msdos (funcs): Same.
+ * libiberty/functions.texi: Regenerated.
+
+ * libiberty/pex-common.h (struct pex_obj): Doc fixes.
+
+ * libiberty/functions.texi: Regenerate.
+
2006-03-27 Mark Mitchell <mark@codesourcery.com>
* libiberty/pex-win32.c (pex_win32_exec_child): Close stdout/stderr
diff --git a/include/libiberty.h b/include/libiberty.h
index c264cb2ab0e..6fdc6e9d0c8 100644
--- a/include/libiberty.h
+++ b/include/libiberty.h
@@ -448,6 +448,33 @@ extern const char *pex_run (struct pex_obj *obj, int flags,
const char *outname, const char *errname,
int *err);
+/* Return a `FILE' pointer FP for the standard input of the first
+ program in the pipeline; FP is opened for writing. You must have
+ passed `PEX_USE_PIPES' to the `pex_init' call that returned OBJ.
+ You must close FP yourself with `fclose' to indicate that the
+ pipeline's input is complete.
+
+ The file descriptor underlying FP is marked not to be inherited by
+ child processes.
+
+ This call is not supported on systems which do not support pipes;
+ it returns with an error. (We could implement it by writing a
+ temporary file, but then you would need to write all your data and
+ close FP before your first call to `pex_run' -- and that wouldn't
+ work on systems that do support pipes: the pipe would fill up, and
+ you would block. So there isn't any easy way to conceal the
+ differences between the two types of systems.)
+
+ If you call both `pex_write_input' and `pex_read_output', be
+ careful to avoid deadlock. If the output pipe fills up, so that
+ each program in the pipeline is waiting for the next to read more
+ data, and you fill the input pipe by writing more data to FP, then
+ there is no way to make progress: the only process that could read
+ data from the output pipe is you, but you are blocked on the input
+ pipe. */
+
+extern FILE *pex_write_input (struct pex_obj *obj, int binary);
+
/* Read the standard output of the last program to be executed.
pex_run can not be called after this. BINARY should be non-zero if
the file should be opened in binary mode; this is ignored on Unix.
diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in
index dcd5ebd86d1..77848ad5928 100644
--- a/libiberty/Makefile.in
+++ b/libiberty/Makefile.in
@@ -129,7 +129,7 @@ COMPILE.c = $(CC) -c @DEFS@ $(LIBCFLAGS) -I. -I$(INCDIR) $(HDEFINES) @ac_libiber
CFILES = alloca.c argv.c asprintf.c atexit.c \
basename.c bcmp.c bcopy.c bsearch.c bzero.c \
calloc.c choose-temp.c clock.c concat.c cp-demangle.c \
- cp-demint.c cplus-dem.c \
+ cp-demint.c cplus-dem.c cygpath.c \
dyn-string.c \
fdmatch.c ffs.c fibheap.c floatformat.c fnmatch.c \
fopen_unlocked.c \
@@ -186,7 +186,7 @@ REQUIRED_OFILES = ./regex.o ./cplus-dem.o ./cp-demangle.o ./md5.o \
# maint-missing" and "make check".
CONFIGURED_OFILES = ./asprintf.o ./atexit.o \
./basename.o ./bcmp.o ./bcopy.o ./bsearch.o ./bzero.o \
- ./calloc.o ./clock.o ./copysign.o \
+ ./calloc.o ./clock.o ./copysign.o ./cygpath.o \
./_doprnt.o \
./ffs.o \
./getcwd.o ./getpagesize.o ./gettimeofday.o \
@@ -548,6 +548,12 @@ $(CONFIGURED_OFILES): stamp-picdir
else true; fi
$(COMPILE.c) $(srcdir)/cplus-dem.c $(OUTPUT_OPTION)
+./cygpath.o: $(srcdir)/cygpath.c $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h
+ if [ x"$(PICFLAG)" != x ]; then \
+ $(COMPILE.c) $(PICFLAG) $(srcdir)/cygpath.c -o pic/$@; \
+ else true; fi
+ $(COMPILE.c) $(srcdir)/cygpath.c $(OUTPUT_OPTION)
+
./dyn-string.o: $(srcdir)/dyn-string.c config.h $(INCDIR)/ansidecl.h \
$(INCDIR)/dyn-string.h $(INCDIR)/libiberty.h
if [ x"$(PICFLAG)" != x ]; then \
diff --git a/libiberty/configure b/libiberty/configure
index 59633d520fc..8a866d89f89 100755
--- a/libiberty/configure
+++ b/libiberty/configure
@@ -8205,6 +8205,20 @@ case "${host}" in
esac
+# On MinGW, add support for Cygwin paths.
+case "${host}" in
+ *-*-mingw*)
+ case $LIBOBJS in
+ "cygpath.$ac_objext" | \
+ *" cygpath.$ac_objext" | \
+ "cygpath.$ac_objext "* | \
+ *" cygpath.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS cygpath.$ac_objext" ;;
+esac
+
+ ;;
+esac
+
if test x$gcc_no_link = xyes; then
if test "x${ac_cv_func_mmap_fixed_mapped+set}" != xset; then
ac_cv_func_mmap_fixed_mapped=no
diff --git a/libiberty/configure.ac b/libiberty/configure.ac
index a57685a14ec..9c1eed9bbed 100644
--- a/libiberty/configure.ac
+++ b/libiberty/configure.ac
@@ -618,6 +618,13 @@ case "${host}" in
esac
AC_SUBST(pexecute)
+# On MinGW, add support for Cygwin paths.
+case "${host}" in
+ *-*-mingw*)
+ AC_LIBOBJ([cygpath])
+ ;;
+esac
+
libiberty_AC_FUNC_STRNCMP
# Install a library built with a cross compiler in $(tooldir) rather
diff --git a/libiberty/cygpath.c b/libiberty/cygpath.c
new file mode 100644
index 00000000000..2e7b4c9c968
--- /dev/null
+++ b/libiberty/cygpath.c
@@ -0,0 +1,270 @@
+/* Support Cygwin paths under MinGW.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ Written by CodeSourcery.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or modify it
+under the terms of the GNU Library General Public License as published
+by the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If not, write
+to the Free Software Foundation, Inc., 51 Franklin Street - Fifth
+Floor, Boston, MA 02110-1301, USA. */
+
+#include <windows.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <io.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "libiberty.h"
+
+/* If non-zero, we have attempted to use cygpath. CYGPATH_PEX may
+ still be NULL, if cygpath is unavailable. */
+static int cygpath_initialized;
+
+/* If non-NULL, an instance of cygpath connected via a pipe. */
+static struct pex_obj *cygpath_pex;
+
+/* The input to cygpath. */
+static FILE *cygpath_in;
+
+/* The output from cygpath. */
+static FILE *cygpath_out;
+
+/* CYG_PATH is a pointer to a Cygwin path. This function converts the
+ Cygwin path to a Windows path, storing the result in
+ WIN32_PATH. Returns true if the conversion was successful; false
+ otherwise. */
+static bool
+cygpath (const char *cyg_path, char win32_path[MAX_PATH + 1])
+{
+ bool ok;
+
+ if (!cygpath_initialized)
+ {
+ const char *argv[] = { "cygpath", "-w", "-f", "-", NULL };
+ const char *cygpath_path;
+ int err;
+
+ /* If we are unable to invoke cygpath, we do not want to try
+ again. So, we set the initialized flag at this point; if
+ errors occur during the invocation, it will remain set. */
+ cygpath_initialized = 1;
+ /* Check to see if the user wants cygpath support. */
+ cygpath_path = getenv ("CYGPATH");
+ if (!cygpath_path)
+ /* The user doesn't need to support Cygwin paths. */
+ goto error;
+ /* If the environment variable is set to a non-empty string, use
+ that string as the path to cygpath. */
+ if (cygpath_path[0] != '\0')
+ argv[0] = cygpath_path;
+ /* Create the pex object. */
+ cygpath_pex = pex_init (PEX_SEARCH | PEX_USE_PIPES,
+ "cygpath", NULL);
+ if (!cygpath_pex)
+ goto error;
+ /* Get the FILE we will use to write to the child. */
+ cygpath_in = pex_write_input (cygpath_pex, /*binary=*/0);
+ if (!cygpath_in)
+ goto error;
+ /* Start the child process. */
+ if (pex_run (cygpath_pex, PEX_SEARCH | PEX_USE_PIPES,
+ argv[0], (char**) argv,
+ NULL, NULL,
+ &err) != NULL)
+ goto error;
+ /* Get the FILE we will use to read from the child. */
+ cygpath_out = pex_read_output (cygpath_pex, /*binary=*/1);
+ if (!cygpath_out)
+ goto error;
+ }
+ else if (!cygpath_pex)
+ /* We previously tried to use cygpath, but something went wrong. */
+ return false;
+
+ /* Write CYG_PATH to the child, on a line by itself. */
+ if (fprintf (cygpath_in, "%s\n", cyg_path) < 0)
+ goto error;
+ /* Flush the output. (We cannot set the stream into line-buffered
+ mode with setvbuf because Windows treats _IOLBF as a synonym for
+ _IOFBF.) */
+ fflush (cygpath_in);
+ /* Read the output. */
+ ok = true;
+ while (1)
+ {
+ size_t pathlen;
+ if (!fgets (win32_path, MAX_PATH, cygpath_out))
+ goto error;
+ pathlen = strlen (win32_path);
+ if (pathlen == 0 && ok)
+ /* This isn't a well-formed response from cygpath. */
+ goto error;
+ if (win32_path[pathlen - 1] == '\n')
+ {
+ win32_path[pathlen - 1] = '\0';
+ break;
+ }
+ /* We didn't reach the end of the line. There's no point in
+ trying to use this output, since we know the length of
+ paths are limited to MAX_PATH characters, but we read the
+ entire line so that we are still in sync with
+ cygpath. */
+ ok = false;
+ }
+
+ return ok;
+
+ error:
+
+ /* Free resources. */
+ if (cygpath_out)
+ {
+ fclose (cygpath_out);
+ cygpath_out = NULL;
+ }
+ if (cygpath_in)
+ {
+ fclose (cygpath_in);
+ cygpath_in = NULL;
+ }
+ if (cygpath_pex)
+ {
+ pex_free (cygpath_pex);
+ cygpath_pex = NULL;
+ }
+
+ return false;
+}
+
+/* Returns the handle for the MVCRT DLL, or NULL if it is not
+ available. */
+static HANDLE
+msvcrt_dll (void)
+{
+ static HANDLE dll = INVALID_HANDLE_VALUE;
+
+ /* After we call LoadLibrary, DLL will be either a valid handle or
+ NULL, so this check ensures that we only try to load the library
+ once. */
+ if (dll == INVALID_HANDLE_VALUE)
+ dll = LoadLibrary ("msvcrt.dll");
+
+ return dll;
+}
+
+/* Call the underlying MSVCRT fopen with PATH and MODE, and return
+ what it returns. */
+static FILE *
+msvcrt_fopen (const char *path, const char *mode)
+{
+ typedef FILE *(fopen_type)(const char *path,
+ const char *mode);
+
+ static fopen_type *f = NULL;
+
+ /* Get the address of "fopen". */
+ if (!f)
+ {
+ HANDLE dll = msvcrt_dll ();
+ if (!dll)
+ {
+ errno = ENOSYS;
+ return NULL;
+ }
+ f = (fopen_type *) GetProcAddress (dll, "fopen");
+ if (!f)
+ {
+ errno = ENOSYS;
+ return NULL;
+ }
+ }
+
+ /* Call fopen. */
+ return (*f)(path, mode);
+}
+
+FILE *
+fopen (const char *path, const char *mode)
+{
+ FILE *f;
+ char win32_path[MAX_PATH + 1];
+
+ /* Assume PATH is a Windows path. */
+ f = msvcrt_fopen (path, mode);
+ if (f || errno != ENOENT)
+ return f;
+ /* Perhaps it is a Cygwin path? */
+ if (cygpath (path, win32_path))
+ f = msvcrt_fopen (win32_path, mode);
+ return f;
+}
+
+int
+open (const char *path, int oflag, ...)
+{
+ int fd;
+ char win32_path[MAX_PATH + 1];
+ int pmode = 0;
+
+ if ((oflag & _O_CREAT))
+ {
+ va_list ap;
+ va_start (ap, oflag);
+ pmode = va_arg (ap, int);
+ va_end (ap);
+ }
+
+ /* Assume PATH is a Windows path. */
+ fd = _open (path, oflag, pmode);
+ if (fd != -1 || errno != ENOENT)
+ return fd;
+ /* Perhaps it is a Cygwin path? */
+ if (cygpath (path, win32_path))
+ fd = _open (win32_path, oflag, pmode);
+ return fd;
+}
+
+int
+stat (const char *path, struct stat *buffer)
+{
+ int r;
+ char win32_path[MAX_PATH + 1];
+
+ /* Assume PATH is a Windows path. */
+ r = _stat (path, (struct _stat *) buffer);
+ if (r != -1 || errno != ENOENT)
+ return r;
+ /* Perhaps it is a Cygwin path? */
+ if (cygpath (path, win32_path))
+ r = _stat (win32_path, (struct _stat *) buffer);
+ return r;
+}
+
+int
+access (const char *path, int mode)
+{
+ int r;
+ char win32_path[MAX_PATH + 1];
+
+ /* Assume PATH is a Windows path. */
+ r = _access (path, mode);
+ if (r != -1 || errno != ENOENT)
+ return r;
+ /* Perhaps it is a Cygwin path? */
+ if (cygpath (path, win32_path))
+ r = _access (win32_path, mode);
+ return r;
+}
diff --git a/libiberty/functions.texi b/libiberty/functions.texi
index a09e2075fe1..af03e93f3a9 100644
--- a/libiberty/functions.texi
+++ b/libiberty/functions.texi
@@ -234,6 +234,26 @@ operating system to free the memory when the program exits.
@end deftypefn
+@c argv.c:293
+@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
+
+The @var{argcp} and @code{argvp} arguments are pointers to the usual
+@code{argc} and @code{argv} arguments to @code{main}. This function
+looks for arguments that begin with the character @samp{@@}. Any such
+arguments are interpreted as ``response files''. The contents of the
+response file are interpreted as additional command line options. In
+particular, the file is separated into whitespace-separated strings;
+each such string is taken as a command-line option. The new options
+are inserted in place of the option naming the response file, and
+@code{*argcp} and @code{*argvp} will be updated. If the value of
+@code{*argvp} is modified by this function, then the new value has
+been dynamically allocated and can be deallocated by the caller with
+@code{freeargv}. However, most callers will simply call
+@code{expandargv} near the beginning of @code{main} and allow the
+operating system to free the memory when the program exits.
+
+@end deftypefn
+
@c fdmatch.c:23
@deftypefn Extension int fdmatch (int @var{fd1}, int @var{fd2})
@@ -668,14 +688,14 @@ reading and writing.
@end deftypefn
-@c pexecute.txh:169
+@c pexecute.txh:198
@deftypefn Extension void pex_free (struct pex_obj @var{obj})
Clean up and free all data associated with @var{obj}.
@end deftypefn
-@c pexecute.txh:144
+@c pexecute.txh:173
@deftypefn Extension int pex_get_status (struct pex_obj *@var{obj}, int @var{count}, int *@var{vector})
Returns the exit status of all programs run using @var{obj}.
@@ -685,7 +705,7 @@ to @code{pex_run}. Returns 0 on error, 1 on success.
@end deftypefn
-@c pexecute.txh:153
+@c pexecute.txh:182
@deftypefn Extension int pex_get_times (struct pex_obj *@var{obj}, int @var{count}, struct pex_time *@var{vector})
Returns the process execution times of all programs run using
@@ -702,7 +722,7 @@ process times, all the fields will be set to @code{0}.
@end deftypefn
-@c pexecute.txh:1
+@c pexecute.txh:2
@deftypefn Extension {struct pex_obj *} pex_init (int @var{flags}, const char *@var{pname}, const char *@var{tempbase})
Prepare to execute one or more programs, with standard output of each
@@ -734,7 +754,7 @@ temporary files; it may be @code{NULL} to use a randomly chosen name.
@end deftypefn
-@c pexecute.txh:175
+@c pexecute.txh:204
@deftypefn Extension {const char *} pex_one (int @var{flags}, const char *@var{executable}, char * const *@var{argv}, const char *@var{pname}, const char *@var{outname}, const char *@var{errname}, int *@var{status}, int *@var{err})
An interface to permit the easy execution of a
@@ -747,7 +767,7 @@ be set to the exit status of the program.
@end deftypefn
-@c pexecute.txh:132
+@c pexecute.txh:161
@deftypefn Extension {FILE *} pex_read_output (struct pex_obj *@var{obj}, int @var{binary})
Returns a @code{FILE} pointer which may be used to read the standard
@@ -760,7 +780,7 @@ it will be closed by @code{pex_free}.
@end deftypefn
-@c pexecute.txh:32
+@c pexecute.txh:33
@deftypefn Extension {const char *} pex_run (struct pex_obj *@var{obj}, int @var{flags}, const char *@var{executable}, char * const *@var{argv}, const char *@var{outname}, const char *@var{errname}, int *@var{err})
Execute one program in a pipeline. On success this returns
@@ -861,7 +881,36 @@ value, or to 0 if there is no relevant @code{errno}.
@end deftypefn
-@c pexecute.txh:187
+@c pexecute.txh:133
+@deftypefn Extension {FILE *} pex_write_input (struct pex_obj *@var{obj}, int @var{binary})
+
+Return a @code{FILE} pointer @var{fp} for the standard input of the
+first program in the pipeline; @var{fp} is opened for writing. You
+must have passed @code{PEX_USE_PIPES} to the @code{pex_init} call that
+returned @var{obj}. You must close @var{fp} yourself with
+@code{fclose} to indicate that the pipeline's input is complete.
+
+The file descriptor underlying @var{fp} is marked not to be inherited
+by child processes.
+
+This call is not supported on systems which do not support pipes; it
+returns with an error. (We could implement it by writing a temporary
+file, but then you would need to write all your data and close
+@var{fp} before your first call to @code{pex_run} --- and that
+wouldn't work on systems that do support pipes: the pipe would fill
+up, and you would block. So there isn't any easy way to conceal the
+differences between the two types of systems.)
+
+If you call both @code{pex_write_input} and @code{pex_read_output}, be
+careful to avoid deadlock. If the output pipe fills up, so that each
+program in the pipeline is waiting for the next to read more data, and
+you fill the input pipe by writing more data to @var{fp}, then there
+is no way to make progress: the only process that could read data from
+the output pipe is you, but you are blocked on the input pipe.
+
+@end deftypefn
+
+@c pexecute.txh:216
@deftypefn Extension int pexecute (const char *@var{program}, char * const *@var{argv}, const char *@var{this_pname}, const char *@var{temp_base}, char **@var{errmsg_fmt}, char **@var{errmsg_arg}, int flags)
This is the old interface to execute one or more programs. It is
@@ -889,7 +938,7 @@ name is unset/removed.
@end deftypefn
-@c pexecute.txh:195
+@c pexecute.txh:224
@deftypefn Extension int pwait (int @var{pid}, int *@var{status}, int @var{flags})
Another part of the old execution interface.
diff --git a/libiberty/pex-common.c b/libiberty/pex-common.c
index b2ca6e08ce2..fd0c6b22e9b 100644
--- a/libiberty/pex-common.c
+++ b/libiberty/pex-common.c
@@ -108,6 +108,8 @@ pex_run (struct pex_obj *obj, int flags, const char *executable,
in = -1;
out = -1;
errdes = -1;
+ p[READ_PORT] = -1;
+ p[WRITE_PORT] = -1;
outname = (char *) orig_outname;
outname_allocated = 0;
@@ -276,6 +278,8 @@ pex_run (struct pex_obj *obj, int flags, const char *executable,
pid = obj->funcs->exec_child (obj, flags, executable, argv, in, out, errdes,
&errmsg, err);
+ if (p[WRITE_PORT] != -1)
+ obj->funcs->close (obj, p[WRITE_PORT]);
if (pid < 0)
goto error_exit;
@@ -297,6 +301,52 @@ pex_run (struct pex_obj *obj, int flags, const char *executable,
return errmsg;
}
+/* Return a FILE pointer for the input of the first program
+ executed. */
+
+FILE *
+pex_write_input (struct pex_obj *obj, int binary)
+{
+ int p[2];
+ FILE *write_input;
+
+ /* You must call pex_write_input before the first pex_run or pex_one. */
+ if (obj->count > 0)
+ goto usage_error;
+
+ /* You must be using pipes. Implementations that don't support
+ pipes clear this flag before calling pex_init_common. */
+ if (! (obj->flags & PEX_USE_PIPES))
+ goto usage_error;
+
+ /* If we have somehow already selected other input, that's a
+ mistake. */
+ if ((obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
+ || obj->next_input_name)
+ goto usage_error;
+
+ if (obj->funcs->pipe (obj, p, binary != 0) < 0)
+ return NULL;
+
+ write_input = obj->funcs->fdopenw (obj, p[WRITE_PORT], binary != 0);
+ if (! write_input)
+ {
+ int saved_errno = errno;
+ obj->funcs->close (obj, p[READ_PORT]);
+ obj->funcs->close (obj, p[WRITE_PORT]);
+ errno = saved_errno;
+ return NULL;
+ }
+
+ obj->next_input = p[READ_PORT];
+
+ return write_input;
+
+ usage_error:
+ errno = EINVAL;
+ return NULL;
+}
+
/* Return a FILE pointer for the output of the last program
executed. */
diff --git a/libiberty/pex-common.h b/libiberty/pex-common.h
index b70b38d9736..13ec98149ea 100644
--- a/libiberty/pex-common.h
+++ b/libiberty/pex-common.h
@@ -121,6 +121,11 @@ struct pex_funcs
PEX_USE_PIPES is set). If BINARY is non-zero, open in binary
mode. Return pointer on success, NULL on error. */
FILE * (*fdopenr) (struct pex_obj *, int /* fd */, int /* binary */);
+ /* Get a FILE pointer to write to the file descriptor FD (only
+ called if PEX_USE_PIPES is set). If BINARY is non-zero, open in
+ binary mode. Arrange for FD not to be inherited by the child
+ processes. Return pointer on success, NULL on error. */
+ FILE * (*fdopenw) (struct pex_obj *, int /* fd */, int /* binary */);
/* Free any system dependent data associated with OBJ. May be
NULL if there is nothing to do. */
void (*cleanup) (struct pex_obj *);
diff --git a/libiberty/pex-djgpp.c b/libiberty/pex-djgpp.c
index 6e58e3fd8dc..17fbf2cc7e4 100644
--- a/libiberty/pex-djgpp.c
+++ b/libiberty/pex-djgpp.c
@@ -62,6 +62,7 @@ const struct pex_funcs funcs =
pex_djgpp_wait,
NULL, /* pipe */
NULL, /* fdopenr */
+ NULL, /* fdopenw */
NULL /* cleanup */
};
diff --git a/libiberty/pex-msdos.c b/libiberty/pex-msdos.c
index 2256117d1bb..db22337aa2a 100644
--- a/libiberty/pex-msdos.c
+++ b/libiberty/pex-msdos.c
@@ -73,6 +73,7 @@ const struct pex_funcs funcs =
pex_msdos_wait,
NULL, /* pipe */
NULL, /* fdopenr */
+ NULL, /* fdopenw */
pex_msdos_cleanup
};
diff --git a/libiberty/pex-unix.c b/libiberty/pex-unix.c
index 35a545cb17b..c92a4297971 100644
--- a/libiberty/pex-unix.c
+++ b/libiberty/pex-unix.c
@@ -277,6 +277,7 @@ static int pex_unix_wait (struct pex_obj *, long, int *, struct pex_time *,
int, const char **, int *);
static int pex_unix_pipe (struct pex_obj *, int *, int);
static FILE *pex_unix_fdopenr (struct pex_obj *, int, int);
+static FILE *pex_unix_fdopenw (struct pex_obj *, int, int);
static void pex_unix_cleanup (struct pex_obj *);
/* The list of functions we pass to the common routines. */
@@ -290,6 +291,7 @@ const struct pex_funcs funcs =
pex_unix_wait,
pex_unix_pipe,
pex_unix_fdopenr,
+ pex_unix_fdopenw,
pex_unix_cleanup
};
@@ -495,6 +497,15 @@ pex_unix_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
return fdopen (fd, "r");
}
+static FILE *
+pex_unix_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+ int binary ATTRIBUTE_UNUSED)
+{
+ if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
+ return NULL;
+ return fdopen (fd, "w");
+}
+
static void
pex_unix_cleanup (struct pex_obj *obj ATTRIBUTE_UNUSED)
{
diff --git a/libiberty/pex-win32.c b/libiberty/pex-win32.c
index 3a75c5be004..046f393c6d9 100644
--- a/libiberty/pex-win32.c
+++ b/libiberty/pex-win32.c
@@ -83,6 +83,7 @@ static int pex_win32_wait (struct pex_obj *, long, int *,
struct pex_time *, int, const char **, int *);
static int pex_win32_pipe (struct pex_obj *, int *, int);
static FILE *pex_win32_fdopenr (struct pex_obj *, int, int);
+static FILE *pex_win32_fdopenw (struct pex_obj *, int, int);
/* The list of functions we pass to the common routines. */
@@ -95,6 +96,7 @@ const struct pex_funcs funcs =
pex_win32_wait,
pex_win32_pipe,
pex_win32_fdopenr,
+ pex_win32_fdopenw,
NULL /* cleanup */
};
@@ -766,6 +768,18 @@ pex_win32_fdopenr (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
return fdopen (fd, binary ? "rb" : "r");
}
+static FILE *
+pex_win32_fdopenw (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd,
+ int binary)
+{
+ HANDLE h = (HANDLE) _get_osfhandle (fd);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+ if (! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0))
+ return NULL;
+ return fdopen (fd, binary ? "wb" : "w");
+}
+
#ifdef MAIN
#include <stdio.h>
diff --git a/libiberty/pexecute.txh b/libiberty/pexecute.txh
index 461ff33d018..2bfad0c8b75 100644
--- a/libiberty/pexecute.txh
+++ b/libiberty/pexecute.txh
@@ -1,3 +1,4 @@
+@c -*- mode: texinfo -*-
@deftypefn Extension {struct pex_obj *} pex_init (int @var{flags}, const char *@var{pname}, const char *@var{tempbase})
Prepare to execute one or more programs, with standard output of each
@@ -129,6 +130,34 @@ value, or to 0 if there is no relevant @code{errno}.
@end deftypefn
+@deftypefn Extension {FILE *} pex_write_input (struct pex_obj *@var{obj}, int @var{binary})
+
+Return a @code{FILE} pointer @var{fp} for the standard input of the
+first program in the pipeline; @var{fp} is opened for writing. You
+must have passed @code{PEX_USE_PIPES} to the @code{pex_init} call that
+returned @var{obj}. You must close @var{fp} yourself with
+@code{fclose} to indicate that the pipeline's input is complete.
+
+The file descriptor underlying @var{fp} is marked not to be inherited
+by child processes.
+
+This call is not supported on systems which do not support pipes; it
+returns with an error. (We could implement it by writing a temporary
+file, but then you would need to write all your data and close
+@var{fp} before your first call to @code{pex_run} --- and that
+wouldn't work on systems that do support pipes: the pipe would fill
+up, and you would block. So there isn't any easy way to conceal the
+differences between the two types of systems.)
+
+If you call both @code{pex_write_input} and @code{pex_read_output}, be
+careful to avoid deadlock. If the output pipe fills up, so that each
+program in the pipeline is waiting for the next to read more data, and
+you fill the input pipe by writing more data to @var{fp}, then there
+is no way to make progress: the only process that could read data from
+the output pipe is you, but you are blocked on the input pipe.
+
+@end deftypefn
+
@deftypefn Extension {FILE *} pex_read_output (struct pex_obj *@var{obj}, int @var{binary})
Returns a @code{FILE} pointer which may be used to read the standard