]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
* libiberty/configure.ac: Add cygpath for mingw hosts.
authorMark Mitchell <mark@codesourcery.com>
Fri, 31 Mar 2006 01:17:06 +0000 (01:17 +0000)
committerMark Mitchell <mark@codesourcery.com>
Fri, 31 Mar 2006 01:17:06 +0000 (01:17 +0000)
* 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.

14 files changed:
ChangeLog.csl
include/libiberty.h
libiberty/Makefile.in
libiberty/configure
libiberty/configure.ac
libiberty/cygpath.c [new file with mode: 0644]
libiberty/functions.texi
libiberty/pex-common.c
libiberty/pex-common.h
libiberty/pex-djgpp.c
libiberty/pex-msdos.c
libiberty/pex-unix.c
libiberty/pex-win32.c
libiberty/pexecute.txh

index 739f40f07c416a0d10c772c5a1cf2ea72eeab6d4..b139379d73461c36649c0fb876c0e3dbca884a9d 100644 (file)
@@ -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
index c264cb2ab0ee0df21284133adda17ad30743bcdb..6fdc6e9d0c819fd2534d5a3d3173e0fe98131001 100644 (file)
@@ -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.
index dcd5ebd86d1674168243f148e5e54497422e56b4..77848ad5928f19fc1125d17cd38f8f6cdaded72e 100644 (file)
@@ -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 \
index 59633d520fc05347f786ac45434307326669cb78..8a866d89f89d03706080f76e230b4c91d3c6ca31 100755 (executable)
@@ -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
index a57685a14ec40f2252b29af93105d81b0bbd0f1b..9c1eed9bbed1214f601f428172d12dd24aaab85e 100644 (file)
@@ -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 (file)
index 0000000..2e7b4c9
--- /dev/null
@@ -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;
+}
index a09e2075fe1f68245aaf01618a98abf597bbc96c..af03e93f3a9e34f2717192e5e5fcf9c6ec38f72b 100644 (file)
@@ -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.
index b2ca6e08ce208151554088d44c7b103f5974e839..fd0c6b22e9bf86d03d5c64a07b615ed84e00ab85 100644 (file)
@@ -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.  */
 
index b70b38d9736428d92b2c20e21349d2af1a239a61..13ec98149eaa73e4d403a705e7c85753fbfac5dc 100644 (file)
@@ -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 *);
index 6e58e3fd8dcc864b975f7d220a5eb57e73a43387..17fbf2cc7e4406205068bbdb68da71dd0e065c47 100644 (file)
@@ -62,6 +62,7 @@ const struct pex_funcs funcs =
   pex_djgpp_wait,
   NULL, /* pipe */
   NULL, /* fdopenr */
+  NULL, /* fdopenw */
   NULL  /* cleanup */
 };
 
index 2256117d1bb0cb7d5d20c1224b01827ee5371023..db22337aa2afcd82fe20c3af5cbbbc76120bdbb6 100644 (file)
@@ -73,6 +73,7 @@ const struct pex_funcs funcs =
   pex_msdos_wait,
   NULL, /* pipe */
   NULL, /* fdopenr */
+  NULL, /* fdopenw */
   pex_msdos_cleanup
 };
 
index 35a545cb17b1dccebf2949472cb75d7df6afd9be..c92a429797128c4ba36aff5676649eeded39da47 100644 (file)
@@ -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)
 {
index 3a75c5be004dc204d780f2bccd895c11645be86c..046f393c6d9f7a9aad19b73e89b3860d6931557f 100644 (file)
@@ -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>
 
index 461ff33d018c7ea52ce94933ad81a4fc28f24412..2bfad0c8b751c76d568384789eb44da8b194cb36 100644 (file)
@@ -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