This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Proposed new pexecute interface


Here is a complete implementation of a proposed new pexecute
interface.  This interface is intended to address PR 14316.

I sent in an earlier patch here:
    http://gcc.gnu.org/ml/gcc-patches/2004-03/msg01445.html
Zack had some comments:
    http://gcc.gnu.org/ml/gcc-patches/2004-04/msg00227.html
    http://gcc.gnu.org/ml/gcc-patches/2004-04/msg00637.html
    http://gcc.gnu.org/ml/gcc-patches/2004-04/msg01044.html

And a revised interface here:
    http://gcc.gnu.org/ml/gcc/2005-03/msg00337.html

This patch is a full implementation of a modified version of the
revised interface.

This implementation retains pexecute and pwait for backward
compatibility purposes.  They are implemented using the new code.  I
completed a bootstrap on i686-pc-linux-gnu with this patch and no
other changes to gcc.

This patch has been lightly tested on Windows without Cygwin, and has
not been tested at all on the other two supported hosts: DJGPP and
MSDOS.  I hope that other people can help me out with testing on those
hosts.  I promise to help address all issues which arise.

I would like to hear any comments before I check this in.

To make it easier to evaluate the interface separately from the
implementation, I've put in the description of it from libiberty.h,
followed by the patch itself.  You can also see documentation in the
patch to pexecute.txh.

Ian


/* Flags for pex_init.  These are bits to be or'ed together.  */

/* Record subprocess times, if possible.  */
#define PEX_RECORD_TIMES	0x1

/* Use pipes for communication between processes, if possible.  */
#define PEX_USE_PIPES		0x2

/* Save files used for communication between processes.  */
#define PEX_SAVE_TEMPS		0x4

/* Prepare to execute one or more programs, with standard output of
   each program fed to standard input of the next.
   FLAGS	As above.
   PNAME	The name of the program to report in error messages.
   TEMPBASE	A base name to use for temporary files; may be NULL to
   		use a random name.
   Returns NULL on error.  */

extern struct pex_obj *pex_init PARAMS ((int flags, const char *pname,
					 const char *tempbase));

/* Flags for pex_run.  These are bits to be or'ed together.  */

/* Last program in pipeline.  Standard output of program goes to
   OUTNAME, or, if OUTNAME is NULL, to standard output of caller.  Do
   not set this if you want to call pex_read_output.  After this is
   set, pex_run may no longer be called with the same struct
   pex_obj.  */
#define PEX_LAST		0x1

/* Search for program in executable search path.  */
#define PEX_SEARCH		0x2

/* OUTNAME is a suffix.  */
#define PEX_SUFFIX		0x4

/* Send program's standard error to standard output.  */
#define PEX_STDERR_TO_STDOUT	0x8

/* Input file should be opened in binary mode.  This flag is ignored
   on Unix.  */
#define PEX_BINARY_INPUT	0x10

/* Output file should be opened in binary mode.  This flag is ignored
   on Unix.  For proper behaviour PEX_BINARY_INPUT and
   PEX_BINARY_OUTPUT have to match appropriately--i.e., a call using
   PEX_BINARY_OUTPUT should be followed by a call using
   PEX_BINARY_INPUT.  */
#define PEX_BINARY_OUTPUT	0x20

/* Execute one program.  Returns NULL on success.  On error returns an
   error string (typically just the name of a system call).

   OBJ		Returned by pex_init.

   FLAGS	As above.

   EXECUTABLE	The program to execute.

   ARGV		NULL terminated array of arguments to pass to the program.

   OUTNAME	Sets the output file name as follows:

		PEX_SUFFIX set (OUTNAME may not be NULL):
		  TEMPBASE parameter to pex_init not NULL:
		    Output file name is the concatenation of TEMPBASE
		    and OUTNAME.
		  TEMPBASE is NULL:
		    Output file name is a random file name ending in
		    OUTNAME.
		PEX_SUFFIX not set:
		  OUTNAME not NULL:
		    Output file name is OUTNAME.
		  OUTNAME NULL, TEMPBASE not NULL:
		    Output file name is randomly chosen using
		    TEMPBASE.
		  OUTNAME NULL, TEMPBASE NULL:
		    Output file name is randomly chosen.

		If PEX_LAST is not set, the output file name is the
   		name to use for a temporary file holding stdout, if
   		any (there will not be a file if PEX_USE_PIPES is set
   		and the system supports pipes).  If a file is used, it
   		will be removed when no longer needed unless
   		PEX_SAVE_TEMPS is set.

		If PEX_LAST is set, and OUTNAME is not NULL, standard
   		output is written to the output file name.  The file
   		will not be removed.  If PEX_LAST and PEX_SUFFIX are
   		both set, TEMPBASE may not be NULL.

   ERRNAME	If not NULL, this is the name of a file to which
		standard error is written.  If NULL, standard error of
		the program is standard error of the caller.

   ERR		On an error return, *ERR is set to an errno value, or
   		to 0 if there is no relevant errno.
*/

extern const char *pex_run PARAMS ((struct pex_obj *obj, int flags,
				    const char *executable,
				    char * const *argv,
				    const char *outname,
				    const char *errname,
				    int *err));

/* 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.
   Returns NULL on error.  Don't call fclose on the returned FILE; it
   will be closed by pex_free.  */

extern FILE *pex_read_output PARAMS ((struct pex_obj *, int binary));

/* Return exit status of all programs.  The status codes in the vector
   are in the order of the calls to pex_run.  Returns 0 on error, 1 on
   success.  */

extern int pex_get_status PARAMS ((struct pex_obj *, int count, int *vector));

/* Return times of all programs.  This is really just struct timeval,
   but that is not portable to all systems.  Returns 0 on error, 1 on
   success.  */

struct pex_time
{
  unsigned long user_seconds;
  unsigned long user_microseconds;
  unsigned long system_seconds;
  unsigned long system_microseconds;
};

extern int pex_get_times PARAMS ((struct pex_obj *, int count,
				  struct pex_time *vector));

/* Clean up a pex_obj.  */

extern void pex_free PARAMS ((struct pex_obj *));

/* Just execute one program.  Return value is as for pex_run.
   FLAGS	Combination of PEX_SEARCH and PEX_STDERR_TO_STDOUT.
   EXECUTABLE	As for pex_run.
   ARGV		As for pex_run.
   PNAME	As for pex_init.
   OUTNAME	As for pex_run when PEX_LAST is set.
   ERRNAME	As for pex_run.
   STATUS	Set to exit status on success.
   ERR		As for pex_run.
*/

extern const char *pex_one PARAMS ((int flags,
				    const char *executable,
				    char * const *argv,
				    const char *pname,
				    const char *outname,
				    const char *errname,
				    int *status,
				    int *err));




2005-03-21  Ian Lance Taylor  <ian@airs.com>

	* pex-common.c: New file.
	* pex-one.c: New file.
	* pexecute.c: New file.
	* pex-common.h: Include <stdio.h>.
	(struct pex_obj): Define.
	(struct pex_funcs): Define.
	(pex_init_common): Declare.
	* pex-unix.c: Rewrite.
	* pex-win32.c: Rewrite.
	* pex-djgpp.c: Rewrite.
	* pex-msdos.c: Rewrite.
	* testsuite/text-pexecute.c: New file.
	* pexecute.txh: Rewrite.
	* configure.ac: Check for wait3 and wait4.  Set CHECK to
	really-check rather than check-cplus-dem.
	* functions.texi: Rebuild.
	* Makefile.in: Rebuild dependencies.
	(CFILES): Add pexecute.c, pex-common.c, pex-one.c.
	(REQUIRED_OFILES): Add pexecute.o, pex-common.o, pex-one.o.
	* testsuite/Makefile.in (really-check): New target.
	(check-pexecute, test-pexecute): New targets.
	* configure: Rebuild.

2005-03-21  Ian Lance Taylor  <ian@airs.com>

	* libiberty.h: Include <stdio.h>.
	(PEX_RECORD_TIMES, PEX_USE_PIPES, PEX_SAVE_TEMPS): Define.
	(PEX_LAST, PEX_SEARCH, PEX_SUFFIX, PEX_STDERR_TO_STDOUT): Define.
	(PEX_BINARY_INPUT, PEX_BINARY_OUTPUT): Define.
	(pex_init, pex_run, pex_read_output): Declare.
	(pex_get_status, pex_get_times, pex_free, pex_one): Declare.
	(struct pex_time): Define.


Index: libiberty/Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/Makefile.in,v
retrieving revision 1.109
diff -u -p -r1.109 Makefile.in
--- libiberty/Makefile.in	10 Mar 2005 00:57:10 -0000	1.109
+++ libiberty/Makefile.in	21 Mar 2005 17:17:19 -0000
@@ -142,8 +142,8 @@ CFILES = alloca.c argv.c asprintf.c atex
 	make-temp-file.c md5.c memchr.c memcmp.c memcpy.c memmove.c	\
 	 mempcpy.c memset.c mkstemps.c					\
 	objalloc.c obstack.c						\
-	partition.c							\
-	 pex-djgpp.c pex-msdos.c					\
+	partition.c pexecute.c						\
+	 pex-common.c pex-djgpp.c pex-msdos.c pex-one.c			\
 	 pex-unix.c pex-win32.c						\
          physmem.c putenv.c						\
 	random.c regex.c rename.c rindex.c				\
@@ -169,7 +169,8 @@ REQUIRED_OFILES = ./regex.o ./cplus-dem.
 	./lbasename.o ./lrealpath.o					\
 	./make-relative-prefix.o ./make-temp-file.o			\
 	./objalloc.o ./obstack.o					\
-	./partition.o ./physmem.o @pexecute@				\
+	./partition.o ./pexecute.o ./physmem.o				\
+	./pex-common.o ./pex-one.o @pexecute@				\
 	./safe-ctype.o ./sort.o ./spaces.o ./splay-tree.o ./strerror.o	\
 	 ./strsignal.o							\
 	./ternary.o							\
@@ -755,6 +756,13 @@ $(CONFIGURED_OFILES): stamp-picdir
 	else true; fi
 	$(COMPILE.c) $(srcdir)/partition.c $(OUTPUT_OPTION)
 
+./pex-common.o: $(srcdir)/pex-common.c config.h $(INCDIR)/ansidecl.h \
+	$(INCDIR)/libiberty.h $(srcdir)/pex-common.h
+	if [ x"$(PICFLAG)" != x ]; then \
+	  $(COMPILE.c) $(PICFLAG) $(srcdir)/pex-common.c -o pic/$@; \
+	else true; fi
+	$(COMPILE.c) $(srcdir)/pex-common.c $(OUTPUT_OPTION)
+
 ./pex-djgpp.o: $(srcdir)/pex-djgpp.c config.h $(INCDIR)/ansidecl.h \
 	$(INCDIR)/libiberty.h $(srcdir)/pex-common.h
 	if [ x"$(PICFLAG)" != x ]; then \
@@ -770,6 +778,13 @@ $(CONFIGURED_OFILES): stamp-picdir
 	else true; fi
 	$(COMPILE.c) $(srcdir)/pex-msdos.c $(OUTPUT_OPTION)
 
+./pex-one.o: $(srcdir)/pex-one.c config.h $(INCDIR)/ansidecl.h \
+	$(INCDIR)/libiberty.h
+	if [ x"$(PICFLAG)" != x ]; then \
+	  $(COMPILE.c) $(PICFLAG) $(srcdir)/pex-one.c -o pic/$@; \
+	else true; fi
+	$(COMPILE.c) $(srcdir)/pex-one.c $(OUTPUT_OPTION)
+
 ./pex-unix.o: $(srcdir)/pex-unix.c config.h $(INCDIR)/ansidecl.h \
 	$(INCDIR)/libiberty.h $(srcdir)/pex-common.h
 	if [ x"$(PICFLAG)" != x ]; then \
@@ -784,6 +799,13 @@ $(CONFIGURED_OFILES): stamp-picdir
 	else true; fi
 	$(COMPILE.c) $(srcdir)/pex-win32.c $(OUTPUT_OPTION)
 
+./pexecute.o: $(srcdir)/pexecute.c config.h $(INCDIR)/ansidecl.h \
+	$(INCDIR)/libiberty.h
+	if [ x"$(PICFLAG)" != x ]; then \
+	  $(COMPILE.c) $(PICFLAG) $(srcdir)/pexecute.c -o pic/$@; \
+	else true; fi
+	$(COMPILE.c) $(srcdir)/pexecute.c $(OUTPUT_OPTION)
+
 ./physmem.o: $(srcdir)/physmem.c config.h $(INCDIR)/ansidecl.h \
 	$(INCDIR)/libiberty.h
 	if [ x"$(PICFLAG)" != x ]; then \
Index: libiberty/configure
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/configure,v
retrieving revision 1.87
diff -u -p -r1.87 configure
--- libiberty/configure	9 Mar 2005 21:27:11 -0000	1.87
+++ libiberty/configure	21 Mar 2005 17:17:20 -0000
@@ -4816,7 +4816,7 @@ vars="sys_errlist sys_nerr sys_siglist"
 
 checkfuncs="getrusage on_exit psignal strerror strsignal sysconf times sbrk gettimeofday"
 checkfuncs="$checkfuncs realpath canonicalize_file_name pstat_getstatic pstat_getdynamic sysmp"
-checkfuncs="$checkfuncs getsysinfo table sysctl"
+checkfuncs="$checkfuncs getsysinfo table sysctl wait3 wait4"
 
 # These are neither executed nor required, but they help keep
 # autoheader happy without adding a bunch of text to acconfig.h.
@@ -4884,6 +4884,8 @@ if test "x" = "y"; then
 
 
 
+
+
 for ac_func in asprintf atexit basename bcmp bcopy bsearch bzero calloc clock \
   getcwd getpagesize index insque mkstemps memchr memcmp memcpy \
   memmove mempcpy memset putenv random rename rindex sigsetmask \
@@ -4891,7 +4893,7 @@ for ac_func in asprintf atexit basename 
   strtod strtol strtoul tmpnam vasprintf vfprintf vprintf \
   vsprintf waitpid getrusage on_exit psignal strerror strsignal \
   sysconf times sbrk gettimeofday ffs snprintf vsnprintf \
-  pstat_getstatic pstat_getdynamic sysmp getsysinfo table sysctl \
+  pstat_getstatic pstat_getdynamic sysmp getsysinfo table sysctl wait3 wait4 \
   realpath canonicalize_file_name
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -5129,7 +5131,7 @@ fi;
 else
 
    # Not a target library, so we set things up to run the test suite.
-   CHECK=check-cplus-dem
+   CHECK=really-check
 
 fi
 
Index: libiberty/configure.ac
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/configure.ac,v
retrieving revision 1.15
diff -u -p -r1.15 configure.ac
--- libiberty/configure.ac	10 Mar 2005 00:57:10 -0000	1.15
+++ libiberty/configure.ac	21 Mar 2005 17:17:20 -0000
@@ -267,7 +267,7 @@ vars="sys_errlist sys_nerr sys_siglist"
 
 checkfuncs="getrusage on_exit psignal strerror strsignal sysconf times sbrk gettimeofday"
 checkfuncs="$checkfuncs realpath canonicalize_file_name pstat_getstatic pstat_getdynamic sysmp"
-checkfuncs="$checkfuncs getsysinfo table sysctl"
+checkfuncs="$checkfuncs getsysinfo table sysctl wait3 wait4"
 
 # These are neither executed nor required, but they help keep
 # autoheader happy without adding a bunch of text to acconfig.h.
@@ -279,7 +279,7 @@ if test "x" = "y"; then
   strtod strtol strtoul tmpnam vasprintf vfprintf vprintf \
   vsprintf waitpid getrusage on_exit psignal strerror strsignal \
   sysconf times sbrk gettimeofday ffs snprintf vsnprintf \
-  pstat_getstatic pstat_getdynamic sysmp getsysinfo table sysctl \
+  pstat_getstatic pstat_getdynamic sysmp getsysinfo table sysctl wait3 wait4 \
   realpath canonicalize_file_name)
   AC_DEFINE(HAVE_SYS_ERRLIST, 1, [Define if you have the sys_errlist variable.])
   AC_DEFINE(HAVE_SYS_NERR,    1, [Define if you have the sys_nerr variable.])
@@ -356,7 +356,7 @@ if test -n "${with_target_subdir}"; then
 else
 
    # Not a target library, so we set things up to run the test suite.
-   CHECK=check-cplus-dem
+   CHECK=really-check
 
 fi
 
Index: libiberty/functions.texi
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/functions.texi,v
retrieving revision 1.17
diff -u -p -r1.17 functions.texi
--- libiberty/functions.texi	11 Jan 2005 20:22:38 -0000	1.17
+++ libiberty/functions.texi	21 Mar 2005 17:17:20 -0000
@@ -25,6 +25,151 @@ nineteen EBCDIC varying characters is te
 @end ftable
 @end defvr
 
+@c pexecute.txh:1
+@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
+program fed to standard input of the next.  This is a system
+independent interface to execute a pipeline.
+
+@var{flags} is a bitwise combination of the following:
+
+@table @code
+
+@vindex PEX_RECORD_TIMES
+@item PEX_RECORD_TIMES
+Record subprocess times if possible.
+
+@vindex PEX_USE_PIPES
+@item PEX_USE_PIPES
+Use pipes for communication between processes, if possible.
+
+@vindex PEX_SAVE_TEMPS
+@item PEX_SAVE_TEMPS
+Don't delete temporary files used for communication between
+processes.
+
+@end table
+
+@var{pname} is the name of program to be executed, used in error
+messages.  @var{tempbase} is a base name to use for any required
+temporary files; it may be @code{NULL} to use a randomly chosen name.
+
+@end deftypefn
+
+@c pexecute.txh:160
+@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 @var{pex_init} to permit the easy execution of a
+single program.  The return value and most of the parameters are as
+for a call to @code{pex_run}.  @var{flags} is restricted to a
+combination of @code{PEX_SEARCH}, @code{PEX_STDERR_TO_STDOUT}, and
+@code{PEX_BINARY_OUTPUT}.  @var{outname} is interpreted as if
+@code{PEX_LAST} were set.  On a successful return, *@var{status} will
+be set to the exit status of the program.
+
+@end deftypefn
+
+@c pexecute.txh:118
+@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
+output of the last program in the pipeline.  When this is used,
+@code{PEX_LAST} should not be used in a call to @code{pex_run}.  After
+this is called, @code{pex_run} may no longer be called with the same
+@var{obj}.  @var{binary} should be non-zero if the file should be
+opened in binary mode.  Don't call @code{fclose} on the returned file;
+it will be closed by @code{pex_free}.
+
+@end deftypefn
+
+@c pexecute.txh:32
+@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
+@code{NULL}.  On failure it returns an error message.
+
+@var{obj} is returned by a previous call to @code{pex_init}.
+
+@var{flags} is a bitwise combination of the following:
+
+@table @code
+
+@vindex PEX_LAST
+@item PEX_LAST
+This must be set on the last program in the pipeline.  In particular,
+it should be set when executing a single program.  The standard output
+of the program will be sent to @var{outname}, or, if @var{outname} is
+@code{NULL}, to the standard output of the calling program.  This
+should not be set if you want to call @code{pex_read_output}
+(described below).  After a call to @code{pex_run} with this bit set,
+@var{pex_run} may no longer be called with the same @var{obj}.
+
+@vindex PEX_SEARCH
+@item PEX_SEARCH
+Search for the program using the user's executable search path.
+
+@vindex PEX_SUFFIX
+@item PEX_SUFFIX
+@var{outname} is a suffix.  See the description of @var{outname},
+below.
+
+@vindex PEX_STDERR_TO_STDOUT
+@item PEX_STDERR_TO_STDOUT
+Send the program's standard error to standard output, if possible.
+
+@vindex PEX_BINARY_INPUT
+@vindex PEX_BINARY_OUTPUT
+@item PEX_BINARY_INPUT
+@itemx PEX_BINARY_OUTPUT
+The standard input (output) of the program should be read (written) in
+binary mode rather than text mode.  These flags are ignored on systems
+which do not distinguish binary mode and text mode, such as Unix.  For
+proper behavior these flags should match appropriately--a call to
+@code{pex_run} using @code{PEX_BINARY_OUTPUT} should be followed by a
+call using @code{PEX_BINARY_INPUT}.
+@end table
+
+@var{executable} is the program to execute.  @var{argv} is the set of
+arguments to pass to the program; normally @code{@var{argv}[0]} will
+be a copy of @var{executable}.
+
+@var{outname} is used to set the name of the file to use for standard
+output.  There are two cases in which no output file will be used: 1)
+if @code{PEX_LAST} is not set in @var{flags}, and @code{PEX_USE_PIPES}
+was set in the call to @code{pex_init}, and the system supports pipes;
+2) if @code{PEX_LAST} is set in @var{flags}, and @var{outname} is
+@code{NULL}.  Otherwise the code will use a file to hold standard
+output.  If @code{PEX_LAST} is not set, this file is considered to be
+a temporary file, and it will be removed when no longer needed, unless
+@code{PEX_SAVE_TEMPS} was set in the call to @code{pex_init}.
+
+There are two cases to consider when setting the name of the file to
+hold standard output.
+
+First case: @code{PEX_SUFFIX} is set in @var{flags}.  In this case
+@var{outname} may not be @code{NULL}.  If the @var{tempbase} parameter
+to @code{pex_init} was not @code{NULL}, then the output file name is
+the concatenation of @var{tempbase} and @var{outname}.  If
+@var{tempbase} was @code{NULL}, then the output file name is a random
+file name ending in @var{outname}.
+
+Second case: @code{PEX_SUFFIX} was not set in @var{flags}.  In this
+case, if @var{outname} is not @code{NULL}, it is used as the output
+file name.  If @var{outname} is @code{NULL}, and @var{tempbase} was
+not NULL, the output file name is randomly chosen using
+@var{tempbase}.  Otherwise the output file name is chosen completely
+at random.
+
+@var{errname} is the file name to use for standard error output.  If
+it is @code{NULL}, standard error is the same as the caller.
+Otherwise, standard error is written to the named file.
+
+On an error return, the code sets @code{*@var{err}} to an @code{errno}
+value, or to 0 if there is no relevant @code{errno}.
+
+@end deftypefn
+
 @c alloca.c:26
 @deftypefn Replacement void* alloca (size_t @var{size})
 
@@ -339,6 +484,14 @@ between calls to @code{getpwd}.
 
 @end deftypefn
 
+@c gettimeofday.c:12
+@deftypefn int gettimeofday (struct timeval *@var{tp}, void *@var{tz})
+
+Writes the current time to @var{tp}.  This implementation requires
+that @var{tz} be NULL.  Returns 0 on success, -1 on failure.
+
+@end deftypefn
+
 @c hex.c:30
 @deftypefn Extension void hex_init (void)
 
@@ -610,42 +763,45 @@ reading and writing.
 
 @end deftypefn
 
-@c pexecute.txh:1
-@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)
+@c pexecute.txh:154
+@deftypefn Extension void pex_free (struct pex_obj @var{obj})
 
-Executes a program.
+Clean up and free all data associated with @var{obj}.
 
-@var{program} and @var{argv} are the arguments to
-@code{execv}/@code{execvp}.
+@end deftypefn
 
-@var{this_pname} is name of the calling program (i.e., @code{argv[0]}).
+@c pexecute.txh:130
+@deftypefn Extension int pex_get_status (struct pex_obj *@var{obj}, int @var{count}, int *@var{vector})
 
-@var{temp_base} is the path name, sans suffix, of a temporary file to
-use if needed.  This is currently only needed for MS-DOS ports that
-don't use @code{go32} (do any still exist?).  Ports that don't need it
-can pass @code{NULL}.
-
-(@code{@var{flags} & PEXECUTE_SEARCH}) is non-zero if @env{PATH}
-should be searched (??? It's not clear that GCC passes this flag
-correctly).  (@code{@var{flags} & PEXECUTE_FIRST}) is nonzero for the
-first process in chain.  (@code{@var{flags} & PEXECUTE_FIRST}) is
-nonzero for the last process in chain.  The first/last flags could be
-simplified to only mark the last of a chain of processes but that
-requires the caller to always mark the last one (and not give up
-early if some error occurs).  It's more robust to require the caller
-to mark both ends of the chain.
-
-The result is the pid on systems like Unix where we
-@code{fork}/@code{exec} and on systems like WIN32 and OS/2 where we
-use @code{spawn}.  It is up to the caller to wait for the child.
-
-The result is the @code{WEXITSTATUS} on systems like MS-DOS where we
-@code{spawn} and wait for the child here.
-
-Upon failure, @var{errmsg_fmt} and @var{errmsg_arg} are set to the
-text of the error message with an optional argument (if not needed,
-@var{errmsg_arg} is set to @code{NULL}), and @minus{}1 is returned.
-@code{errno} is available to the caller to use.
+Returns the exit status of all programs run using @var{obj}.
+@var{count} is the number of results expected.  The results will be
+placed into @var{vector}.  The results are in the order of the calls
+to @code{pex_run}.  Returns 0 on error, 1 on success.
+
+@end deftypefn
+
+@c pexecute.txh:139
+@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
+@var{obj}.  @var{count} is the number of results expected.  The
+results will be placed into @var{vector}.  The results are in the
+order of the calls to @code{pex_run}.  Returns 0 on error, 1 on
+success.
+
+@code{struct pex_time} has the following fields: @code{user_seconds},
+@code{user_microseconds}, @code{system_seconds},
+@code{system_microseconds}.  On systems which do not support reporting
+process times, all the fields will be set to @code{0}.
+
+@end deftypefn
+
+@c pexecute.txh:172
+@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
+still supported for compatibility purposes, but is no longer
+documented.
 
 @end deftypefn
 
@@ -668,23 +824,10 @@ name is unset/removed.
 
 @end deftypefn
 
-@c pexecute.txh:39
+@c pexecute.txh:180
 @deftypefn Extension int pwait (int @var{pid}, int *@var{status}, int @var{flags})
 
-Waits for a program started by @code{pexecute} to finish.
-
-@var{pid} is the process id of the task to wait for. @var{status} is
-the `status' argument to wait. @var{flags} is currently unused
-(allows future enhancement without breaking upward compatibility).
-Pass 0 for now.
-
-The result is the pid of the child reaped, or -1 for failure
-(@code{errno} says why).
-
-On systems that don't support waiting for a particular child,
-@var{pid} is ignored.  On systems like MS-DOS that don't really
-multitask @code{pwait} is just a mechanism to provide a consistent
-interface for the caller.
+Another part of the old execution interface.
 
 @end deftypefn
 
@@ -1008,6 +1151,16 @@ not be used in new projects.  Use @code{
 
 @end deftypefn
 
+@c unlink-if-ordinary.c:27
+@deftypefn Supplemental int unlink_if_ordinary (const char*)
+
+Unlinks the named file, unless it is special (e.g. a device file).
+Returns 0 when the file was unlinked, a negative value (and errno set) when
+there was an error deleting the file, and a positive value if no attempt
+was made to unlink the file because it is special.
+
+@end deftypefn
+
 @c vasprintf.c:51
 @deftypefn Extension int vasprintf (char **@var{resptr}, const char *@var{format}, va_list @var{args})
 
Index: libiberty/pex-common.c
===================================================================
RCS file: libiberty/pex-common.c
diff -N libiberty/pex-common.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libiberty/pex-common.c	21 Mar 2005 17:17:20 -0000
@@ -0,0 +1,495 @@
+/* Common code for executing a program in a sub-process.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor <ian@airs.com>.
+
+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., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include "libiberty.h"
+#include "pex-common.h"
+
+#include <stdio.h>
+#include <errno.h>
+#ifdef NEED_DECLARATION_ERRNO
+extern int errno;
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+extern int mkstemps PARAMS ((char *, int));
+
+/* This file contains subroutines for the program execution routines
+   (pex_init, pex_run, etc.).  This file is compiled on all
+   systems.  */
+
+static void pex_add_remove PARAMS ((struct pex_obj *, const char *, int));
+static int pex_get_status_and_time PARAMS ((struct pex_obj *, int,
+					    const char **, int *));
+
+/* Initialize a pex_obj structure.  */
+
+struct pex_obj *
+pex_init_common (flags, pname, tempbase, funcs)
+     int flags;
+     const char *pname;
+     const char *tempbase;
+     const struct pex_funcs *funcs;
+{
+  struct pex_obj *obj;
+
+  obj = xmalloc (sizeof (*obj));
+  obj->flags = flags;
+  obj->pname = pname;
+  obj->tempbase = tempbase;
+  obj->next_input = STDIN_FILE_NO;
+  obj->next_input_name = NULL;
+  obj->next_input_name_allocated = 0;
+  obj->count = 0;
+  obj->children = NULL;
+  obj->status = NULL;
+  obj->time = NULL;
+  obj->number_waited = 0;
+  obj->read_output = NULL;
+  obj->remove_count = 0;
+  obj->remove = NULL;
+  obj->funcs = funcs;
+  obj->sysdep = NULL;
+  return obj;
+}
+
+/* Add a file to be removed when we are done.  */
+
+static void
+pex_add_remove (obj, name, allocated)
+     struct pex_obj *obj;
+     const char *name;
+     int allocated;
+{
+  char *add;
+
+  ++obj->remove_count;
+  obj->remove = xrealloc (obj->remove, obj->remove_count * sizeof (char *));
+  if (allocated)
+    add = (char *) name;
+  else
+    add = xstrdup (name);
+  obj->remove[obj->remove_count - 1] = add;
+}
+
+/* Run a program.  */
+
+const char *
+pex_run (obj, flags, executable, argv, orig_outname, errname, err)
+     struct pex_obj *obj;
+     int flags;
+     const char *executable;
+     char * const * argv;
+     const char *orig_outname;
+     const char *errname;
+     int *err;
+{
+  const char *errmsg;
+  int in, out, errdes;
+  char *outname;
+  int outname_allocated;
+  int p[2];
+  long pid;
+
+  in = -1;
+  out = -1;
+  errdes = -1;
+  outname = (char *) orig_outname;
+  outname_allocated = 0;
+
+  /* Set IN.  */
+
+  if (obj->next_input_name != NULL)
+    {
+      /* We have to make sure that the previous process has completed
+	 before we try to read the file.  */
+      if (!pex_get_status_and_time (obj, 0, &errmsg, err))
+	goto error_exit;
+
+      in = obj->funcs->open_read (obj, obj->next_input_name,
+				  (flags & PEX_BINARY_INPUT) != 0);
+      if (in < 0)
+	{
+	  *err = errno;
+	  errmsg = "open temporary file";
+	  goto error_exit;
+	}
+      if (obj->next_input_name_allocated)
+	{
+	  free (obj->next_input_name);
+	  obj->next_input_name_allocated = 0;
+	}
+      obj->next_input_name = NULL;
+    }
+  else
+    {
+      in = obj->next_input;
+      if (in < 0)
+	{
+	  *err = 0;
+	  errmsg = "pipeline already complete";
+	  goto error_exit;
+	}
+    }
+
+  /* Set OUT and OBJ->NEXT_INPUT/OBJ->NEXT_INPUT_NAME.  */
+
+  if ((flags & PEX_LAST) != 0)
+    {
+      if (outname == NULL)
+	out = STDOUT_FILE_NO;
+      else if ((flags & PEX_SUFFIX) != 0)
+	{
+	  outname = concat (obj->tempbase, outname, NULL);
+	  outname_allocated = 1;
+	}
+      obj->next_input = -1;
+    }
+  else if ((obj->flags & PEX_USE_PIPES) == 0)
+    {
+      if (outname == NULL)
+	{
+	  if (obj->tempbase == NULL)
+	    {
+	      outname = make_temp_file (NULL);
+	      outname_allocated = 1;
+	    }
+	  else
+	    {
+	      int len = strlen (obj->tempbase);
+
+	      if (len >= 6
+		  && strcmp (obj->tempbase + len - 6, "XXXXXX") == 0)
+		outname = xstrdup (obj->tempbase);
+	      else
+		outname = concat (obj->tempbase, "XXXXXX", NULL);
+
+	      outname_allocated = 1;
+
+	      out = mkstemps (outname, 0);
+	      if (out < 0)
+		{
+		  *err = 0;
+		  errmsg = "could not create temporary output file";
+		  goto error_exit;
+		}
+
+	      /* This isn't obj->funcs->close because we got the
+		 descriptor from mkstemps, not from a function in
+		 obj->funcs.  Calling close here is just like what
+		 make_temp_file does.  */
+	      close (out);
+	      out = -1;
+	    }
+	}
+      else if ((flags & PEX_SUFFIX) != 0)
+	{
+	  if (obj->tempbase == NULL)
+	    outname = make_temp_file (outname);
+	  else
+	    outname = concat (obj->tempbase, outname, NULL);
+	  outname_allocated = 1;
+	}
+
+      if ((obj->flags & PEX_SAVE_TEMPS) == 0)
+	{
+	  pex_add_remove (obj, outname, outname_allocated);
+	  outname_allocated = 0;
+	}
+
+      if (!outname_allocated)
+	{
+	  obj->next_input_name = outname;
+	  obj->next_input_name_allocated = 0;
+	}
+      else
+	{
+	  obj->next_input_name = outname;
+	  outname_allocated = 0;
+	  obj->next_input_name_allocated = 1;
+	}
+    }
+  else
+    {
+      if (obj->funcs->pipe (obj, p, (flags & PEX_BINARY_OUTPUT) != 0) < 0)
+	{
+	  *err = errno;
+	  errmsg = "pipe";
+	  goto error_exit;
+	}
+
+      out = p[WRITE_PORT];
+      obj->next_input = p[READ_PORT];
+    }
+
+  if (out < 0)
+    {
+      out = obj->funcs->open_write (obj, outname,
+				    (flags & PEX_BINARY_OUTPUT) != 0);
+      if (out < 0)
+	{
+	  *err = errno;
+	  errmsg = "open temporary output file";
+	  goto error_exit;
+	}
+    }
+
+  if (outname_allocated)
+    {
+      free (outname);
+      outname_allocated = 0;
+    }
+
+  /* Set ERRDES.  */
+
+  if (errname == NULL)
+    errdes = STDERR_FILE_NO;
+  else
+    {
+      /* We assume that stderr is in text mode--it certainly shouldn't
+	 be controlled by PEX_BINARY_OUTPUT.  If necessary, we can add
+	 a PEX_BINARY_STDERR flag.  */
+      errdes = obj->funcs->open_write (obj, errname, 0);
+      if (errdes < 0)
+	{
+	  *err = errno;
+	  errmsg = "open error file";
+	  goto error_exit;
+	}
+    }
+
+  /* Run the program.  */
+
+  pid = obj->funcs->exec_child (obj, flags, executable, argv, in, out, errdes,
+				&errmsg, err);
+  if (pid < 0)
+    goto error_exit;
+
+  ++obj->count;
+  obj->children = xrealloc (obj->children, obj->count * sizeof (long));
+  obj->children[obj->count - 1] = pid;
+
+  return NULL;
+
+ error_exit:
+  if (in >= 0 && in != STDIN_FILE_NO)
+    obj->funcs->close (obj, in);
+  if (out >= 0 && out != STDOUT_FILE_NO)
+    obj->funcs->close (obj, out);
+  if (errdes >= 0 && errdes != STDERR_FILE_NO)
+    obj->funcs->close (obj, errdes);
+  if (outname_allocated)
+    free (outname);
+  return errmsg;
+}
+
+/* Return a FILE pointer for the output of the last program
+   executed.  */
+
+FILE *
+pex_read_output (obj, binary)
+     struct pex_obj *obj;
+     int binary;
+{
+  if (obj->next_input_name != NULL)
+    {
+      const char *errmsg;
+      int err;
+
+      /* We have to make sure that the process has completed before we
+	 try to read the file.  */
+      if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
+	{
+	  errno = err;
+	  return NULL;
+	}
+
+      obj->read_output = fopen (obj->next_input_name, binary ? "rb" : "r");
+
+      if (obj->next_input_name_allocated)
+	{
+	  free (obj->next_input_name);
+	  obj->next_input_name_allocated = 0;
+	}
+      obj->next_input_name = NULL;
+    }
+  else
+    {
+      int o;
+
+      o = obj->next_input;
+      if (o < 0 || o == STDIN_FILE_NO)
+	return NULL;
+      obj->read_output = obj->funcs->fdopenr (obj, o, binary);
+      obj->next_input = -1;
+    }
+
+  return obj->read_output;
+}
+
+/* Get the exit status and, if requested, the resource time for all
+   the child processes.  Return 0 on failure, 1 on success.  */
+
+static int
+pex_get_status_and_time (obj, done, errmsg, err)
+     struct pex_obj *obj;
+     int done;
+     const char **errmsg;
+     int *err;
+{
+  int ret;
+  int i;
+
+  if (obj->number_waited == obj->count)
+    return 1;
+
+  obj->status = xrealloc (obj->status, obj->count * sizeof (int));
+  if ((obj->flags & PEX_RECORD_TIMES) != 0)
+    obj->time = xrealloc (obj->time, obj->count * sizeof (struct pex_time));
+
+  ret = 1;
+  for (i = obj->number_waited; i < obj->count; ++i)
+    {
+      if (obj->funcs->wait (obj, obj->children[i], &obj->status[i],
+			    obj->time == NULL ? NULL : &obj->time[i],
+			    done, errmsg, err) < 0)
+	ret = 0;
+    }
+  obj->number_waited = i;
+
+  return ret;
+}
+
+/* Get exit status of executed programs.  */
+
+int
+pex_get_status (obj, count, vector)
+     struct pex_obj *obj;
+     int count;
+     int *vector;
+{
+  if (obj->status == NULL)
+    {
+      const char *errmsg;
+      int err;
+
+      if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
+	return 0;
+    }
+
+  if (count > obj->count)
+    {
+      memset (vector + obj->count, 0, (count - obj->count) * sizeof (int));
+      count = obj->count;
+    }
+
+  memcpy (vector, obj->status, count * sizeof (int));
+
+  return 1;
+}
+
+/* Get process times of executed programs.  */
+
+int
+pex_get_times (obj, count, vector)
+     struct pex_obj *obj;
+     int count;
+     struct pex_time *vector;
+{
+  if (obj->status == NULL)
+    {
+      const char *errmsg;
+      int err;
+
+      if (!pex_get_status_and_time (obj, 0, &errmsg, &err))
+	return 0;
+    }
+
+  if (obj->time == NULL)
+    return 0;
+
+  if (count > obj->count)
+    {
+      memset (vector + obj->count, 0,
+	      (count - obj->count) * sizeof (struct pex_time));
+      count = obj->count;
+    }
+
+  memcpy (vector, obj->time, count * sizeof (struct pex_time));
+
+  return 1;
+}
+
+/* Free a pex_obj structure.  */
+
+void
+pex_free (obj)
+     struct pex_obj *obj;
+{
+  if (obj->next_input >= 0 && obj->next_input != STDIN_FILE_NO)
+    obj->funcs->close (obj, obj->next_input);
+
+  /* If the caller forgot to wait for the children, we do it here, to
+     avoid zombies.  */
+  if (obj->status == NULL)
+    {
+      const char *errmsg;
+      int err;
+
+      obj->flags &= ~ PEX_RECORD_TIMES;
+      pex_get_status_and_time (obj, 1, &errmsg, &err);
+    }
+
+  if (obj->next_input_name_allocated)
+    free (obj->next_input_name);
+  if (obj->children != NULL)
+    free (obj->children);
+  if (obj->status != NULL)
+    free (obj->status);
+  if (obj->time != NULL)
+    free (obj->time);
+  if (obj->read_output != NULL)
+    fclose (obj->read_output);
+
+  if (obj->remove_count > 0)
+    {
+      int i;
+
+      for (i = 0; i < obj->remove_count; ++i)
+	{
+	  remove (obj->remove[i]);
+	  free (obj->remove[i]);
+	}
+      free (obj->remove);
+    }
+
+  if (obj->funcs->cleanup != NULL)
+    obj->funcs->cleanup (obj);
+
+  free (obj);
+}
Index: libiberty/pex-common.h
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/pex-common.h,v
retrieving revision 1.2
diff -u -p -r1.2 pex-common.h
--- libiberty/pex-common.h	18 Mar 2004 03:16:37 -0000	1.2
+++ libiberty/pex-common.h	21 Mar 2005 17:17:20 -0000
@@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "libiberty.h"
+#include <stdio.h>
 
 #define install_error_msg "installation problem, cannot exec `%s'"
 
@@ -42,4 +43,90 @@ Boston, MA 02111-1307, USA.  */
 /* value of `pipe': port index for writing.  */
 #define WRITE_PORT 1
 
+/* The structure used by pex_init and friends.  */
+
+struct pex_obj
+{
+  /* Flags.  */
+  int flags;
+  /* Name of calling program, for error messages.  */
+  const char *pname;
+  /* Base name to use for temporary files.  */
+  const char *tempbase;
+  /* Pipe to use as stdin for next process.  */
+  int next_input;
+  /* File name to use as stdin for next process.  */
+  char *next_input_name;
+  /* Whether next_input_name was allocated using malloc.  */
+  int next_input_name_allocated;
+  /* Number of child processes.  */
+  int count;
+  /* PIDs of child processes; array allocated using maloc.  */
+  long *children;
+  /* Exit statuses of child processes; array allocated using malloc.  */
+  int *status;
+  /* Time used by child processes; array allocated using malloc.  */
+  struct pex_time *time;
+  /* Number of children we have already waited for.  */
+  int number_waited;
+  /* FILE created by pex_read_output.  */
+  FILE *read_output;
+  /* Number of temporary files to remove.  */
+  int remove_count;
+  /* List of temporary files to remove; array allocated using malloc
+     of strings allocated using malloc.  */
+  char **remove;
+  /* Pointers to system dependent functions.  */
+  const struct pex_funcs *funcs;
+  /* For use by system dependent code.  */
+  void *sysdep;
+};
+
+/* Functions passed to pex_run_common.  */
+
+struct pex_funcs
+{
+  /* Open file NAME for reading.  If BINARY is non-zero, open in
+     binary mode.  Return >= 0 on success, -1 on error.  */
+  int (*open_read) PARAMS ((struct pex_obj *, const char *name, int binary));
+  /* Open file NAME for writing.  If BINARY is non-zero, open in
+     binary mode.  Return >= 0 on success, -1 on error.  */
+  int (*open_write) PARAMS ((struct pex_obj *, const char *name, int binary));
+  /* Execute a child process.  FLAGS, EXECUTABLE, ARGV, ERR are from
+     pex_run.  IN, OUT, ERRDES are each a descriptor, from open_read,
+     open_write, or pipe, or they are one of STDIN_FILE_NO,
+     STDOUT_FILE_NO or STDERR_FILE_NO; if not STD*_FILE_NO, they
+     should be closed.  The function should handle the
+     PEX_STDERR_TO_STDOUT flag.  Return >= 0 on success, or -1 on
+     error and set *ERRMSG and *ERR.  */
+  long (*exec_child) PARAMS ((struct pex_obj *, int flags,
+			      const char *executable, char * const * argv,
+			      int in, int out, int errdes,
+			      const char **errmsg, int *err));
+  /* Close a descriptor.  Return 0 on success, -1 on error.  */
+  int (*close) PARAMS ((struct pex_obj *, int));
+  /* Wait for a child to complete, returning exit status in *STATUS
+     and time in *TIME (if it is not null).  CHILD is from fork.  DONE
+     is 1 if this is called via pex_free.  ERRMSG and ERR are as in
+     fork.  Return 0 on success, -1 on error.  */
+  int (*wait) PARAMS ((struct pex_obj *, long, int *status,
+		       struct pex_time *time, int done, const char **errmsg,
+		       int *err));
+  /* Create a pipe (only called if PEX_USE_PIPES is set) storing two
+     descriptin in *P.  If BINARY is non-zero, open in binary mode.
+     Return 0 on success, -1 on error.  */
+  int (*pipe) PARAMS ((struct pex_obj *, int *p, int binary));
+  /* Get a FILE pointer to read from a file descriptor (only called if
+     PEX_USE_PIPES is set).  If BINARY is non-zero, open in binary
+     mode.  Return pointer on success, NULL on error.  */
+  FILE * (*fdopenr) PARAMS ((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) PARAMS ((struct pex_obj *));
+};
+
+extern struct pex_obj *pex_init_common PARAMS ((int, const char *,
+						const char *,
+						const struct pex_funcs *));
+
 #endif
Index: libiberty/pex-djgpp.c
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/pex-djgpp.c,v
retrieving revision 1.1
diff -u -p -r1.1 pex-djgpp.c
--- libiberty/pex-djgpp.c	24 Jan 2003 20:02:11 -0000	1.1
+++ libiberty/pex-djgpp.c	21 Mar 2005 17:17:20 -0000
@@ -1,6 +1,6 @@
 /* Utilities to execute a program in a subprocess (possibly linked by pipes
    with other subprocesses), and wait for it.  DJGPP specialization.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005
    Free Software Foundation, Inc.
 
 This file is part of the libiberty library.
@@ -38,66 +38,269 @@ extern int errno;
 #define PWAIT_ERROR EINVAL
 #endif
 
-/* MSDOS doesn't multitask, but for the sake of a consistent interface
-   the code behaves like it does.  pexecute runs the program, tucks the
-   exit code away, and returns a "pid".  pwait must be called to fetch the
-   exit code.  */
-
-/* For communicating information from pexecute to pwait.  */
-static int last_pid = 0;
-static int last_status = 0;
-static int last_reaped = 0;
-
-int
-pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
-     const char *program;
-     char * const *argv;
-     const char *this_pname;
-     const char *temp_base;
-     char **errmsg_fmt, **errmsg_arg;
+static int pex_djgpp_open_read PARAMS ((struct pex_obj *, const char *, int));
+static int pex_djgpp_open_write PARAMS ((struct pex_obj *, const char *, int));
+static long pex_djgpp_exec_child PARAMS ((struct pex_obj *, int, const char *,
+					 char * const *, int, int, int,
+					 const char **, int *));
+static int pex_djgpp_close PARAMS ((struct pex_obj *, int));
+static int pex_djgpp_wait PARAMS ((struct pex_obj *, long, int *,
+				   struct pex_time *, int, const char **,
+				   int *));
+
+/* The list of functions we pass to the common routines.  */
+
+const struct pex_funcs funcs =
+{
+  pex_djgpp_open_read,
+  pex_djgpp_open_write,
+  pex_djgpp_exec_child,
+  pex_djgpp_close,
+  pex_djgpp_wait,
+  NULL, /* pipe */
+  NULL, /* fdopenr */
+  NULL  /* cleanup */
+};
+
+/* Return a newly initialized pex_obj structure.  */
+
+struct pex_obj *
+pex_init (flags, pname, tempbase)
+     int flags;
+     const char *pname;
+     const char *tempbase;
+{
+  /* DJGPP does not support pipes.  */
+  flags &= ~ PEX_USE_PIPES;
+  return pex_init_common (flags, pname, tempbase, funcs);
+}
+
+/* Open a file for reading.  */
+
+static int
+pex_djgpp_open_read (obj, name, binary)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     const char *name;
+     int binary ATTRIBUTE_UNUSED;
+{
+  return open (name, O_RDONLY | (binary ? O_BINARY : O_TEXT));
+}
+
+/* Open a file for writing.  */
+
+static int
+pex_djgpp_open_write (obj, name, binary)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     const char *name;
+     int binary ATTRIBUTE_UNUSED;
+{
+  /* Note that we can't use O_EXCL here because gcc may have already
+     created the temporary file via make_temp_file.  */
+  return open (name,
+	       (O_WRONLY | O_CREAT | O_TRUNC
+		| (binary ? O_BINARY : O_TEXT)),
+	       S_IRUSR | S_IWUSR);
+}
+
+/* Close a file.  */
+
+static int
+pex_djgpp_close (obj, fd)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     int fd;
+{
+  return close (fd);
+}
+
+/* Execute a child.  */
+
+static long
+pex_djgpp_exec_child (obj, flags, executable, argv, in, out, errdes,
+		     errmsg, err)
+     struct pex_obj *obj;
      int flags;
+     const char *executable;
+     char * const * argv;
+     int in;
+     int out;
+     int errdes;
+     const char **errmsg;
+     int *err;
 {
-  int rc;
+  int org_in, org_out, org_errdes;
+  int status;
+  int *statuses;
+
+  org_in = -1;
+  org_out = -1;
+  org_errdes = -1;
 
-  last_pid++;
-  if (last_pid < 0)
-    last_pid = 1;
+  if (in != STDIN_FILE_NO)
+    {
+      org_in = _dup (STDIN_FILE_NO);
+      if (org_in < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup";
+	  return -1;
+	}
+      if (_dup2 (in, STDIN_FILE_NO) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup2";
+	  return -1;
+	}
+      if (_close (in) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_close";
+	  return -1;
+	}
+    }
+
+  if (out != STDOUT_FILE_NO)
+    {
+      org_out = _dup (STDOUT_FILE_NO);
+      if (org_out < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup";
+	  return -1;
+	}
+      if (_dup2 (out, STDOUT_FILE_NO) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup2";
+	  return -1;
+	}
+      if (_close (out) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_close";
+	  return -1;
+	}
+    }
+
+  if (errdes != STDERR_FILE_NO
+      || (flags & PEX_STDERR_TO_STDOUT) != 0)
+    {
+      int e;
+
+      org_errdes = _dup (STDERR_FILE_NO);
+      if (org_errdes < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup";
+	  return -1;
+	}
+      if (_dup2 ((flags & PEX_STDERR_TO_STDOUT) != 0 ? STDOUT_FILE_NO : errdes,
+		 STDERR_FILE_NO) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup2";
+	  return -1;
+	}
+      if (errdes != STDERR_FILE_NO)
+	{
+	  if (_close (errdes) < 0)
+	    {
+	      *err = errno;
+	      *errmsg = "_close";
+	      return -1;
+	    }
+	}
+    }
+
+  status = (((flags & PEX_SEARCH) != 0 ? _spawnvp : _spawnv)
+	    (P_WAIT, program, (const char **) argv));
+
+  if (status == -1)
+    {
+      *err = errno;
+      *errmsg = ((flags & PEX_SEARCH) != 0) ? "_spawnvp" : "_spawnv";
+    }
 
-  if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
-    abort ();
+  if (in != STDIN_FILE_NO)
+    {
+      if (_dup2 (org_in, STDIN_FILE_NO) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup2";
+	  return -1;
+	}
+      if (_close (org_in) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_close";
+	  return -1;
+	}
+    }
 
-  /* ??? What are the possible return values from spawnv?  */
-  rc = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (P_WAIT, program, argv);
+  if (out != STDOUT_FILE_NO)
+    {
+      if (_dup2 (org_out, STDOUT_FILE_NO) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup2";
+	  return -1;
+	}
+      if (_close (org_out) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_close";
+	  return -1;
+	}
+    }
 
-  if (rc == -1)
+  if (errdes != STDERR_FILE_NO
+      || (flags & PEX_STDERR_TO_STDOUT) != 0)
     {
-      *errmsg_fmt = install_error_msg;
-      *errmsg_arg = (char *)program;
-      return -1;
+      if (_dup2 (org_errdes, STDERR_FILE_NO) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup2";
+	  return -1;
+	}
+      if (_close (org_errdes) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_close";
+	  return -1;
+	}
     }
 
-  /* Tuck the status away for pwait, and return a "pid".  */
-  last_status = rc << 8;
-  return last_pid;
+  /* Save the exit status for later.  When we are called, obj->count
+     is the number of children which have executed before this
+     one.  */
+  statuses = (int *) obj->sysdep;
+  statuses = xrealloc (statuses, (obj->count + 1) * sizeof (int));
+  statuses[obj->count] = status;
+  obj->sysdep = (void *) statuses;
+
+  return obj->count;
 }
 
-int
-pwait (pid, status, flags)
-     int pid;
+/* Wait for a child process to complete.  Actually the child process
+   has already completed, and we just need to return the exit
+   status.  */
+
+static int
+pex_djgpp_wait (obj, pid, status, time, done, errmsg, err)
+     struct pex_obj *obj;
+     long pid;
      int *status;
-     int flags;
+     struct pex_time *time;
+     int done;
+     const char **errmsg;
+     int *err;
 {
-  /* On MSDOS each pexecute must be followed by its associated pwait.  */
-  if (pid != last_pid
-      /* Called twice for the same child?  */
-      || pid == last_reaped)
-    {
-      errno = PWAIT_ERROR;
-      return -1;
-    }
-  /* ??? Here's an opportunity to canonicalize the values in STATUS.
-     Needed?  */
-  *status = (last_status >> 8);
-  last_reaped = last_pid;
-  return last_pid;
+  int *statuses;
+
+  if (time != NULL)
+    memset (time, 0, sizeof *time);
+
+  statuses = (int *) obj->sysdep;
+  *status = statuses[pid];
+
+  return 0;
 }
Index: libiberty/pex-msdos.c
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/pex-msdos.c,v
retrieving revision 1.1
diff -u -p -r1.1 pex-msdos.c
--- libiberty/pex-msdos.c	24 Jan 2003 20:02:11 -0000	1.1
+++ libiberty/pex-msdos.c	21 Mar 2005 17:17:20 -0000
@@ -1,6 +1,6 @@
 /* Utilities to execute a program in a subprocess (possibly linked by pipes
    with other subprocesses), and wait for it.  Generic MSDOS specialization.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005
    Free Software Foundation, Inc.
 
 This file is part of the libiberty library.
@@ -36,6 +36,310 @@ extern int errno;
 #include "safe-ctype.h"
 #include <process.h>
 
+/* The structure we keep in obj->sysdep.  */
+
+#define PEX_MSDOS_FILE_COUNT 3
+
+#define PEX_MSDOS_FD_OFFSET 10
+
+struct pex_msdos
+{
+  /* An array of file names.  We refer to these using file descriptors
+     of 10 + array index.  */
+  const char *files[PEX_MSDOS_FILE_COUNT];
+  /* Exit statuses of programs which have been run.  */
+  int *statuses;
+};
+
+static int pex_msdos_open PARAMS ((struct pex_obj *, const char *, int));
+static int pex_msdos_open PARAMS ((struct pex_obj *, const char *, int));
+static int pex_msdos_fdindex PARAMS ((struct pex_msdos *, int));
+static long pex_msdos_exec_child PARAMS ((struct pex_obj *, int, const char *,
+					 char * const *, int, int, int,
+					 const char **, int *));
+static int pex_msdos_close PARAMS ((struct pex_obj *, int));
+static int pex_msdos_wait PARAMS ((struct pex_obj *, long, int *,
+				   struct pex_time *, int, const char **,
+				   int *));
+static void pex_msdos_cleanup PARAMS ((struct pex_obj *));
+
+/* The list of functions we pass to the common routines.  */
+
+const struct pex_funcs funcs =
+{
+  pex_msdos_open,
+  pex_msdos_open,
+  pex_msdos_exec_child,
+  pex_msdos_close,
+  pex_msdos_wait,
+  NULL, /* pipe */
+  NULL, /* fdopenr */
+  pex_msdos_cleanup
+};
+
+/* Return a newly initialized pex_obj structure.  */
+
+struct pex_obj *
+pex_init (flags, pname, tempbase)
+     int flags;
+     const char *pname;
+     const char *tempbase;
+{
+  struct pex_obj *ret;
+  int i;
+
+  /* MSDOS does not support pipes.  */
+  flags &= ~ PEX_USE_PIPES;
+
+  ret = pex_init_common (flags, pname, tempbase, funcs);
+
+  ret->sysdep = xmalloc (sizeof (struct pex_msdos));
+  for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
+    ret->files[i] = NULL;
+  ret->statuses = NULL;
+
+  return ret;
+}
+
+/* Open a file.  FIXME: We ignore the binary argument, since we have
+   no way to handle it.  */
+
+static int
+pex_msdos_open (obj, name, binary)
+     struct pex_obj *obj;
+     const char *name;
+     int binary ATTRIBUTE_UNUSED;
+{
+  struct pex_msdos *ms;
+  int i;
+
+  ms = (struct pex_msdos *) obj->sysdep;
+
+  for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
+    {
+      if (ms->files[i] == NULL)
+	{
+	  ms->files[i] = xstrdup (name);
+	  return i + PEX_MSDOS_FD_OFFSET;
+	}
+    }
+
+  abort ();
+}
+
+/* Get the index into msdos->files associated with an open file
+   descriptor.  */
+
+static int
+pex_msdos_fdindex (ms, fd)
+     struct pex_msdos *ms;
+     int fd;
+{
+  fd -= PEX_MSDOS_FD_OFFSET;
+  if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL)
+    abort ();
+  return fd;
+}
+
+
+/* Close a file.  */
+
+static int
+pex_msdos_close (obj, fd)
+     struct pex_obj *obj;
+     int fd;
+{
+  struct pex_msdos *ms;
+  int fdinex;
+
+  ms = (struct pex_msdos *) obj->sysdep;
+  fdindex = pe_msdos_fdindex (ms, fd);
+  free (ms->files[fdindex]);
+  ms->files[fdindex] = NULL;
+}
+
+/* Execute a child.  */
+
+static long
+pex_msdos_exec_child (obj, flags, executable, argv, in, out, errdes,
+		      errmsg, err)
+     struct pex_obj *obj;
+     int flags;
+     const char *executable;
+     char * const * argv;
+     int in;
+     int out;
+     int errdes ATTRIBUTE_UNUSED;
+     const char **errmsg;
+     int *err;
+{
+  struct pex_msdos *ms;
+  char *temp_base;
+  int temp_base_allocated;
+  char *rf;
+  int inindex;
+  char *infile;
+  int outindex;
+  char *outfile;
+  char *scmd;
+  FILE *argfile;
+  int i;
+  int status;
+
+  ms = (struct pex_msdos *) obj->sysdep;
+
+  /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES
+     and PEX_STDERR_TO_STDOUT.  */
+
+  temp_base = obj->temp_base;
+  if (temp_base != NULL)
+    temp_base_allocated = 0;
+  else
+    {
+      temp_base = choose_temp_base ();
+      temp_base_allocated = 1;
+    }
+
+  rf = concat (temp_base, ".gp", NULL);
+
+  if (temp_base_allocated)
+    free (temp_base);
+
+  if (in == STDIN_FILE_NO)
+    {
+      inindex = -1;
+      infile = "";
+    }
+  else
+    {
+      inindex = pex_msdos_fdindex (ms, in);
+      infile = ms->files[inindex];
+    }
+
+  if (out == STDOUT_FILE_NO)
+    {
+      outindex = -1;
+      outfile = "";
+    }
+  else
+    {
+      outindex = pex_msdos_fdindex (ms, out);
+      outfile = ms->files[outindex];
+    }
+
+  scmd = xmalloc (strlen (program)
+		  + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0)
+		  + strlen (rf)
+		  + strlen (infile)
+		  + strlen (outfile)
+		  + 10);
+  sprintf (scmd, "%s%s @%s%s%s%s%s",
+	   program,
+	   (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "",
+	   rf,
+	   inindex != -1 ? " <" : "",
+	   infile,
+	   outindex != -1 ? " >" : "",
+	   outfile);
+
+  argfile = fopen (rf, "w");
+  if (argfile == NULL)
+    {
+      *err = errno;
+      free (scmd);
+      free (rf);
+      *errmsg = "cannot open temporary command file";
+      return -1;
+    }
+
+  for (i = 1; argv[i] != NULL; ++i)
+    {
+      char *p;
+
+      for (p = argv[i]; *p != '\0'; ++p)
+	{
+	  if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p))
+	    putc ('\\', argfile);
+	  putc (*p, argfile);
+	}
+      putc ('\n', argfile);
+    }
+
+  fclose (argfile);
+
+  status = system (scmd);
+
+  if (status == -1)
+    {
+      *err = errno;
+      remove (rf);
+      free (scmd);
+      free (rf);
+      *errmsg = "system";
+      return -1;
+    }
+
+  remove (rf);
+  free (scmd);
+  free (rf);
+
+  /* Save the exit status for later.  When we are called, obj->count
+     is the number of children which have executed before this
+     one.  */
+  ms->statuses = xrealloc (ms->statuses, (obj->count + 1) * sizeof (int));
+  ms->statuses[obj->count] = status;
+
+  return obj->count;
+}
+
+/* Wait for a child process to complete.  Actually the child process
+   has already completed, and we just need to return the exit
+   status.  */
+
+static int
+pex_msdos_wait (obj, pid, status, time, done, errmsg, err)
+     struct pex_obj *obj;
+     long pid;
+     int *status;
+     struct pex_time *time;
+     int done;
+     const char **errmsg;
+     int *err;
+{
+  struct pex_msdos *ms;
+
+  ms = (struct pex_msdos *) obj->sysdep;
+
+  if (time != NULL)
+    memset (time, 0, sizeof *time);
+
+  *status = ms->statuses[pid];
+
+  return 0;
+}
+
+/* Clean up the pex_msdos structure.  */
+
+static void
+pex_msdos_cleanup (obj)
+     struct pex_obj  *obj;
+{
+  struct pex_msdos *ms;
+  int i;
+
+  ms = (struct pex_msdos *) obj->sysdep;
+  for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
+    if (msdos->files[i] != NULL)
+      free (msdos->files[i]);
+  if (msdos->statuses != NULL)
+    free (msdos->statuses);
+  free (msdos);
+  obj->sysdep = NULL;
+}
+
+
+
+
 /* MSDOS doesn't multitask, but for the sake of a consistent interface
    the code behaves like it does.  pexecute runs the program, tucks the
    exit code away, and returns a "pid".  pwait must be called to fetch the
Index: libiberty/pex-one.c
===================================================================
RCS file: libiberty/pex-one.c
diff -N libiberty/pex-one.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libiberty/pex-one.c	21 Mar 2005 17:17:20 -0000
@@ -0,0 +1,49 @@
+/* Execute a program and wait for a result.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+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., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include "libiberty.h"
+
+const char *
+pex_one (flags, executable, argv, pname, outname, errname, status, err)
+     int flags;
+     const char *executable;
+     char * const *argv;
+     const char *pname;
+     const char *outname;
+     const char *errname;
+     int *status;
+     int *err;
+{
+  struct pex_obj *obj;
+  const char *errmsg;
+
+  obj = pex_init (0, pname, NULL);
+  errmsg = pex_run (obj, flags, executable, argv, outname, errname, err);
+  if (errmsg == NULL)
+    {
+      if (!pex_get_status (obj, 1, status))
+	{
+	  *err = 0;
+	  errmsg = "pex_get_status failed";
+	}
+    }
+  pex_free (obj);
+  return errmsg;  
+}
Index: libiberty/pex-unix.c
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/pex-unix.c,v
retrieving revision 1.3
diff -u -p -r1.3 pex-unix.c
--- libiberty/pex-unix.c	30 Nov 2004 02:56:42 -0000	1.3
+++ libiberty/pex-unix.c	21 Mar 2005 17:17:20 -0000
@@ -1,7 +1,7 @@
 /* Utilities to execute a program in a subprocess (possibly linked by pipes
    with other subprocesses), and wait for it.  Generic Unix version
    (also used for UWIN and VMS).
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
    Free Software Foundation, Inc.
 
 This file is part of the libiberty library.
@@ -20,30 +20,43 @@ License along with libiberty; see the fi
 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
+#include "config.h"
+#include "libiberty.h"
 #include "pex-common.h"
 
 #include <stdio.h>
+#include <signal.h>
 #include <errno.h>
 #ifdef NEED_DECLARATION_ERRNO
 extern int errno;
 #endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
+
+#include <sys/types.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
 #endif
 #ifdef HAVE_SYS_WAIT_H
 #include <sys/wait.h>
 #endif
-
-#ifndef HAVE_WAITPID
-#define waitpid(pid, status, flags) wait(status)
+#ifdef HAVE_GETRUSAGE
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
 #endif
 
+
 #ifdef vfork /* Autoconf may define this to fork for us. */
 # define VFORK_STRING "fork"
 #else
@@ -57,85 +70,336 @@ extern int errno;
                lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1)
 #endif /* VMS */
 
-/* Execute a program, possibly setting up pipes to programs executed
-   via other calls to this function.
 
-   This version of the function uses vfork.  In general vfork is
-   similar to setjmp/longjmp, in that any variable which is modified by
-   the child process has an indeterminate value in the parent process.
-   We follow a safe approach here by not modifying any variables at
-   all in the child process (with the possible exception of variables
-   modified by xstrerror if exec fails, but this is unlikely to be
-   detectable).
-
-   We work a little bit harder to avoid gcc warnings.  gcc will warn
-   about any automatic variable which is live at the time of the
-   vfork, which is non-volatile, and which is either set more than
-   once or is an argument to the function.  This warning isn't quite
-   right, since what we really care about is whether the variable is
-   live at the time of the vfork and set afterward by the child
-   process, but gcc only checks whether the variable is set more than
-   once.  To avoid this warning, we ensure that any variable which is
-   live at the time of the vfork (i.e., used after the vfork) is set
-   exactly once and is not an argument, or is marked volatile.  */
-
-int
-pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg,
-	  flagsarg)
-     const char *program;
-     char * const *argv;
-     const char *this_pname;
-     const char *temp_base ATTRIBUTE_UNUSED;
-     char **errmsg_fmt, **errmsg_arg;
-     int flagsarg;
-{
-  int pid;
-  int pdes[2];
-  int out;
-  int input_desc, output_desc;
-  int flags;
-  /* We declare these to be volatile to avoid warnings from gcc about
-     them being clobbered by vfork.  */
-  volatile int retries, sleep_interval;
-  /* Pipe waiting from last process, to be used as input for the next one.
-     Value is STDIN_FILE_NO if no pipe is waiting
-     (i.e. the next command is the first of a group).  */
-  static int last_pipe_input;
+/* File mode to use for private and world-readable files.  */
 
-  flags = flagsarg;
+#if defined (S_IRUSR) && defined (S_IWUSR) && defined (S_IRGRP) && defined (S_IWGRP) && defined (S_IROTH) && defined (S_IWOTH)
+#define PUBLIC_MODE  \
+    (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
+#else
+#define PUBLIC_MODE 0666
+#endif
 
-  /* If this is the first process, initialize.  */
-  if (flags & PEXECUTE_FIRST)
-    last_pipe_input = STDIN_FILE_NO;
+/* Get the exit status of a particular process, and optionally get the
+   time that it took.  This is simple if we have wait4, slightly
+   harder if we have waitpid, and is a pain if we only have wait.  */
+
+static pid_t pex_wait PARAMS ((struct pex_obj *, pid_t, int *,
+			       struct pex_time *));
+
+#ifdef HAVE_WAIT4
+
+static pid_t
+pex_wait (obj, pid, status, time)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     pid_t pid;
+     int *status;
+     struct pex_time *time;
+{
+  pid_t ret;
+  struct rusage r;
+
+#ifdef HAVE_WAITPID
+  if (time == NULL)
+    return waitpid (pid, status, 0);
+#endif
 
-  input_desc = last_pipe_input;
+  ret = wait4 (pid, status, 0, &r);
 
-  /* If this isn't the last process, make a pipe for its output,
-     and record it as waiting to be the input to the next process.  */
-  if (! (flags & PEXECUTE_LAST))
+  if (time != NULL)
     {
-      if (pipe (pdes) < 0)
+      time->user_seconds = r.ru_utime.tv_sec;
+      time->user_microseconds= r.ru_utime.tv_usec;
+      time->system_seconds = r.ru_stime.tv_sec;
+      time->system_microseconds= r.ru_stime.tv_usec;
+    }
+
+  return ret;
+}
+
+#else /* ! defined (HAVE_WAIT4) */
+
+#ifdef HAVE_WAITPID
+
+#ifndef HAVE_GETRUSAGE
+
+static pid_t
+pex_wait (obj, pid, status, time)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     pid_t pid;
+     int *status;
+     struct pex_time *time;
+{
+  if (time != NULL)
+    memset (time, 0, sizeof (struct pex_time));
+  return waitpid (pid, status, 0);
+}
+
+#else /* defined (HAVE_GETRUSAGE) */
+
+static pid_t
+pex_wait (obj, pid, status, time)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     pid_t pid;
+     int *status;
+     struct pex_time *time;
+{
+  struct rusage r1, r2;
+  pid_t ret;
+
+  if (time == NULL)
+    return waitpid (pid, status, 0);
+
+  getrusage (RUSAGE_CHILDREN, &r1);
+
+  ret = waitpid (pid, status, 0);
+  if (ret < 0)
+    return ret;
+
+  getrusage (RUSAGE_CHILDREN, &r2);
+
+  time->user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
+  time->user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
+  if (time->user_microseconds < 0)
+    {
+      --time->user_seconds;
+      time->user_microseconds += 1000000;
+    }
+
+  time->system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
+  time->system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
+  if (time->system_microseconds < 0)
+    {
+      --time->system_seconds;
+      time->system_microseconds += 1000000;
+    }
+
+  return ret;
+}
+
+#endif /* defined (HAVE_GETRUSAGE) */
+
+#else /* ! defined (HAVE_WAITPID) */
+
+struct status_list
+{
+  struct status_list *next;
+  pid_t pid;
+  int status;
+  struct pex_time time;
+};
+
+static pid_t
+pex_wait (obj, pid, status, time)
+     struct pex_obj *obj;
+     pid_t pid;
+     int *status;
+     struct pex_time *time;
+{
+  struct status_list **pp;
+
+  for (pp = (struct status_list **) &obj->sysdep;
+       *pp != NULL;
+       pp = &(*pp)->next)
+    {
+      if ((*pp)->pid == pid)
 	{
-	  *errmsg_fmt = "pipe";
-	  *errmsg_arg = NULL;
-	  return -1;
+	  struct status_list *p;
+
+	  p = *pp;
+	  *status = p->status;
+	  if (time != NULL)
+	    *time = p->time;
+	  *pp = p->next;
+	  free (p);
+	  return pid;
 	}
-      out = pdes[WRITE_PORT];
-      last_pipe_input = pdes[READ_PORT];
     }
-  else
+
+  while (1)
     {
-      /* Last process.  */
-      out = STDOUT_FILE_NO;
-      last_pipe_input = STDIN_FILE_NO;
+      pid_t cpid;
+      struct status_list *psl;
+      struct pex_time pt;
+#ifdef HAVE_GETRUSAGE
+      struct rusage r1, r2;
+#endif
+
+      if (time != NULL)
+	{
+#ifdef HAVE_GETRUSAGE
+	  getrusage (RUSAGE_CHILDREN, &r1);
+#else
+	  memset (&pt, 0, sizeof (struct pex_time));
+#endif
+	}
+
+      cpid = wait (status);
+
+#ifdef HAVE_GETRUSAGE
+      if (time != NULL && cpid >= 0)
+	{
+	  getrusage (RUSAGE_CHILDREN, &r2);
+
+	  pt.user_seconds = r2.ru_utime.tv_sec - r1.ru_utime.tv_sec;
+	  pt.user_microseconds = r2.ru_utime.tv_usec - r1.ru_utime.tv_usec;
+	  if (pt.user_microseconds < 0)
+	    {
+	      --pt.user_seconds;
+	      pt.user_microseconds += 1000000;
+	    }
+
+	  pt.system_seconds = r2.ru_stime.tv_sec - r1.ru_stime.tv_sec;
+	  pt.system_microseconds = r2.ru_stime.tv_usec - r1.ru_stime.tv_usec;
+	  if (pt.system_microseconds < 0)
+	    {
+	      --pt.system_seconds;
+	      pt.system_microseconds += 1000000;
+	    }
+	}
+#endif
+
+      if (cpid < 0 || cpid == pid)
+	{
+	  if (time != NULL)
+	    *time = pt;
+	  return cpid;
+	}
+
+      psl = xmalloc (sizeof (struct status_list));
+      psl->pid = cpid;
+      psl->status = *status;
+      if (time != NULL)
+	psl->time = pt;
+      psl->next = (struct status_list *) obj->sysdep;
+      obj->sysdep = (void *) psl;
     }
+}
+
+#endif /* ! defined (HAVE_WAITPID) */
+#endif /* ! defined (HAVE_WAIT4) */
+
+static void pex_child_error PARAMS ((struct pex_obj *, const char *,
+				     const char *, int))
+     ATTRIBUTE_NORETURN;
+static int pex_unix_open_read PARAMS ((struct pex_obj *, const char *, int));
+static int pex_unix_open_write PARAMS ((struct pex_obj *, const char *, int));
+static long pex_unix_exec_child PARAMS ((struct pex_obj *, int, const char *,
+					 char * const *, int, int, int,
+					 const char **, int *));
+static int pex_unix_close PARAMS ((struct pex_obj *, int));
+static int pex_unix_wait PARAMS ((struct pex_obj *, long, int *,
+				  struct pex_time *, int, const char **,
+				  int *));
+static int pex_unix_pipe PARAMS ((struct pex_obj *, int *, int));
+static FILE *pex_unix_fdopenr PARAMS ((struct pex_obj *, int, int));
+static void pex_unix_cleanup PARAMS ((struct pex_obj *));
+
+/* The list of functions we pass to the common routines.  */
+
+const struct pex_funcs funcs =
+{
+  pex_unix_open_read,
+  pex_unix_open_write,
+  pex_unix_exec_child,
+  pex_unix_close,
+  pex_unix_wait,
+  pex_unix_pipe,
+  pex_unix_fdopenr,
+  pex_unix_cleanup
+};
+
+/* Return a newly initialized pex_obj structure.  */
+
+struct pex_obj *
+pex_init (flags, pname, tempbase)
+     int flags;
+     const char *pname;
+     const char *tempbase;
+{
+  return pex_init_common (flags, pname, tempbase, &funcs);
+}
 
-  output_desc = out;
+/* Open a file for reading.  */
+
+static int
+pex_unix_open_read (obj, name, binary)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     const char *name;
+     int binary ATTRIBUTE_UNUSED;
+{
+  return open (name, O_RDONLY);
+}
+
+/* Open a file for writing.  */
+
+static int
+pex_unix_open_write (obj, name, binary)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     const char *name;
+     int binary ATTRIBUTE_UNUSED;
+{
+  /* Note that we can't use O_EXCL here because gcc may have already
+     created the temporary file via make_temp_file.  */
+  return open (name, O_WRONLY | O_CREAT | O_TRUNC, PUBLIC_MODE);
+}
+
+/* Close a file.  */
+
+static int
+pex_unix_close (obj, fd)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     int fd;
+{
+  return close (fd);
+}
+
+/* Report an error from a child process.  We don't use stdio routines,
+   because we might be here due to a vfork call.  */
+
+static void
+pex_child_error (obj, executable, errmsg, err)
+     struct pex_obj *obj;
+     const char *executable;
+     const char *errmsg;
+     int err;
+{
+#define writeerr(s) write (STDERR_FILE_NO, s, strlen (s))
+  writeerr (obj->pname);
+  writeerr (": error trying to exec '");
+  writeerr (executable);
+  writeerr ("': ");
+  writeerr (errmsg);
+  writeerr (": ");
+  writeerr (xstrerror (err));
+  writeerr ("\n");
+  _exit (-1);
+}
+
+/* Execute a child.  */
+
+static long
+pex_unix_exec_child (obj, flags, executable, argv, in, out, errdes,
+		     errmsg, err)
+     struct pex_obj *obj;
+     int flags;
+     const char *executable;
+     char * const * argv;
+     int in;
+     int out;
+     int errdes;
+     const char **errmsg;
+     int *err;
+{
+  pid_t pid;
+  /* We declare these to be volatile to avoid warnings from gcc about
+     them being clobbered by vfork.  */
+  volatile int sleep_interval;
+  volatile int retries;
 
-  /* Fork a subprocess; wait and retry if it fails.  */
   sleep_interval = 1;
   pid = -1;
-  for (retries = 0; retries < 4; retries++)
+  for (retries = 0; retries < 4; ++retries)
     {
       pid = vfork ();
       if (pid >= 0)
@@ -147,69 +411,149 @@ pexecute (program, argv, this_pname, tem
   switch (pid)
     {
     case -1:
-      *errmsg_fmt = "fork";
-      *errmsg_arg = NULL;
+      *err = errno;
+      *errmsg = VFORK_STRING;
       return -1;
 
-    case 0: /* child */
-      /* Move the input and output pipes into place, if necessary.  */
-      if (input_desc != STDIN_FILE_NO)
+    case 0:
+      /* Child process.  */
+      if (in != STDIN_FILE_NO)
 	{
-	  close (STDIN_FILE_NO);
-	  dup (input_desc);
-	  close (input_desc);
+	  if (dup2 (in, STDIN_FILE_NO) < 0)
+	    pex_child_error (obj, executable, "dup2", errno);
+	  if (close (in) < 0)
+	    pex_child_error (obj, executable, "close", errno);
 	}
-      if (output_desc != STDOUT_FILE_NO)
+      if (out != STDOUT_FILE_NO)
 	{
-	  close (STDOUT_FILE_NO);
-	  dup (output_desc);
-	  close (output_desc);
+	  if (dup2 (out, STDOUT_FILE_NO) < 0)
+	    pex_child_error (obj, executable, "dup2", errno);
+	  if (close (out) < 0)
+	    pex_child_error (obj, executable, "close", errno);
+	}
+      if (errdes != STDERR_FILE_NO)
+	{
+	  if (dup2 (errdes, STDERR_FILE_NO) < 0)
+	    pex_child_error (obj, executable, "dup2", errno);
+	  if (close (errdes) < 0)
+	    pex_child_error (obj, executable, "close", errno);
+	}
+      if ((flags & PEX_STDERR_TO_STDOUT) != 0)
+	{
+	  if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
+	    pex_child_error (obj, executable, "dup2", errno);
+	}
+      if ((flags & PEX_SEARCH) != 0)
+	{
+	  execvp (executable, argv);
+	  pex_child_error (obj, executable, "execvp", errno);
 	}
-
-      /* Close the parent's descs that aren't wanted here.  */
-      if (last_pipe_input != STDIN_FILE_NO)
-	close (last_pipe_input);
-
-      /* Exec the program.  */
-      if (flags & PEXECUTE_SEARCH)
-	execvp (program, argv);
       else
-	execv (program, argv);
+	{
+	  execv (executable, argv);
+	  pex_child_error (obj, executable, "execv", errno);
+	}
 
-      /* We don't want to call fprintf after vfork.  */
-#define writeerr(s) write (STDERR_FILE_NO, s, strlen (s))
-      writeerr (this_pname);
-      writeerr (": ");
-      writeerr ("installation problem, cannot exec '");
-      writeerr (program);
-      writeerr ("': ");
-      writeerr (xstrerror (errno));
-      writeerr ("\n");
-      _exit (-1);
       /* NOTREACHED */
-      return 0;
+      return -1;
 
     default:
-      /* In the parent, after forking.
-	 Close the descriptors that we made for this child.  */
-      if (input_desc != STDIN_FILE_NO)
-	close (input_desc);
-      if (output_desc != STDOUT_FILE_NO)
-	close (output_desc);
+      /* Parent process.  */
+      if (in != STDIN_FILE_NO)
+	{
+	  if (close (in) < 0)
+	    {
+	      *err = errno;
+	      *errmsg = "close";
+	      return -1;
+	    }
+	}
+      if (out != STDOUT_FILE_NO)
+	{
+	  if (close (out) < 0)
+	    {
+	      *err = errno;
+	      *errmsg = "close";
+	      return -1;
+	    }
+	}
+      if (errdes != STDERR_FILE_NO)
+	{
+	  if (close (errdes) < 0)
+	    {
+	      *err = errno;
+	      *errmsg = "close";
+	      return -1;
+	    }
+	}
 
-      /* Return child's process number.  */
-      return pid;
+      return (long) pid;
     }
 }
 
-int
-pwait (pid, status, flags)
-     int pid;
+/* Wait for a child process to complete.  */
+
+static int
+pex_unix_wait (obj, pid, status, time, done, errmsg, err)
+     struct pex_obj *obj;
+     long pid;
      int *status;
-     int flags ATTRIBUTE_UNUSED;
+     struct pex_time *time;
+     int done;
+     const char **errmsg;
+     int *err;
+{
+  /* If we are cleaning up when the caller didn't retrieve process
+     status for some reason, encourage the process to go away.  */
+  if (done)
+    kill (pid, SIGTERM);
+
+  if (pex_wait (obj, pid, status, time) < 0)
+    {
+      *err = errno;
+      *errmsg = "wait";
+      return -1;
+    }
+
+  return 0;
+}
+
+/* Create a pipe.  */
+
+static int
+pex_unix_pipe (obj, p, binary)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     int *p;
+     int binary ATTRIBUTE_UNUSED;
 {
-  /* ??? Here's an opportunity to canonicalize the values in STATUS.
-     Needed?  */
-  pid = waitpid (pid, status, 0);
-  return pid;
+  return pipe (p);
+}
+
+/* Get a FILE pointer to read from a file descriptor.  */
+
+static FILE *
+pex_unix_fdopenr (obj, fd, binary)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     int fd;
+     int binary ATTRIBUTE_UNUSED;
+{
+  return fdopen (fd, "r");
+}
+
+static void
+pex_unix_cleanup (obj)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+{
+#if !defined (HAVE_WAIT4) && !defined (HAVE_WAITPID)
+  while (obj->sysdep != NULL)
+    {
+      struct status_list *this;
+      struct status_list *next;
+
+      this = (struct status_list *) obj->sysdep;
+      next = this->next;
+      free (this);
+      obj->sysdep = (void *) next;
+    }
+#endif
 }
Index: libiberty/pex-win32.c
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/pex-win32.c,v
retrieving revision 1.4
diff -u -p -r1.4 pex-win32.c
--- libiberty/pex-win32.c	31 May 2004 10:32:58 -0000	1.4
+++ libiberty/pex-win32.c	21 Mar 2005 17:17:21 -0000
@@ -1,6 +1,6 @@
 /* Utilities to execute a program in a subprocess (possibly linked by pipes
    with other subprocesses), and wait for it.  Generic Win32 specialization.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
    Free Software Foundation, Inc.
 
 This file is part of the libiberty library.
@@ -21,6 +21,9 @@ Boston, MA 02111-1307, USA.  */
 
 #include "pex-common.h"
 
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
@@ -35,6 +38,7 @@ Boston, MA 02111-1307, USA.  */
 #include <io.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <sys/stat.h>
 
 /* mingw32 headers may not define the following.  */
 
@@ -54,27 +58,49 @@ Boston, MA 02111-1307, USA.  */
 
 static const char * const *
 fix_argv (argvec)
-     char **argvec;
+     char * const *argvec;
 {
+  char **argv;
   int i;
-  char * command0 = argvec[0];
+  char *command0;
+
+  /* See whether we need to change anything.  */
+  for (command0 = argvec[0]; *command0 != '\0'; command0++)
+    if (*command0 == '/')
+      break;
+  if (*command0 == '\0')
+    {
+      for (i = 1; argvec[i] != NULL; i++)
+	if (strpbrk (argvec[i], "\" \t") != NULL)
+	  break;
+
+      if (argvec[i] == NULL)
+	return (const char * const *) argvec;
+    }
+
+  for (i = 0; argvec[i] != NULL; i++)
+    ;
+  argv = xmalloc ((i + 1) * sizeof (char *));
+  for (i = 0; argvec[i] != NULL; i++)
+    argv[i] = xstrdup (argvec[i]);
+  argv[i] = NULL;
 
   /* Ensure that the executable pathname uses Win32 backslashes. This
-     is not necessary on NT, but on W9x, forward slashes causes failure
-     of spawn* and exec* functions (and probably any function that
-     calls CreateProcess) *iff* the executable pathname (argvec[0]) is
-     a quoted string.  And quoting is necessary in case a pathname
-     contains  embedded white space. You can't win.  */
-  for (; *command0 != '\0'; command0++)
+     is not necessary on NT, but on W9x, forward slashes causes
+     failure of spawn* and exec* functions (and probably any function
+     that calls CreateProcess) *iff* the executable pathname (argv[0])
+     is a quoted string.  And quoting is necessary in case a pathname
+     contains embedded white space.  You can't win.  */
+  for (command0 = argv[0]; *command0 != '\0'; command0++)
     if (*command0 == '/')
       *command0 = '\\';
- 
-  for (i = 1; argvec[i] != 0; i++)
+
+  for (i = 1; argv[i] != 0; i++)
     {
       int len, j;
       char *temp, *newtemp;
 
-      temp = argvec[i];
+      temp = argv[i];
       len = strlen (temp);
       for (j = 0; j < len; j++)
         {
@@ -91,17 +117,21 @@ fix_argv (argvec)
             }
         }
 
-        argvec[i] = temp;
-      }
+      if (argv[i] != temp)
+	{
+	  free (argv[i]);
+	  argv[i] = temp;
+	}
+    }
 
-  for (i = 0; argvec[i] != 0; i++)
+  for (i = 0; argv[i] != 0; i++)
     {
-      if (strpbrk (argvec[i], " \t"))
+      if (strpbrk (argv[i], " \t"))
         {
 	  int len, trailing_backslash;
 	  char *temp;
 
-	  len = strlen (argvec[i]);
+	  len = strlen (argv[i]);
 	  trailing_backslash = 0;
 
 	  /* There is an added complication when an arg with embedded white
@@ -112,8 +142,8 @@ fix_argv (argvec)
 	     We handle this case by escaping the trailing backslash, provided
 	     it was not escaped in the first place.  */
 	  if (len > 1 
-	      && argvec[i][len-1] == '\\' 
-	      && argvec[i][len-2] != '\\')
+	      && argv[i][len-1] == '\\' 
+	      && argv[i][len-2] != '\\')
 	    {
 	      trailing_backslash = 1;
 	      ++len;			/* to escape the final backslash. */
@@ -123,133 +153,315 @@ fix_argv (argvec)
 
 	  temp = xmalloc (len + 1);
 	  temp[0] = '"';
-	  strcpy (temp + 1, argvec[i]);
+	  strcpy (temp + 1, argv[i]);
 	  if (trailing_backslash)
-	    temp[len-2] = '\\';
-	  temp[len-1] = '"';
+	    temp[len - 2] = '\\';
+	  temp[len - 1] = '"';
 	  temp[len] = '\0';
 
-	  argvec[i] = temp;
+	  free (argv[i]);
+	  argv[i] = temp;
 	}
     }
 
-  return (const char * const *) argvec;
+  return (const char * const *) argv;
 }
 
-/* Win32 supports pipes */
-int
-pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
-     const char *program;
-     char * const *argv;
-     const char *this_pname ATTRIBUTE_UNUSED;
-     const char *temp_base ATTRIBUTE_UNUSED;
-     char **errmsg_fmt, **errmsg_arg;
+static int pex_win32_open_read PARAMS ((struct pex_obj *, const char *, int));
+static int pex_win32_open_write PARAMS ((struct pex_obj *, const char *, int));
+static long pex_win32_exec_child PARAMS ((struct pex_obj *, int, const char *,
+					  char * const *, int, int, int,
+					  const char **, int *));
+static int pex_win32_close PARAMS ((struct pex_obj *, int));
+static int pex_win32_wait PARAMS ((struct pex_obj *, long, int *,
+				   struct pex_time *, int, const char **,
+				   int *));
+static int pex_win32_pipe PARAMS ((struct pex_obj *, int *, int));
+static FILE *pex_win32_fdopenr PARAMS ((struct pex_obj *, int, int));
+
+/* The list of functions we pass to the common routines.  */
+
+const struct pex_funcs funcs =
+{
+  pex_win32_open_read,
+  pex_win32_open_write,
+  pex_win32_exec_child,
+  pex_win32_close,
+  pex_win32_wait,
+  pex_win32_pipe,
+  pex_win32_fdopenr,
+  NULL /* cleanup */
+};
+
+/* Return a newly initialized pex_obj structure.  */
+
+struct pex_obj *
+pex_init (flags, pname, tempbase)
      int flags;
+     const char *pname;
+     const char *tempbase;
+{
+  return pex_init_common (flags, pname, tempbase, &funcs);
+}
+
+/* Open a file for reading.  */
+
+static int
+pex_win32_open_read (obj, name, binary)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     const char *name;
+     int binary;
+{
+  return _open (name, _O_RDONLY | (binary ? _O_BINARY : _O_TEXT));
+}
+
+/* Open a file for writing.  */
+
+static int
+pex_win32_open_write (obj, name, binary)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     const char *name;
+     int binary;
 {
-  int pid;
-  int pdes[2];
-  int org_stdin = -1;
-  int org_stdout = -1;
-  int input_desc, output_desc;
+  /* Note that we can't use O_EXCL here because gcc may have already
+     created the temporary file via make_temp_file.  */
+  return _open (name,
+		(_O_WRONLY | _O_CREAT | _O_TRUNC
+		 | (binary ? _O_BINARY : _O_TEXT)),
+		_S_IREAD | _S_IWRITE);
+}
+
+/* Close a file.  */
+
+static int
+pex_win32_close (obj, fd)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     int fd;
+{
+  return _close (fd);
+}
 
-  /* Pipe waiting from last process, to be used as input for the next one.
-     Value is STDIN_FILE_NO if no pipe is waiting
-     (i.e. the next command is the first of a group).  */
-  static int last_pipe_input;
+/* Execute a child.  */
 
-  /* If this is the first process, initialize.  */
-  if (flags & PEXECUTE_FIRST)
-    last_pipe_input = STDIN_FILE_NO;
+static long
+pex_win32_exec_child (obj, flags, executable, argv, in, out, errdes,
+		     errmsg, err)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     int flags;
+     const char *executable;
+     char * const * argv;
+     int in;
+     int out;
+     int errdes;
+     const char **errmsg;
+     int *err;
+{
+  int org_in, org_out, org_errdes;
+  long pid;
 
-  input_desc = last_pipe_input;
+  org_in = -1;
+  org_out = -1;
+  org_errdes = -1;
 
-  /* If this isn't the last process, make a pipe for its output,
-     and record it as waiting to be the input to the next process.  */
-  if (! (flags & PEXECUTE_LAST))
+  if (in != STDIN_FILE_NO)
     {
-      if (_pipe (pdes, 256, O_BINARY) < 0)
+      org_in = _dup (STDIN_FILE_NO);
+      if (org_in < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup";
+	  return -1;
+	}
+      if (_dup2 (in, STDIN_FILE_NO) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup2";
+	  return -1;
+	}
+      if (_close (in) < 0)
 	{
-	  *errmsg_fmt = "pipe";
-	  *errmsg_arg = NULL;
+	  *err = errno;
+	  *errmsg = "_close";
 	  return -1;
 	}
-      output_desc = pdes[WRITE_PORT];
-      last_pipe_input = pdes[READ_PORT];
     }
-  else
+
+  if (out != STDOUT_FILE_NO)
     {
-      /* Last process.  */
-      output_desc = STDOUT_FILE_NO;
-      last_pipe_input = STDIN_FILE_NO;
+      org_out = _dup (STDOUT_FILE_NO);
+      if (org_out < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup";
+	  return -1;
+	}
+      if (_dup2 (out, STDOUT_FILE_NO) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup2";
+	  return -1;
+	}
+      if (_close (out) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_close";
+	  return -1;
+	}
     }
 
-  if (input_desc != STDIN_FILE_NO)
+  if (errdes != STDERR_FILE_NO
+      || (flags & PEX_STDERR_TO_STDOUT) != 0)
     {
-      org_stdin = dup (STDIN_FILE_NO);
-      dup2 (input_desc, STDIN_FILE_NO);
-      close (input_desc); 
+      org_errdes = _dup (STDERR_FILE_NO);
+      if (org_errdes < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup";
+	  return -1;
+	}
+      if (_dup2 ((flags & PEX_STDERR_TO_STDOUT) != 0 ? STDOUT_FILE_NO : errdes,
+		 STDERR_FILE_NO) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup2";
+	  return -1;
+	}
+      if (errdes != STDERR_FILE_NO)
+	{
+	  if (_close (errdes) < 0)
+	    {
+	      *err = errno;
+	      *errmsg = "_close";
+	      return -1;
+	    }
+	}
     }
 
-  if (output_desc != STDOUT_FILE_NO)
+  pid = (((flags & PEX_SEARCH) != 0 ? _spawnvp : _spawnv)
+	 (_P_NOWAIT, executable, fix_argv (argv)));
+
+  if (pid == -1)
     {
-      org_stdout = dup (STDOUT_FILE_NO);
-      dup2 (output_desc, STDOUT_FILE_NO);
-      close (output_desc);
+      *err = errno;
+      *errmsg = ((flags & PEX_SEARCH) != 0) ? "_spawnvp" : "_spawnv";
     }
 
-  pid = (flags & PEXECUTE_SEARCH ? _spawnvp : _spawnv)
-    (_P_NOWAIT, program, fix_argv(argv));
-
-  if (input_desc != STDIN_FILE_NO)
+  if (in != STDIN_FILE_NO)
     {
-      dup2 (org_stdin, STDIN_FILE_NO);
-      close (org_stdin);
+      if (_dup2 (org_in, STDIN_FILE_NO) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup2";
+	  return -1;
+	}
+      if (_close (org_in) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_close";
+	  return -1;
+	}
     }
 
-  if (output_desc != STDOUT_FILE_NO)
+  if (out != STDOUT_FILE_NO)
     {
-      dup2 (org_stdout, STDOUT_FILE_NO);
-      close (org_stdout);
+      if (_dup2 (org_out, STDOUT_FILE_NO) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup2";
+	  return -1;
+	}
+      if (_close (org_out) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_close";
+	  return -1;
+	}
     }
 
-  if (pid == -1)
+  if (errdes != STDERR_FILE_NO
+      || (flags & PEX_STDERR_TO_STDOUT) != 0)
     {
-      *errmsg_fmt = install_error_msg;
-      *errmsg_arg = (char*) program;
-      return -1;
+      if (_dup2 (org_errdes, STDERR_FILE_NO) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_dup2";
+	  return -1;
+	}
+      if (_close (org_errdes) < 0)
+	{
+	  *err = errno;
+	  *errmsg = "_close";
+	  return -1;
+	}
     }
 
   return pid;
 }
 
-/* MS CRTDLL doesn't return enough information in status to decide if the
-   child exited due to a signal or not, rather it simply returns an
-   integer with the exit code of the child; eg., if the child exited with 
-   an abort() call and didn't have a handler for SIGABRT, it simply returns
-   with status = 3. We fix the status code to conform to the usual WIF*
-   macros. Note that WIFSIGNALED will never be true under CRTDLL. */
-
-int
-pwait (pid, status, flags)
-     int pid;
+/* Wait for a child process to complete.  MS CRTDLL doesn't return
+   enough information in status to decide if the child exited due to a
+   signal or not, rather it simply returns an integer with the exit
+   code of the child; eg., if the child exited with an abort() call
+   and didn't have a handler for SIGABRT, it simply returns with
+   status == 3.  We fix the status code to conform to the usual WIF*
+   macros.  Note that WIFSIGNALED will never be true under CRTDLL. */
+
+static int
+pex_win32_wait (obj, pid, status, time, done, errmsg, err)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     long pid;
      int *status;
-     int flags ATTRIBUTE_UNUSED;
+     struct pex_time *time;
+     int done ATTRIBUTE_UNUSED;
+     const char **errmsg;
+     int *err;
 {
   int termstat;
 
-  pid = _cwait (&termstat, pid, WAIT_CHILD);
+  if (time != NULL)
+    memset (time, 0, sizeof *time);
 
-  /* ??? Here's an opportunity to canonicalize the values in STATUS.
-     Needed?  */
+  /* FIXME: If done is non-zero, we should probably try to kill the
+     process.  */
+
+  if (_cwait (&termstat, pid, WAIT_CHILD) < 0)
+    {
+      *err = errno;
+      *errmsg = "_cwait";
+      return -1;
+    }
+
+  /* cwait returns the child process exit code in termstat.  A value
+     of 3 indicates that the child caught a signal, but not which one.
+     Since only SIGABRT, SIGFPE and SIGINT do anything, we report
+     SIGABRT.  */
 
-  /* cwait returns the child process exit code in termstat.
-     A value of 3 indicates that the child caught a signal, but not
-     which one.  Since only SIGABRT, SIGFPE and SIGINT do anything, we
-     report SIGABRT.  */
   if (termstat == 3)
     *status = SIGABRT;
   else
-    *status = (((termstat) & 0xff) << 8);
+    *status = ((termstat & 0xff) << 8);
 
-  return pid;
+  return 0;
+}
+
+/* Create a pipe.  */
+
+static int
+pex_win32_pipe (obj, p, binary)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     int *p;
+     int binary;
+{
+  return _pipe (p, 256, binary ? _O_BINARY : _O_TEXT);
+}
+
+/* Get a FILE pointer to read from a file descriptor.  */
+
+static FILE *
+pex_win32_fdopenr (obj, fd, binary)
+     struct pex_obj *obj ATTRIBUTE_UNUSED;
+     int fd;
+     int binary;
+{
+  return fdopen (fd, binary ? "rb" : "r");
 }
Index: libiberty/pexecute.c
===================================================================
RCS file: libiberty/pexecute.c
diff -N libiberty/pexecute.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libiberty/pexecute.c	21 Mar 2005 17:17:21 -0000
@@ -0,0 +1,129 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+   with other subprocesses), and wait for it.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+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., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* pexecute is an old routine.  This implementation uses the newer
+   pex_init/pex_run/pex_get_status/pex_free routines.  Don't use
+   pexecute in new code.  Use the newer routines instead.  */
+
+#include "config.h"
+#include "libiberty.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+/* We only permit a single pexecute chain to execute at a time.  This
+   was always true anyhow, though it wasn't documented.  */
+
+static struct pex_obj *pex;
+static int idx;
+
+int
+pexecute (program, argv, pname, temp_base, errmsg_fmt, errmsg_arg, flags)
+     const char *program;
+     char * const *argv;
+     const char *pname;
+     const char *temp_base;
+     char **errmsg_fmt;
+     char **errmsg_arg;
+     int flags;
+{
+  const char *errmsg;
+  int err;
+
+  if ((flags & PEXECUTE_FIRST) != 0)
+    {
+      if (pex != NULL)
+	{
+	  *errmsg_fmt = "pexecute already in progress";
+	  *errmsg_arg = NULL;
+	  return -1;
+	}
+      pex = pex_init (PEX_USE_PIPES, pname, temp_base);
+      idx = 0;
+    }
+  else
+    {
+      if (pex == NULL)
+	{
+	  *errmsg_fmt = "pexecute not in progress";
+	  *errmsg_arg = NULL;
+	  return -1;
+	}
+    }
+
+  errmsg = pex_run (pex,
+		    (((flags & PEXECUTE_LAST) != 0 ? PEX_LAST : 0)
+		     | ((flags & PEXECUTE_SEARCH) != 0 ? PEX_SEARCH : 0)),
+		    program, argv, NULL, NULL, &err);
+  if (errmsg != NULL)
+    {
+      *errmsg_fmt = (char *) errmsg;
+      *errmsg_arg = NULL;
+      return -1;
+    }
+
+  /* Instead of a PID, we just return a one-based index into the
+     status values.  We avoid zero just because the old pexecute would
+     never return it.  */
+  return ++idx;
+}
+
+int
+pwait (pid, status, flags)
+     int pid;
+     int *status;
+     int flags ATTRIBUTE_UNUSED;
+{
+  /* The PID returned by pexecute is one-based.  */
+  --pid;
+
+  if (pex == NULL || pid < 0 || pid >= idx)
+    return -1;
+
+  if (pid == 0 && idx == 1)
+    {
+      if (!pex_get_status (pex, 1, status))
+	return -1;
+    }
+  else
+    {
+      int *vector;
+
+      vector = xmalloc (idx * sizeof (int));
+      if (!pex_get_status (pex, idx, vector))
+	return -1;
+      *status = vector[pid];
+      free (vector);
+    }
+
+  /* Assume that we are done after the caller has retrieved the last
+     exit status.  The original implementation did not require that
+     the exit statuses be retrieved in order, but this implementation
+     does.  */
+  if (pid + 1 == idx)
+    {
+      pex_free (pex);
+      pex = NULL;
+      idx = 0;
+    }
+
+  return pid + 1;
+}
Index: libiberty/pexecute.txh
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/pexecute.txh,v
retrieving revision 1.1
diff -u -p -r1.1 pexecute.txh
--- libiberty/pexecute.txh	24 Jan 2003 20:02:11 -0000	1.1
+++ libiberty/pexecute.txh	21 Mar 2005 17:17:22 -0000
@@ -1,63 +1,184 @@
-@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)
+@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
+program fed to standard input of the next.  This is a system
+independent interface to execute a pipeline.
+
+@var{flags} is a bitwise combination of the following:
+
+@table @code
+
+@vindex PEX_RECORD_TIMES
+@item PEX_RECORD_TIMES
+Record subprocess times if possible.
 
-Executes a program.
+@vindex PEX_USE_PIPES
+@item PEX_USE_PIPES
+Use pipes for communication between processes, if possible.
 
-@var{program} and @var{argv} are the arguments to
-@code{execv}/@code{execvp}.
+@vindex PEX_SAVE_TEMPS
+@item PEX_SAVE_TEMPS
+Don't delete temporary files used for communication between
+processes.
 
-@var{this_pname} is name of the calling program (i.e., @code{argv[0]}).
+@end table
 
-@var{temp_base} is the path name, sans suffix, of a temporary file to
-use if needed.  This is currently only needed for MS-DOS ports that
-don't use @code{go32} (do any still exist?).  Ports that don't need it
-can pass @code{NULL}.
-
-(@code{@var{flags} & PEXECUTE_SEARCH}) is non-zero if @env{PATH}
-should be searched (??? It's not clear that GCC passes this flag
-correctly).  (@code{@var{flags} & PEXECUTE_FIRST}) is nonzero for the
-first process in chain.  (@code{@var{flags} & PEXECUTE_FIRST}) is
-nonzero for the last process in chain.  The first/last flags could be
-simplified to only mark the last of a chain of processes but that
-requires the caller to always mark the last one (and not give up
-early if some error occurs).  It's more robust to require the caller
-to mark both ends of the chain.
-
-The result is the pid on systems like Unix where we
-@code{fork}/@code{exec} and on systems like WIN32 and OS/2 where we
-use @code{spawn}.  It is up to the caller to wait for the child.
-
-The result is the @code{WEXITSTATUS} on systems like MS-DOS where we
-@code{spawn} and wait for the child here.
-
-Upon failure, @var{errmsg_fmt} and @var{errmsg_arg} are set to the
-text of the error message with an optional argument (if not needed,
-@var{errmsg_arg} is set to @code{NULL}), and @minus{}1 is returned.
-@code{errno} is available to the caller to use.
+@var{pname} is the name of program to be executed, used in error
+messages.  @var{tempbase} is a base name to use for any required
+temporary files; it may be @code{NULL} to use a randomly chosen name.
 
 @end deftypefn
 
-@deftypefn Extension int pwait (int @var{pid}, int *@var{status}, int @var{flags})
+@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
+@code{NULL}.  On failure it returns an error message.
+
+@var{obj} is returned by a previous call to @code{pex_init}.
+
+@var{flags} is a bitwise combination of the following:
+
+@table @code
+
+@vindex PEX_LAST
+@item PEX_LAST
+This must be set on the last program in the pipeline.  In particular,
+it should be set when executing a single program.  The standard output
+of the program will be sent to @var{outname}, or, if @var{outname} is
+@code{NULL}, to the standard output of the calling program.  This
+should not be set if you want to call @code{pex_read_output}
+(described below).  After a call to @code{pex_run} with this bit set,
+@var{pex_run} may no longer be called with the same @var{obj}.
+
+@vindex PEX_SEARCH
+@item PEX_SEARCH
+Search for the program using the user's executable search path.
+
+@vindex PEX_SUFFIX
+@item PEX_SUFFIX
+@var{outname} is a suffix.  See the description of @var{outname},
+below.
+
+@vindex PEX_STDERR_TO_STDOUT
+@item PEX_STDERR_TO_STDOUT
+Send the program's standard error to standard output, if possible.
+
+@vindex PEX_BINARY_INPUT
+@vindex PEX_BINARY_OUTPUT
+@item PEX_BINARY_INPUT
+@itemx PEX_BINARY_OUTPUT
+The standard input (output) of the program should be read (written) in
+binary mode rather than text mode.  These flags are ignored on systems
+which do not distinguish binary mode and text mode, such as Unix.  For
+proper behavior these flags should match appropriately--a call to
+@code{pex_run} using @code{PEX_BINARY_OUTPUT} should be followed by a
+call using @code{PEX_BINARY_INPUT}.
+@end table
+
+@var{executable} is the program to execute.  @var{argv} is the set of
+arguments to pass to the program; normally @code{@var{argv}[0]} will
+be a copy of @var{executable}.
+
+@var{outname} is used to set the name of the file to use for standard
+output.  There are two cases in which no output file will be used: 1)
+if @code{PEX_LAST} is not set in @var{flags}, and @code{PEX_USE_PIPES}
+was set in the call to @code{pex_init}, and the system supports pipes;
+2) if @code{PEX_LAST} is set in @var{flags}, and @var{outname} is
+@code{NULL}.  Otherwise the code will use a file to hold standard
+output.  If @code{PEX_LAST} is not set, this file is considered to be
+a temporary file, and it will be removed when no longer needed, unless
+@code{PEX_SAVE_TEMPS} was set in the call to @code{pex_init}.
+
+There are two cases to consider when setting the name of the file to
+hold standard output.
+
+First case: @code{PEX_SUFFIX} is set in @var{flags}.  In this case
+@var{outname} may not be @code{NULL}.  If the @var{tempbase} parameter
+to @code{pex_init} was not @code{NULL}, then the output file name is
+the concatenation of @var{tempbase} and @var{outname}.  If
+@var{tempbase} was @code{NULL}, then the output file name is a random
+file name ending in @var{outname}.
+
+Second case: @code{PEX_SUFFIX} was not set in @var{flags}.  In this
+case, if @var{outname} is not @code{NULL}, it is used as the output
+file name.  If @var{outname} is @code{NULL}, and @var{tempbase} was
+not NULL, the output file name is randomly chosen using
+@var{tempbase}.  Otherwise the output file name is chosen completely
+at random.
+
+@var{errname} is the file name to use for standard error output.  If
+it is @code{NULL}, standard error is the same as the caller.
+Otherwise, standard error is written to the named file.
+
+On an error return, the code sets @code{*@var{err}} to an @code{errno}
+value, or to 0 if there is no relevant @code{errno}.
+
+@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
+output of the last program in the pipeline.  When this is used,
+@code{PEX_LAST} should not be used in a call to @code{pex_run}.  After
+this is called, @code{pex_run} may no longer be called with the same
+@var{obj}.  @var{binary} should be non-zero if the file should be
+opened in binary mode.  Don't call @code{fclose} on the returned file;
+it will be closed by @code{pex_free}.
+
+@end deftypefn
 
-Waits for a program started by @code{pexecute} to finish.
+@deftypefn Extension int pex_get_status (struct pex_obj *@var{obj}, int @var{count}, int *@var{vector})
 
-@var{pid} is the process id of the task to wait for. @var{status} is
-the `status' argument to wait. @var{flags} is currently unused
-(allows future enhancement without breaking upward compatibility).
-Pass 0 for now.
+Returns the exit status of all programs run using @var{obj}.
+@var{count} is the number of results expected.  The results will be
+placed into @var{vector}.  The results are in the order of the calls
+to @code{pex_run}.  Returns 0 on error, 1 on success.
 
-The result is the pid of the child reaped, or -1 for failure
-(@code{errno} says why).
+@end deftypefn
+
+@deftypefn Extension int pex_get_times (struct pex_obj *@var{obj}, int @var{count}, struct pex_time *@var{vector})
 
-On systems that don't support waiting for a particular child,
-@var{pid} is ignored.  On systems like MS-DOS that don't really
-multitask @code{pwait} is just a mechanism to provide a consistent
-interface for the caller.
+Returns the process execution times of all programs run using
+@var{obj}.  @var{count} is the number of results expected.  The
+results will be placed into @var{vector}.  The results are in the
+order of the calls to @code{pex_run}.  Returns 0 on error, 1 on
+success.
+
+@code{struct pex_time} has the following fields: @code{user_seconds},
+@code{user_microseconds}, @code{system_seconds},
+@code{system_microseconds}.  On systems which do not support reporting
+process times, all the fields will be set to @code{0}.
 
 @end deftypefn
 
-@undocumented pfinish
+@deftypefn Extension void pex_free (struct pex_obj @var{obj})
+
+Clean up and free all data associated with @var{obj}.
+
+@end deftypefn
 
-pfinish: finish generation of script
+@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})
 
-pfinish is necessary for systems like MPW where a script is generated
-that runs the requested programs.
+An interface to @code{pex_init} to permit the easy execution of a
+single program.  The return value and most of the parameters are as
+for a call to @code{pex_run}.  @var{flags} is restricted to a
+combination of @code{PEX_SEARCH}, @code{PEX_STDERR_TO_STDOUT}, and
+@code{PEX_BINARY_OUTPUT}.  @var{outname} is interpreted as if
+@code{PEX_LAST} were set.  On a successful return, *@var{status} will
+be set to the exit status of the program.
+
+@end deftypefn
+
+@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
+still supported for compatibility purposes, but is no longer
+documented.
+
+@end deftypefn
+
+@deftypefn Extension int pwait (int @var{pid}, int *@var{status}, int @var{flags})
+
+Another part of the old execution interface.
+
+@end deftypefn
Index: libiberty/testsuite/Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/libiberty/testsuite/Makefile.in,v
retrieving revision 1.4
diff -u -p -r1.4 Makefile.in
--- libiberty/testsuite/Makefile.in	18 Nov 2003 18:29:02 -0000	1.4
+++ libiberty/testsuite/Makefile.in	21 Mar 2005 17:17:22 -0000
@@ -42,17 +42,28 @@ INCDIR=$(srcdir)/../$(MULTISRCTOP)../inc
 
 all:
 
+# CHECK is set to "really_check" or the empty string by configure.
 check: @CHECK@
 
+really-check: check-cplus-dem check-pexecute
+
 # Run some tests of the demangler.
 check-cplus-dem: test-demangle $(srcdir)/demangle-expected
 	./test-demangle < $(srcdir)/demangle-expected
 
+# Check the pexecute code.
+check-pexecute: test-pexecute
+	./test-pexecute
+
 TEST_COMPILE = $(CC) @DEFS@ $(LIBCFLAGS) -I.. -I$(INCDIR) $(HDEFINES)
 test-demangle: $(srcdir)/test-demangle.c ../libiberty.a
 	$(TEST_COMPILE) -o test-demangle \
 		$(srcdir)/test-demangle.c ../libiberty.a
 
+test-pexecute: $(srcdir)/test-pexecute.c ../libiberty.a
+	$(TEST_COMPILE) -DHAVE_CONFIG_H -I.. -o test-pexecute \
+		$(srcdir)/test-pexecute.c ../libiberty.a
+
 # Standard (either GNU or Cygnus) rules we don't use.
 info install-info clean-info dvi install etags tags installcheck:
 
Index: libiberty/testsuite/test-pexecute.c
===================================================================
RCS file: libiberty/testsuite/test-pexecute.c
diff -N libiberty/testsuite/test-pexecute.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libiberty/testsuite/test-pexecute.c	21 Mar 2005 17:17:22 -0000
@@ -0,0 +1,531 @@
+/* Pexecute test program,
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor <ian@airs.com>.
+
+   This file is part of GNU libiberty.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "ansidecl.h"
+#include "libiberty.h"
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
+#endif
+#ifndef WTERMSIG
+#define WTERMSIG(S) ((S) & 0x7f)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(S) (((S) & 0xff) == 0)
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
+#endif
+#ifndef WSTOPSIG
+#define WSTOPSIG WEXITSTATUS
+#endif
+#ifndef WCOREDUMP
+#define WCOREDUMP(S) ((S) & WCOREFLG)
+#endif
+#ifndef WCOREFLG
+#define WCOREFLG 0200
+#endif
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+/* When this program is run with no arguments, it runs some tests of
+   the libiberty pexecute functions.  As a test program, it simply
+   invokes itself with various arguments.
+
+   argv[1]:
+     *empty string*      Run tests, exit with success status
+     exit                Exit success
+     error               Exit error
+     abort               Abort
+     echo                Echo remaining arguments, exit success
+     echoerr             Echo next arg to stdout, next to stderr, repeat
+     copy                Copy stdin to stdout
+     write               Write stdin to file named in next argument
+*/
+
+static void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN;
+static void error (int, const char *);
+static void check_line (int, FILE *, const char *);
+static void do_cmd PARAMS ((int, char **)) ATTRIBUTE_NORETURN;
+
+/* The number of errors we have seen.  */
+
+static int error_count;
+
+/* Print a fatal error and exit.  LINE is the line number where we
+   detected the error, ERRMSG is the error message to print, and ERR
+   is 0 or an errno value to print.  */
+
+static void
+fatal_error (line, errmsg, err)
+     int line;
+     const char *errmsg;
+     int err;
+{
+  fprintf (stderr, "test-pexecute:%d: %s", line, errmsg);
+  if (errno != 0)
+    fprintf (stderr, ": %s", xstrerror (err));
+  fprintf (stderr, "\n");
+  exit (EXIT_FAILURE);
+}
+
+#define FATAL_ERROR(ERRMSG, ERR) fatal_error (__LINE__, ERRMSG, ERR)
+
+/* Print an error message and bump the error count.  LINE is the line
+   number where we detected the error, ERRMSG is the error to
+   print.  */
+
+static void
+error (line, errmsg)
+     int line;
+     const char *errmsg;
+{
+  fprintf (stderr, "test-pexecute:%d: %s\n", line, errmsg);
+  ++error_count;
+}
+
+#define ERROR(ERRMSG) error (__LINE__, ERRMSG)
+
+/* Check a line in a file.  */
+
+static void
+check_line (line, e, str)
+     int line;
+     FILE *e;
+     const char *str;
+{
+  const char *p;
+  int c;
+  char buf[1000];
+
+  p = str;
+  while (1)
+    {
+      c = getc (e);
+
+      if (*p == '\0')
+	{
+	  if (c != '\n')
+	    {
+	      snprintf (buf, sizeof buf, "got '%c' when expecting newline", c);
+	      fatal_error (line, buf, 0);
+	    }
+	  c = getc (e);
+	  if (c != EOF)
+	    {
+	      snprintf (buf, sizeof buf, "got '%c' when expecting EOF", c);
+	      fatal_error (line, buf, 0);
+	    }
+	  return;
+	}
+
+      if (c != *p)
+	{
+	  snprintf (buf, sizeof buf, "expected '%c', got '%c'", *p, c);
+	  fatal_error (line, buf, 0);
+	}
+
+      ++p;
+    }
+}
+
+#define CHECK_LINE(E, STR) check_line (__LINE__, E, STR)
+
+/* Main function for the pexecute tester.  Run the tests.  */
+
+int
+main (int argc, char **argv)
+{
+  int trace;
+  struct pex_obj *test_pex_tmp;
+  int test_pex_status;
+  FILE *test_pex_file;
+  struct pex_obj *pex1;
+  char *subargv[10];
+  int status;
+  FILE *e;
+  int statuses[10];
+
+  trace = 0;
+  if (argc > 1 && strcmp (argv[1], "-t") == 0)
+    {
+      trace = 1;
+      --argc;
+      ++argv;
+    }
+
+  if (argc > 1)
+    do_cmd (argc, argv);
+
+#define TEST_PEX_INIT(FLAGS, TEMPBASE)					\
+  (((test_pex_tmp = pex_init (FLAGS, "test-pexecute", TEMPBASE))	\
+    != NULL)								\
+   ? test_pex_tmp							\
+   : (FATAL_ERROR ("pex_init failed", 0), NULL))
+
+#define TEST_PEX_RUN(PEXOBJ, FLAGS, EXECUTABLE, ARGV, OUTNAME, ERRNAME)	\
+  do									\
+    {									\
+      int err;								\
+      if (trace)							\
+	fprintf (stderr, "Line %d: running %s %s\n",			\
+		 __LINE__, EXECUTABLE, ARGV[0]);			\
+      const char *pex_run_err = pex_run (PEXOBJ, FLAGS, EXECUTABLE,	\
+					 ARGV, OUTNAME, ERRNAME, &err);	\
+      if (pex_run_err != NULL)						\
+	FATAL_ERROR (pex_run_err, err);					\
+    }									\
+  while (0)
+
+#define TEST_PEX_GET_STATUS_1(PEXOBJ)					\
+  (pex_get_status (PEXOBJ, 1, &test_pex_status)				\
+   ? test_pex_status							\
+   : (FATAL_ERROR ("pex_get_status failed", errno), 1))
+
+#define TEST_PEX_GET_STATUS(PEXOBJ, COUNT, VECTOR)			\
+  do									\
+    {									\
+      if (!pex_get_status (PEXOBJ, COUNT, VECTOR))			\
+	FATAL_ERROR ("pex_get_status failed", errno);			\
+    }									\
+  while (0)
+
+#define TEST_PEX_READ_OUTPUT(PEXOBJ)					\
+  ((test_pex_file = pex_read_output (PEXOBJ, 0)) != NULL		\
+   ? test_pex_file							\
+   : (FATAL_ERROR ("pex_read_output failed", errno), NULL))
+
+  remove ("temp.x");
+  remove ("temp.y");
+
+  memset (subargv, 0, sizeof subargv);
+
+  subargv[0] = "./test-pexecute";
+
+  pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
+  subargv[1] = "exit";
+  subargv[2] = NULL;
+  TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL);
+  status = TEST_PEX_GET_STATUS_1 (pex1);
+  if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
+    ERROR ("exit failed");
+  pex_free (pex1);
+
+  pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
+  subargv[1] = "error";
+  subargv[2] = NULL;
+  TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, NULL);
+  status = TEST_PEX_GET_STATUS_1 (pex1);
+  if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_FAILURE)
+    ERROR ("error test failed");
+  pex_free (pex1);
+
+  /* We redirect stderr to a file to avoid an error message which is
+     printed on mingw32 when the child calls abort.  */
+  pex1 = TEST_PEX_INIT (PEX_USE_PIPES, NULL);
+  subargv[1] = "abort";
+  subargv[2] = NULL;
+  TEST_PEX_RUN (pex1, PEX_LAST, "./test-pexecute", subargv, NULL, "temp.z");
+  status = TEST_PEX_GET_STATUS_1 (pex1);
+  if (!WIFSIGNALED (status) || WTERMSIG (status) != SIGABRT)
+    ERROR ("abort failed");
+  pex_free (pex1);
+  remove ("temp.z");
+
+  pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
+  subargv[1] = "echo";
+  subargv[2] = "foo";
+  subargv[3] = NULL;
+  TEST_PEX_RUN (pex1, 0, "./test-pexecute", subargv, NULL, NULL);
+  e = TEST_PEX_READ_OUTPUT (pex1);
+  CHECK_LINE (e, "foo");
+  if (TEST_PEX_GET_STATUS_1 (pex1) != 0)
+    ERROR ("echo exit status failed");
+  pex_free (pex1);
+
+  pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
+  subargv[1] = "echo";
+  subargv[2] = "bar";
+  subargv[3] = NULL;
+  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
+  subargv[1] = "copy";
+  subargv[2] = NULL;
+  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
+  e = TEST_PEX_READ_OUTPUT (pex1);
+  CHECK_LINE (e, "bar");
+  TEST_PEX_GET_STATUS (pex1, 2, statuses);
+  if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
+      || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
+    ERROR ("copy exit status failed");
+  pex_free (pex1);
+  if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
+    ERROR ("temporary files exist");
+
+  pex1 = TEST_PEX_INIT (0, "temp");
+  subargv[1] = "echo";
+  subargv[2] = "bar";
+  subargv[3] = NULL;
+  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
+  subargv[1] = "copy";
+  subargv[2] = NULL;
+  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
+  e = TEST_PEX_READ_OUTPUT (pex1);
+  CHECK_LINE (e, "bar");
+  TEST_PEX_GET_STATUS (pex1, 2, statuses);
+  if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
+      || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
+    ERROR ("copy exit status failed");
+  pex_free (pex1);
+  if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
+    ERROR ("temporary files exist");
+
+  pex1 = TEST_PEX_INIT (PEX_SAVE_TEMPS, "temp");
+  subargv[1] = "echo";
+  subargv[2] = "quux";
+  subargv[3] = NULL;
+  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", NULL);
+  subargv[1] = "copy";
+  subargv[2] = NULL;
+  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
+  e = TEST_PEX_READ_OUTPUT (pex1);
+  CHECK_LINE (e, "quux");
+  TEST_PEX_GET_STATUS (pex1, 2, statuses);
+  if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
+      || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
+    ERROR ("copy temp exit status failed");
+  e = fopen ("temp.x", "r");
+  if (e == NULL)
+    FATAL_ERROR ("fopen temp.x failed in copy temp", errno);
+  CHECK_LINE (e, "quux");
+  fclose (e);
+  e = fopen ("temp.y", "r");
+  if (e == NULL)
+    FATAL_ERROR ("fopen temp.y failed in copy temp", errno);
+  CHECK_LINE (e, "quux");
+  fclose (e);
+  pex_free (pex1);
+  remove ("temp.x");
+  remove ("temp.y");
+
+  pex1 = TEST_PEX_INIT (PEX_USE_PIPES, "temp");
+  subargv[1] = "echoerr";
+  subargv[2] = "one";
+  subargv[3] = "two";
+  subargv[4] = NULL;
+  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".x", "temp2.x");
+  subargv[1] = "write";
+  subargv[2] = "temp2.y";
+  subargv[3] = NULL;
+  TEST_PEX_RUN (pex1, PEX_SUFFIX, "./test-pexecute", subargv, ".y", NULL);
+  TEST_PEX_GET_STATUS (pex1, 2, statuses);
+  if (!WIFEXITED (statuses[0]) || WEXITSTATUS (statuses[0]) != EXIT_SUCCESS
+      || !WIFEXITED (statuses[1]) || WEXITSTATUS (statuses[1]) != EXIT_SUCCESS)
+    ERROR ("echoerr exit status failed");
+  pex_free (pex1);
+  if (fopen ("temp.x", "r") != NULL || fopen ("temp.y", "r") != NULL)
+    ERROR ("temporary files exist");
+  e = fopen ("temp2.x", "r");
+  if (e == NULL)
+    FATAL_ERROR ("fopen temp2.x failed in echoerr", errno);
+  CHECK_LINE (e, "two");
+  fclose (e);
+  e = fopen ("temp2.y", "r");
+  if (e == NULL)
+    FATAL_ERROR ("fopen temp2.y failed in echoerr", errno);
+  CHECK_LINE (e, "one");
+  fclose (e);
+  remove ("temp2.x");
+  remove ("temp2.y");
+
+  /* Test the old pexecute interface.  */
+  {
+    int pid1, pid2;
+    char *errmsg_fmt;
+    char *errmsg_arg;
+    char errbuf1[1000];
+    char errbuf2[1000];
+
+    subargv[1] = "echo";
+    subargv[2] = "oldpexecute";
+    subargv[3] = NULL;
+    pid1 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp",
+		     &errmsg_fmt, &errmsg_arg, PEXECUTE_FIRST);
+    if (pid1 < 0)
+      {
+	snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg);
+	snprintf (errbuf2, sizeof errbuf2, "pexecute 1 failed: %s", errbuf1);
+	FATAL_ERROR (errbuf2, 0);
+      }
+
+    subargv[1] = "write";
+    subargv[2] = "temp.y";
+    subargv[3] = NULL;
+    pid2 = pexecute ("./test-pexecute", subargv, "test-pexecute", "temp",
+		     &errmsg_fmt, &errmsg_arg, PEXECUTE_LAST);
+    if (pid2 < 0)
+      {
+	snprintf (errbuf1, sizeof errbuf1, errmsg_fmt, errmsg_arg);
+	snprintf (errbuf2, sizeof errbuf2, "pexecute 2 failed: %s", errbuf1);
+	FATAL_ERROR (errbuf2, 0);
+      }
+
+    if (pwait (pid1, &status, 0) < 0)
+      FATAL_ERROR ("write pwait 1 failed", errno);
+    if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
+      ERROR ("write exit status 1 failed");
+
+    if (pwait (pid2, &status, 0) < 0)
+      FATAL_ERROR ("write pwait 1 failed", errno);
+    if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
+      ERROR ("write exit status 2 failed");
+
+    e = fopen ("temp.y", "r");
+    if (e == NULL)
+      FATAL_ERROR ("fopen temp.y failed in copy temp", errno);
+    CHECK_LINE (e, "oldpexecute");
+    fclose (e);
+
+    remove ("temp.y");
+  }
+
+  if (trace)
+    fprintf (stderr, "Exiting with status %d\n", error_count);
+
+  return error_count;
+}
+
+/* Execute one of the special testing commands.  */
+
+static void
+do_cmd (argc, argv)
+     int argc;
+     char **argv;
+{
+  const char *s;
+
+  /* Try to prevent generating a core dump.  */
+#ifdef RLIMIT_CORE
+ {
+   struct rlimit r;
+
+   r.rlim_cur = 0;
+   r.rlim_max = 0;
+   setrlimit (RLIMIT_CORE, &r);
+ }
+#endif
+
+  s = argv[1];
+  if (strcmp (s, "exit") == 0)
+    exit (EXIT_SUCCESS);
+  else if (strcmp (s, "echo") == 0)
+    {
+      int i;
+
+      for (i = 2; i < argc; ++i)
+	{
+	  if (i > 2)
+	    putchar (' ');
+	  fputs (argv[i], stdout);
+	}
+      putchar ('\n');
+      exit (EXIT_SUCCESS);
+    }
+  else if (strcmp (s, "echoerr") == 0)
+    {
+      int i;
+
+      for (i = 2; i < argc; ++i)
+	{
+	  if (i > 3)
+	    putc (' ', (i & 1) == 0 ? stdout : stderr);
+	  fputs (argv[i], (i & 1) == 0 ? stdout : stderr);
+	}
+      putc ('\n', stdout);
+      putc ('\n', stderr);
+      exit (EXIT_SUCCESS);
+    }
+  else if (strcmp (s, "error") == 0)
+    exit (EXIT_FAILURE);
+  else if (strcmp (s, "abort") == 0)
+    abort ();
+  else if (strcmp (s, "copy") == 0)
+    {
+      int c;
+
+      while ((c = getchar ()) != EOF)
+	putchar (c);
+      exit (EXIT_SUCCESS);
+    }
+  else if (strcmp (s, "write") == 0)
+    {
+      FILE *e;
+      int c;
+
+      e = fopen (argv[2], "w");
+      if (e == NULL)
+	FATAL_ERROR ("fopen for write failed", errno);
+      while ((c = getchar ()) != EOF)
+	putc (c, e);
+      if (fclose (e) != 0)
+	FATAL_ERROR ("fclose for write failed", errno);
+      exit (EXIT_SUCCESS);
+    }
+  else
+    {
+      char buf[1000];
+
+      snprintf (buf, sizeof buf, "unrecognized command %s", argv[1]);
+      FATAL_ERROR (buf, 0);
+    }
+
+  exit (EXIT_FAILURE);
+}
Index: include/libiberty.h
===================================================================
RCS file: /cvs/gcc/gcc/include/libiberty.h,v
retrieving revision 1.42
diff -u -p -r1.42 libiberty.h
--- include/libiberty.h	10 Mar 2005 00:57:07 -0000	1.42
+++ include/libiberty.h	21 Mar 2005 17:17:22 -0000
@@ -48,6 +48,8 @@ extern "C" {
 #include <stdarg.h>
 #endif
 
+#include <stdio.h>
+
 /* Build an argument vector from a string.  Allocates memory using
    malloc.  Use freeargv to free the vector.  */
 
@@ -305,6 +307,170 @@ extern void hex_init PARAMS ((void));
    the argument being performed exactly once.  */
 #define hex_value(c)	((unsigned int) _hex_value[(unsigned char) (c)])
 
+/* Flags for pex_init.  These are bits to be or'ed together.  */
+
+/* Record subprocess times, if possible.  */
+#define PEX_RECORD_TIMES	0x1
+
+/* Use pipes for communication between processes, if possible.  */
+#define PEX_USE_PIPES		0x2
+
+/* Save files used for communication between processes.  */
+#define PEX_SAVE_TEMPS		0x4
+
+/* Prepare to execute one or more programs, with standard output of
+   each program fed to standard input of the next.
+   FLAGS	As above.
+   PNAME	The name of the program to report in error messages.
+   TEMPBASE	A base name to use for temporary files; may be NULL to
+   		use a random name.
+   Returns NULL on error.  */
+
+extern struct pex_obj *pex_init PARAMS ((int flags, const char *pname,
+					 const char *tempbase));
+
+/* Flags for pex_run.  These are bits to be or'ed together.  */
+
+/* Last program in pipeline.  Standard output of program goes to
+   OUTNAME, or, if OUTNAME is NULL, to standard output of caller.  Do
+   not set this if you want to call pex_read_output.  After this is
+   set, pex_run may no longer be called with the same struct
+   pex_obj.  */
+#define PEX_LAST		0x1
+
+/* Search for program in executable search path.  */
+#define PEX_SEARCH		0x2
+
+/* OUTNAME is a suffix.  */
+#define PEX_SUFFIX		0x4
+
+/* Send program's standard error to standard output.  */
+#define PEX_STDERR_TO_STDOUT	0x8
+
+/* Input file should be opened in binary mode.  This flag is ignored
+   on Unix.  */
+#define PEX_BINARY_INPUT	0x10
+
+/* Output file should be opened in binary mode.  This flag is ignored
+   on Unix.  For proper behaviour PEX_BINARY_INPUT and
+   PEX_BINARY_OUTPUT have to match appropriately--i.e., a call using
+   PEX_BINARY_OUTPUT should be followed by a call using
+   PEX_BINARY_INPUT.  */
+#define PEX_BINARY_OUTPUT	0x20
+
+/* Execute one program.  Returns NULL on success.  On error returns an
+   error string (typically just the name of a system call).
+
+   OBJ		Returned by pex_init.
+
+   FLAGS	As above.
+
+   EXECUTABLE	The program to execute.
+
+   ARGV		NULL terminated array of arguments to pass to the program.
+
+   OUTNAME	Sets the output file name as follows:
+
+		PEX_SUFFIX set (OUTNAME may not be NULL):
+		  TEMPBASE parameter to pex_init not NULL:
+		    Output file name is the concatenation of TEMPBASE
+		    and OUTNAME.
+		  TEMPBASE is NULL:
+		    Output file name is a random file name ending in
+		    OUTNAME.
+		PEX_SUFFIX not set:
+		  OUTNAME not NULL:
+		    Output file name is OUTNAME.
+		  OUTNAME NULL, TEMPBASE not NULL:
+		    Output file name is randomly chosen using
+		    TEMPBASE.
+		  OUTNAME NULL, TEMPBASE NULL:
+		    Output file name is randomly chosen.
+
+		If PEX_LAST is not set, the output file name is the
+   		name to use for a temporary file holding stdout, if
+   		any (there will not be a file if PEX_USE_PIPES is set
+   		and the system supports pipes).  If a file is used, it
+   		will be removed when no longer needed unless
+   		PEX_SAVE_TEMPS is set.
+
+		If PEX_LAST is set, and OUTNAME is not NULL, standard
+   		output is written to the output file name.  The file
+   		will not be removed.  If PEX_LAST and PEX_SUFFIX are
+   		both set, TEMPBASE may not be NULL.
+
+   ERRNAME	If not NULL, this is the name of a file to which
+		standard error is written.  If NULL, standard error of
+		the program is standard error of the caller.
+
+   ERR		On an error return, *ERR is set to an errno value, or
+   		to 0 if there is no relevant errno.
+*/
+
+extern const char *pex_run PARAMS ((struct pex_obj *obj, int flags,
+				    const char *executable,
+				    char * const *argv,
+				    const char *outname,
+				    const char *errname,
+				    int *err));
+
+/* 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.
+   Returns NULL on error.  Don't call fclose on the returned FILE; it
+   will be closed by pex_free.  */
+
+extern FILE *pex_read_output PARAMS ((struct pex_obj *, int binary));
+
+/* Return exit status of all programs.  The status codes in the vector
+   are in the order of the calls to pex_run.  Returns 0 on error, 1 on
+   success.  */
+
+extern int pex_get_status PARAMS ((struct pex_obj *, int count, int *vector));
+
+/* Return times of all programs.  This is really just struct timeval,
+   but that is not portable to all systems.  Returns 0 on error, 1 on
+   success.  */
+
+struct pex_time
+{
+  unsigned long user_seconds;
+  unsigned long user_microseconds;
+  unsigned long system_seconds;
+  unsigned long system_microseconds;
+};
+
+extern int pex_get_times PARAMS ((struct pex_obj *, int count,
+				  struct pex_time *vector));
+
+/* Clean up a pex_obj.  */
+
+extern void pex_free PARAMS ((struct pex_obj *));
+
+/* Just execute one program.  Return value is as for pex_run.
+   FLAGS	Combination of PEX_SEARCH and PEX_STDERR_TO_STDOUT.
+   EXECUTABLE	As for pex_run.
+   ARGV		As for pex_run.
+   PNAME	As for pex_init.
+   OUTNAME	As for pex_run when PEX_LAST is set.
+   ERRNAME	As for pex_run.
+   STATUS	Set to exit status on success.
+   ERR		As for pex_run.
+*/
+
+extern const char *pex_one PARAMS ((int flags,
+				    const char *executable,
+				    char * const *argv,
+				    const char *pname,
+				    const char *outname,
+				    const char *errname,
+				    int *status,
+				    int *err));
+
+/* pexecute and pwait are the old pexecute interface, still here for
+   backward compatibility.  Don't use these for new code.  Instead,
+   use pex_init/pex_run/pex_get_status/pex_free, or pex_one.  */
+
 /* Definitions used by the pexecute routine.  */
 
 #define PEXECUTE_FIRST   1
@@ -316,7 +482,7 @@ extern void hex_init PARAMS ((void));
 /* Execute a program.  */
 
 extern int pexecute PARAMS ((const char *, char * const *, const char *,
-			    const char *, char **, char **, int));
+			     const char *, char **, char **, int));
 
 /* Wait for pexecute to finish.  */
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]