RFC/RFT: split up pexecute.c

Zack Weinberg zack@codesourcery.com
Thu Jan 23 18:41:00 GMT 2003


DJ Delorie <dj@redhat.com> writes:

> EMX defines OS2.  MPW is not currently supported by configure anyway,
> so you can just leave that source file unused.  I believe the
> remainder are correct.

Okay.  What do you think of this patch?

zw

        * Makefile.in (CFILES): Remove pexecute.c, add pex-*.c.
        (REQUIRED_OFILES): Remove pexecute.o, add @pexecute@.
        (CONFIGURED_OFILES): Add pex-*.o.
        Regenerate dependencies.

        * configure.in: Change AC_INIT argument to xmalloc.c.
        Calculate and substitute @pexecute@ depending on host triple.

        * pexecute.c: Removed; contents split into...
        * pex-common.h, pex-cygwin.c, pex-djgpp.c, pex-mpw.c,
        pex-msdos.c, pex-os2.c, pex-unix.c, pex-win32.c: 
        ... these new files.

===================================================================
Index: Makefile.in
--- Makefile.in	9 Jan 2003 08:10:57 -0000	1.80
+++ Makefile.in	23 Jan 2003 18:37:34 -0000
@@ -140,7 +140,10 @@ CFILES = alloca.c argv.c asprintf.c atex
 	make-temp-file.c md5.c memchr.c memcmp.c memcpy.c memmove.c	\
 	 memset.c mkstemps.c						\
 	objalloc.c obstack.c						\
-	partition.c pexecute.c putenv.c					\
+	partition.c							\
+	pex-cygwin.c pex-djgpp.c pex-mpw.c pex-msdos.c pex-os2.c	\
+	pex-unix.c pex-win32.c						\
+        putenv.c							\
 	random.c regex.c rename.c rindex.c				\
 	safe-ctype.c setenv.c sigsetmask.c sort.c spaces.c		\
 	 splay-tree.c strcasecmp.c strchr.c strdup.c strerror.c		\
@@ -164,7 +167,7 @@ REQUIRED_OFILES = regex.o cplus-dem.o cp
 	make-relative-prefix.o						\
 	make-temp-file.o						\
 	objalloc.o obstack.o						\
-	partition.o pexecute.o						\
+	partition.o @pexecute@						\
 	safe-ctype.o sort.o spaces.o splay-tree.o strerror.o		\
 	 strsignal.o							\
 	ternary.o							\
@@ -181,6 +184,8 @@ CONFIGURED_OFILES = asprintf.o atexit.o	
 	getcwd.o getpagesize.o						\
 	index.o insque.o						\
 	memchr.o memcmp.o memcpy.o memmove.o memset.o mkstemps.o	\
+	pex-cygwin.o pex-djgpp.o pex-mpw.o pex-msdos.o pex-os2.o	\
+	pex-unix.o pex-win32.o						\
 	putenv.o							\
 	random.o rename.o rindex.o					\
 	setenv.o sigsetmask.o strcasecmp.o strchr.o strdup.o		\
@@ -418,7 +423,7 @@ copysign.o: $(INCDIR)/ansidecl.h
 cp-demangle.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/demangle.h \
 	$(INCDIR)/dyn-string.h $(INCDIR)/getopt.h $(INCDIR)/libiberty.h
 cplus-dem.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/demangle.h \
-	$(INCDIR)/getopt.h $(INCDIR)/libiberty.h $(INCDIR)/safe-ctype.h
+	$(INCDIR)/libiberty.h $(INCDIR)/safe-ctype.h
 dyn-string.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/dyn-string.h \
 	$(INCDIR)/libiberty.h
 fdmatch.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h
@@ -437,7 +442,8 @@ hashtab.o: config.h $(INCDIR)/ansidecl.h
 hex.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h
 lbasename.o: $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \
 	$(INCDIR)/safe-ctype.h
-make-relative-prefix.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h
+make-relative-prefix.o: config.h $(INCDIR)/ansidecl.h \
+	$(INCDIR)/libiberty.h
 make-temp-file.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h
 md5.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/md5.h
 memchr.o: $(INCDIR)/ansidecl.h
@@ -450,8 +456,7 @@ objalloc.o: config.h $(INCDIR)/ansidecl.
 obstack.o: config.h $(INCDIR)/obstack.h
 partition.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \
 	$(INCDIR)/partition.h
-pexecute.o: config.h $(INCDIR)/ansidecl.h $(INCDIR)/libiberty.h \
-	$(INCDIR)/safe-ctype.h
+pex-msdos.o: $(INCDIR)/safe-ctype.h
 putenv.o: config.h $(INCDIR)/ansidecl.h
 random.o: $(INCDIR)/ansidecl.h
 regex.o: config.h $(INCDIR)/xregex.h $(INCDIR)/xregex2.h
===================================================================
Index: configure.in
--- configure.in	1 Jul 2002 05:38:50 -0000	1.52
+++ configure.in	23 Jan 2003 18:37:34 -0000
@@ -1,7 +1,7 @@
 dnl Process this file with autoconf to produce a configure script
 
 AC_PREREQ(2.13)
-AC_INIT(pexecute.c)
+AC_INIT(xmalloc.c)
 
 # This works around the fact that libtool configuration may change LD
 # for this particular configuration, but some shells, instead of
@@ -424,6 +424,17 @@ if test -z "${setobjs}"; then
   done
   AC_CHECK_FUNCS($checkfuncs)
 fi
+
+# Figure out which version of pexecute to use.
+case "${host}" in
+     *-*-cygwin*)		pexecute=pex-cygwin.o ;;
+     *-*-mingw* | *-*-winnt*)	pexecute=pex-win32.o  ;;
+     *-*-msdosdjgpp*)		pexecute=pex-djgpp.o  ;;
+     *-*-msdos*)		pexecute=pex-msdos.o  ;;
+     *-*-os2-emx*)		pexecute=pex-os2.o    ;;
+     *)				pexecute=pex-unix.o   ;;
+esac
+AC_SUBST(pexecute)
 
 libiberty_AC_FUNC_STRNCMP
 
===================================================================
Index: pex-common.h
--- pex-common.h	1 Jan 1970 00:00:00 -0000
+++ pex-common.h	23 Jan 2003 18:37:34 -0000
@@ -0,0 +1,104 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+   with other subprocesses), and wait for it.  Shared logic and documentation.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+   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: execute a program.
+
+ @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)
+
+ Executes a program.
+
+ @var{program} and @var{argv} are the arguments to
+ @code{execv}/@code{execvp}.
+
+ @var{this_pname} is name of the calling program (i.e., @code{argv[0]}).
+
+ @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.
+
+ @end deftypefn
+
+ @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.
+
+ @end deftypefn
+
+ @undocumented pfinish
+
+ pfinish: finish generation of script
+
+ pfinish is necessary for systems like MPW where a script is generated
+ that runs the requested programs.  */
+
+#include "config.h"
+#include "libiberty.h"
+
+#define install_error_msg "installation problem, cannot exec `%s'"
+
+/* stdin file number.  */
+#define STDIN_FILE_NO 0
+
+/* stdout file number.  */
+#define STDOUT_FILE_NO 1
+
+/* value of `pipe': port index for reading.  */
+#define READ_PORT 0
+
+/* value of `pipe': port index for writing.  */
+#define WRITE_PORT 1
+
===================================================================
Index: pex-cygwin.c
--- pex-cygwin.c	1 Jan 1970 00:00:00 -0000
+++ pex-cygwin.c	23 Jan 2003 18:37:34 -0000
@@ -0,0 +1,132 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+   with other subprocesses), and wait for it.  Cygwin specialization.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+   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 "pex-common.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <process.h>
+#include <io.h>
+#include <fcntl.h>
+#include <signal.h>
+
+extern int _spawnv ();
+extern int _spawnvp ();
+
+/* Win32 supports pipes, and Cygwin provides waitpid.  */
+
+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;
+     int flags;
+{
+  int pid;
+  int pdes[2], org_stdin, org_stdout;
+  int input_desc, output_desc;
+  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;
+
+  /* If this is the first process, initialize.  */
+  if (flags & PEXECUTE_FIRST)
+    last_pipe_input = STDIN_FILE_NO;
+
+  input_desc = last_pipe_input;
+
+  /* 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 (_pipe (pdes, 256, O_BINARY) < 0)
+	{
+	  *errmsg_fmt = "pipe";
+	  *errmsg_arg = NULL;
+	  return -1;
+	}
+      output_desc = pdes[WRITE_PORT];
+      last_pipe_input = pdes[READ_PORT];
+    }
+  else
+    {
+      /* Last process.  */
+      output_desc = STDOUT_FILE_NO;
+      last_pipe_input = STDIN_FILE_NO;
+    }
+
+  if (input_desc != STDIN_FILE_NO)
+    {
+      org_stdin = dup (STDIN_FILE_NO);
+      dup2 (input_desc, STDIN_FILE_NO);
+      close (input_desc); 
+    }
+
+  if (output_desc != STDOUT_FILE_NO)
+    {
+      org_stdout = dup (STDOUT_FILE_NO);
+      dup2 (output_desc, STDOUT_FILE_NO);
+      close (output_desc);
+    }
+
+  pid = (flags & PEXECUTE_SEARCH ? _spawnvp : _spawnv)
+    (_P_NOWAIT, program, argv);
+
+  if (input_desc != STDIN_FILE_NO)
+    {
+      dup2 (org_stdin, STDIN_FILE_NO);
+      close (org_stdin);
+    }
+
+  if (output_desc != STDOUT_FILE_NO)
+    {
+      dup2 (org_stdout, STDOUT_FILE_NO);
+      close (org_stdout);
+    }
+
+  if (pid == -1)
+    {
+      *errmsg_fmt = install_error_msg;
+      *errmsg_arg = program;
+      return -1;
+    }
+
+  return pid;
+}
+
+int
+pwait (pid, status, flags)
+     int pid;
+     int *status;
+     int flags ATTRIBUTE_UNUSED;
+{
+  return waitpid (pid, status, 0);
+}
===================================================================
Index: pex-djgpp.c
--- pex-djgpp.c	1 Jan 1970 00:00:00 -0000
+++ pex-djgpp.c	23 Jan 2003 18:37:34 -0000
@@ -0,0 +1,103 @@
+/* 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
+   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 "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
+#include <process.h>
+
+/* Use ECHILD if available, otherwise use EINVAL.  */
+#ifdef ECHILD
+#define PWAIT_ERROR ECHILD
+#else
+#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;
+     int flags;
+{
+  int rc;
+
+  last_pid++;
+  if (last_pid < 0)
+    last_pid = 1;
+
+  if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
+    abort ();
+
+  /* ??? What are the possible return values from spawnv?  */
+  rc = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (P_WAIT, program, argv);
+
+  if (rc == -1)
+    {
+      *errmsg_fmt = install_error_msg;
+      *errmsg_arg = (char *)program;
+      return -1;
+    }
+
+  /* Tuck the status away for pwait, and return a "pid".  */
+  last_status = rc << 8;
+  return last_pid;
+}
+
+int
+pwait (pid, status, flags)
+     int pid;
+     int *status;
+     int flags;
+{
+  /* 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;
+}
===================================================================
Index: pex-mpw.c
--- pex-mpw.c	1 Jan 1970 00:00:00 -0000
+++ pex-mpw.c	23 Jan 2003 18:37:34 -0000
@@ -0,0 +1,161 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+   with other subprocesses), and wait for it.  MPW specialization.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+   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 "pex-common.h"
+
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+/* MPW pexecute doesn't actually run anything; instead, it writes out
+   script commands that, when run, will do the actual executing.
+
+   For example, in GCC's case, GCC will write out several script commands:
+
+   cpp ...
+   cc1 ...
+   as ...
+   ld ...
+
+   and then exit.  None of the above programs will have run yet.  The task
+   that called GCC will then execute the script and cause cpp,etc. to run.
+   The caller must invoke pfinish before calling exit.  This adds
+   the finishing touches to the generated script.  */
+
+static int first_time = 1;
+
+extern void mpwify_filename PARAMS ((const char *, char *));
+
+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;
+     int flags;
+{
+  char tmpprogram[255];
+  char *cp, *tmpname;
+  int i;
+
+  mpwify_filename (program, tmpprogram);
+  if (first_time)
+    {
+      printf ("Set Failed 0\n");
+      first_time = 0;
+    }
+
+  fputs ("If {Failed} == 0\n", stdout);
+  /* If being verbose, output a copy of the command.  It should be
+     accurate enough and escaped enough to be "clickable".  */
+  if (flags & PEXECUTE_VERBOSE)
+    {
+      fputs ("\tEcho ", stdout);
+      fputc ('\'', stdout);
+      fputs (tmpprogram, stdout);
+      fputc ('\'', stdout);
+      fputc (' ', stdout);
+      for (i=1; argv[i]; i++)
+	{
+	  fputc ('\'', stdout);
+	  /* See if we have an argument that needs fixing.  */
+	  if (strchr(argv[i], '/'))
+	    {
+	      tmpname = (char *) xmalloc (256);
+	      mpwify_filename (argv[i], tmpname);
+	      argv[i] = tmpname;
+	    }
+	  for (cp = argv[i]; *cp; cp++)
+	    {
+	      /* Write an Option-d escape char in front of special chars.  */
+	      if (strchr("'+", *cp))
+		fputc ('\266', stdout);
+	      fputc (*cp, stdout);
+	    }
+	  fputc ('\'', stdout);
+	  fputc (' ', stdout);
+	}
+      fputs ("\n", stdout);
+    }
+  fputs ("\t", stdout);
+  fputs (tmpprogram, stdout);
+  fputc (' ', stdout);
+
+  for (i=1; argv[i]; i++)
+    {
+      /* See if we have an argument that needs fixing.  */
+      if (strchr(argv[i], '/'))
+	{
+	  tmpname = (char *) xmalloc (256);
+	  mpwify_filename (argv[i], tmpname);
+	  argv[i] = tmpname;
+	}
+      if (strchr (argv[i], ' '))
+	fputc ('\'', stdout);
+      for (cp = argv[i]; *cp; cp++)
+	{
+	  /* Write an Option-d escape char in front of special chars.  */
+	  if (strchr("'+", *cp))
+	    fputc ('\266', stdout);
+	  fputc (*cp, stdout);
+	}
+      if (strchr (argv[i], ' '))
+	fputc ('\'', stdout);
+      fputc (' ', stdout);
+    }
+
+  fputs ("\n", stdout);
+
+  /* Output commands that arrange to clean up and exit if a failure occurs.
+     We have to be careful to collect the status from the program that was
+     run, rather than some other script command.  Also, we don't exit
+     immediately, since necessary cleanups are at the end of the script.  */
+  fputs ("\tSet TmpStatus {Status}\n", stdout);
+  fputs ("\tIf {TmpStatus} != 0\n", stdout);
+  fputs ("\t\tSet Failed {TmpStatus}\n", stdout);
+  fputs ("\tEnd\n", stdout);
+  fputs ("End\n", stdout);
+
+  /* We're just composing a script, can't fail here.  */
+  return 0;
+}
+
+int
+pwait (pid, status, flags)
+     int pid;
+     int *status;
+     int flags;
+{
+  *status = 0;
+  return 0;
+}
+
+/* Write out commands that will exit with the correct error code
+   if something in the script failed.  */
+
+void
+pfinish ()
+{
+  printf ("\tExit \"{Failed}\"\n");
+}
+
===================================================================
Index: pex-msdos.c
--- pex-msdos.c	1 Jan 1970 00:00:00 -0000
+++ pex-msdos.c	23 Jan 2003 18:37:34 -0000
@@ -0,0 +1,147 @@
+/* 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
+   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 "pex-common.h"
+
+#include <stdio.h>
+#include <errno.h>
+#ifdef NEED_DECLARATION_ERRNO
+extern int errno;
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "safe-ctype.h"
+#include <process.h>
+
+/* 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;
+     int flags;
+{
+  int rc;
+  char *scmd, *rf;
+  FILE *argfile;
+  int i, el = flags & PEXECUTE_SEARCH ? 4 : 0;
+
+  last_pid++;
+  if (last_pid < 0)
+    last_pid = 1;
+
+  if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
+    abort ();
+
+  if (temp_base == 0)
+    temp_base = choose_temp_base ();
+  scmd = (char *) xmalloc (strlen (program) + strlen (temp_base) + 6 + el);
+  rf = scmd + strlen(program) + 2 + el;
+  sprintf (scmd, "%s%s @%s.gp", program,
+	   (flags & PEXECUTE_SEARCH ? ".exe" : ""), temp_base);
+  argfile = fopen (rf, "w");
+  if (argfile == 0)
+    {
+      int errno_save = errno;
+      free (scmd);
+      errno = errno_save;
+      *errmsg_fmt = "cannot open `%s.gp'";
+      *errmsg_arg = temp_base;
+      return -1;
+    }
+
+  for (i=1; argv[i]; i++)
+    {
+      char *cp;
+      for (cp = argv[i]; *cp; cp++)
+	{
+	  if (*cp == '"' || *cp == '\'' || *cp == '\\' || ISSPACE (*cp))
+	    fputc ('\\', argfile);
+	  fputc (*cp, argfile);
+	}
+      fputc ('\n', argfile);
+    }
+  fclose (argfile);
+
+  rc = system (scmd);
+
+  {
+    int errno_save = errno;
+    remove (rf);
+    free (scmd);
+    errno = errno_save;
+  }
+
+  if (rc == -1)
+    {
+      *errmsg_fmt = install_error_msg;
+      *errmsg_arg = (char *)program;
+      return -1;
+    }
+
+  /* Tuck the status away for pwait, and return a "pid".  */
+  last_status = rc << 8;
+  return last_pid;
+}
+
+/* Use ECHILD if available, otherwise use EINVAL.  */
+#ifdef ECHILD
+#define PWAIT_ERROR ECHILD
+#else
+#define PWAIT_ERROR EINVAL
+#endif
+
+int
+pwait (pid, status, flags)
+     int pid;
+     int *status;
+     int flags;
+{
+  /* 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;
+  last_reaped = last_pid;
+  return last_pid;
+}
===================================================================
Index: pex-os2.c
--- pex-os2.c	1 Jan 1970 00:00:00 -0000
+++ pex-os2.c	23 Jan 2003 18:37:34 -0000
@@ -0,0 +1,72 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+   with other subprocesses), and wait for it.  OS/2 specialization.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+   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 "pex-common.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+/* ??? Does OS2 have process.h?  */
+extern int spawnv ();
+extern int spawnvp ();
+
+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;
+     int flags;
+{
+  int pid;
+
+  if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
+    abort ();
+  /* ??? Presumably 1 == _P_NOWAIT.  */
+  pid = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (1, program, argv);
+  if (pid == -1)
+    {
+      *errmsg_fmt = install_error_msg;
+      *errmsg_arg = program;
+      return -1;
+    }
+  return pid;
+}
+
+int
+pwait (pid, status, flags)
+     int pid;
+     int *status;
+     int flags;
+{
+  /* ??? Here's an opportunity to canonicalize the values in STATUS.
+     Needed?  */
+  int pid = wait (status);
+  return pid;
+}
===================================================================
Index: pex-unix.c
--- pex-unix.c	1 Jan 1970 00:00:00 -0000
+++ pex-unix.c	23 Jan 2003 18:37:34 -0000
@@ -0,0 +1,166 @@
+/* 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
+   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 "pex-common.h"
+
+#include <stdio.h>
+#include <errno.h>
+#ifdef NEED_DECLARATION_ERRNO
+extern int errno;
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifndef HAVE_WAITPID
+#define waitpid(pid, status, flags) wait(status)
+#endif
+
+extern int execv ();
+extern int execvp ();
+
+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 ATTRIBUTE_UNUSED;
+     char **errmsg_fmt, **errmsg_arg;
+     int flags;
+{
+  int (*func)() = (flags & PEXECUTE_SEARCH ? execvp : execv);
+  int pid;
+  int pdes[2];
+  int input_desc, output_desc;
+  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;
+
+  /* If this is the first process, initialize.  */
+  if (flags & PEXECUTE_FIRST)
+    last_pipe_input = STDIN_FILE_NO;
+
+  input_desc = last_pipe_input;
+
+  /* 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 (pipe (pdes) < 0)
+	{
+	  *errmsg_fmt = "pipe";
+	  *errmsg_arg = NULL;
+	  return -1;
+	}
+      output_desc = pdes[WRITE_PORT];
+      last_pipe_input = pdes[READ_PORT];
+    }
+  else
+    {
+      /* Last process.  */
+      output_desc = STDOUT_FILE_NO;
+      last_pipe_input = STDIN_FILE_NO;
+    }
+
+  /* Fork a subprocess; wait and retry if it fails.  */
+  sleep_interval = 1;
+  pid = -1;
+  for (retries = 0; retries < 4; retries++)
+    {
+      pid = fork ();
+      if (pid >= 0)
+	break;
+      sleep (sleep_interval);
+      sleep_interval *= 2;
+    }
+
+  switch (pid)
+    {
+    case -1:
+      *errmsg_fmt = "fork";
+      *errmsg_arg = NULL;
+      return -1;
+
+    case 0: /* child */
+      /* Move the input and output pipes into place, if necessary.  */
+      if (input_desc != STDIN_FILE_NO)
+	{
+	  close (STDIN_FILE_NO);
+	  dup (input_desc);
+	  close (input_desc);
+	}
+      if (output_desc != STDOUT_FILE_NO)
+	{
+	  close (STDOUT_FILE_NO);
+	  dup (output_desc);
+	  close (output_desc);
+	}
+
+      /* Close the parent's descs that aren't wanted here.  */
+      if (last_pipe_input != STDIN_FILE_NO)
+	close (last_pipe_input);
+
+      /* Exec the program.  */
+      (*func) (program, argv);
+
+      fprintf (stderr, "%s: ", this_pname);
+      fprintf (stderr, install_error_msg, program);
+      fprintf (stderr, ": %s\n", xstrerror (errno));
+      exit (-1);
+      /* NOTREACHED */
+      return 0;
+
+    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);
+
+      /* Return child's process number.  */
+      return pid;
+    }
+}
+
+int
+pwait (pid, status, flags)
+     int pid;
+     int *status;
+     int flags ATTRIBUTE_UNUSED;
+{
+  /* ??? Here's an opportunity to canonicalize the values in STATUS.
+     Needed?  */
+  pid = waitpid (pid, status, 0);
+  return pid;
+}
===================================================================
Index: pex-win32.c
--- pex-win32.c	1 Jan 1970 00:00:00 -0000
+++ pex-win32.c	23 Jan 2003 18:37:34 -0000
@@ -0,0 +1,243 @@
+/* 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
+   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 "pex-common.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <process.h>
+#include <io.h>
+#include <fcntl.h>
+#include <signal.h>
+
+/* mingw32 headers may not define the following.  */
+
+#ifndef _P_WAIT
+#  define _P_WAIT	0
+#  define _P_NOWAIT	1
+#  define _P_OVERLAY	2
+#  define _P_NOWAITO	3
+#  define _P_DETACH	4
+
+#  define WAIT_CHILD		0
+#  define WAIT_GRANDCHILD	1
+#endif
+
+/* This is a kludge to get around the Microsoft C spawn functions' propensity
+   to remove the outermost set of double quotes from all arguments.  */
+
+static const char * const *
+fix_argv (argvec)
+     char **argvec;
+{
+  int i;
+
+  for (i = 1; argvec[i] != 0; i++)
+    {
+      int len, j;
+      char *temp, *newtemp;
+
+      temp = argvec[i];
+      len = strlen (temp);
+      for (j = 0; j < len; j++)
+        {
+          if (temp[j] == '"')
+            {
+              newtemp = xmalloc (len + 2);
+              strncpy (newtemp, temp, j);
+              newtemp [j] = '\\';
+              strncpy (&newtemp [j+1], &temp [j], len-j);
+              newtemp [len+1] = 0;
+              temp = newtemp;
+              len++;
+              j++;
+            }
+        }
+
+        argvec[i] = temp;
+      }
+
+  for (i = 0; argvec[i] != 0; i++)
+    {
+      if (strpbrk (argvec[i], " \t"))
+        {
+	  int len, trailing_backslash;
+	  char *temp;
+
+	  len = strlen (argvec[i]);
+	  trailing_backslash = 0;
+
+	  /* There is an added complication when an arg with embedded white
+	     space ends in a backslash (such as in the case of -iprefix arg
+	     passed to cpp). The resulting quoted strings gets misinterpreted
+	     by the command interpreter -- it thinks that the ending quote
+	     is escaped by the trailing backslash and things get confused. 
+	     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] != '\\')
+	    {
+	      trailing_backslash = 1;
+	      ++len;			/* to escape the final backslash. */
+	    }
+
+	  len += 2;			/* and for the enclosing quotes. */
+
+	  temp = xmalloc (len + 1);
+	  temp[0] = '"';
+	  strcpy (temp + 1, argvec[i]);
+	  if (trailing_backslash)
+	    temp[len-2] = '\\';
+	  temp[len-1] = '"';
+	  temp[len] = '\0';
+
+	  argvec[i] = temp;
+	}
+    }
+
+  return (const char * const *) argvec;
+}
+
+/* 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;
+     const char *temp_base;
+     char **errmsg_fmt, **errmsg_arg;
+     int flags;
+{
+  int pid;
+  int pdes[2], org_stdin, org_stdout;
+  int input_desc, output_desc;
+  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;
+
+  /* If this is the first process, initialize.  */
+  if (flags & PEXECUTE_FIRST)
+    last_pipe_input = STDIN_FILE_NO;
+
+  input_desc = last_pipe_input;
+
+  /* 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 (_pipe (pdes, 256, O_BINARY) < 0)
+	{
+	  *errmsg_fmt = "pipe";
+	  *errmsg_arg = NULL;
+	  return -1;
+	}
+      output_desc = pdes[WRITE_PORT];
+      last_pipe_input = pdes[READ_PORT];
+    }
+  else
+    {
+      /* Last process.  */
+      output_desc = STDOUT_FILE_NO;
+      last_pipe_input = STDIN_FILE_NO;
+    }
+
+  if (input_desc != STDIN_FILE_NO)
+    {
+      org_stdin = dup (STDIN_FILE_NO);
+      dup2 (input_desc, STDIN_FILE_NO);
+      close (input_desc); 
+    }
+
+  if (output_desc != STDOUT_FILE_NO)
+    {
+      org_stdout = dup (STDOUT_FILE_NO);
+      dup2 (output_desc, STDOUT_FILE_NO);
+      close (output_desc);
+    }
+
+  pid = (flags & PEXECUTE_SEARCH ? _spawnvp : _spawnv)
+    (_P_NOWAIT, program, fix_argv(argv));
+
+  if (input_desc != STDIN_FILE_NO)
+    {
+      dup2 (org_stdin, STDIN_FILE_NO);
+      close (org_stdin);
+    }
+
+  if (output_desc != STDOUT_FILE_NO)
+    {
+      dup2 (org_stdout, STDOUT_FILE_NO);
+      close (org_stdout);
+    }
+
+  if (pid == -1)
+    {
+      *errmsg_fmt = install_error_msg;
+      *errmsg_arg = program;
+      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;
+     int *status;
+     int flags;
+{
+  int termstat;
+
+  pid = _cwait (&termstat, pid, WAIT_CHILD);
+
+  /* ??? Here's an opportunity to canonicalize the values in STATUS.
+     Needed?  */
+
+  /* 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);
+
+  return pid;
+}
===================================================================
Index: pexecute.c
--- pexecute.c	17 Oct 2001 21:15:41 -0000	1.23
+++ pexecute.c	1 Jan 1970 00:00:00 -0000
@@ -1,792 +0,0 @@
-/* Utilities to execute a program in a subprocess (possibly linked by pipes
-   with other subprocesses), and wait for it.
-   Copyright (C) 1996-2000 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.  */
-
-/* This file exports two functions: pexecute and pwait.  */
-
-/* This file lives in at least two places: libiberty and gcc.
-   Don't change one without the other.  */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#ifdef NEED_DECLARATION_ERRNO
-extern int errno;
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-
-#include "libiberty.h"
-#include "safe-ctype.h"
-
-/* stdin file number.  */
-#define STDIN_FILE_NO 0
-
-/* stdout file number.  */
-#define STDOUT_FILE_NO 1
-
-/* value of `pipe': port index for reading.  */
-#define READ_PORT 0
-
-/* value of `pipe': port index for writing.  */
-#define WRITE_PORT 1
-
-static char *install_error_msg = "installation problem, cannot exec `%s'";
-
-/* pexecute: execute a program.
-
-@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)
-
-Executes a program.
-
-@var{program} and @var{argv} are the arguments to
-@code{execv}/@code{execvp}.
-
-@var{this_pname} is name of the calling program (i.e., @code{argv[0]}).
-
-@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.
-
-@end deftypefn
-
-@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.
-
-@end deftypefn
-
-@undocumented pfinish
-
-   pfinish: finish generation of script
-
-   pfinish is necessary for systems like MPW where a script is generated that
-   runs the requested programs.  */
-
-#ifdef __MSDOS__
-
-/* 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.  */
-
-#include <process.h>
-
-/* 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;
-     int flags;
-{
-  int rc;
-
-  last_pid++;
-  if (last_pid < 0)
-    last_pid = 1;
-
-  if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
-    abort ();
-
-#ifdef __DJGPP__
-  /* ??? What are the possible return values from spawnv?  */
-  rc = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (P_WAIT, program, argv);
-#else
-  char *scmd, *rf;
-  FILE *argfile;
-  int i, el = flags & PEXECUTE_SEARCH ? 4 : 0;
-
-  if (temp_base == 0)
-    temp_base = choose_temp_base ();
-  scmd = (char *) xmalloc (strlen (program) + strlen (temp_base) + 6 + el);
-  rf = scmd + strlen(program) + 2 + el;
-  sprintf (scmd, "%s%s @%s.gp", program,
-	   (flags & PEXECUTE_SEARCH ? ".exe" : ""), temp_base);
-  argfile = fopen (rf, "w");
-  if (argfile == 0)
-    {
-      int errno_save = errno;
-      free (scmd);
-      errno = errno_save;
-      *errmsg_fmt = "cannot open `%s.gp'";
-      *errmsg_arg = temp_base;
-      return -1;
-    }
-
-  for (i=1; argv[i]; i++)
-    {
-      char *cp;
-      for (cp = argv[i]; *cp; cp++)
-	{
-	  if (*cp == '"' || *cp == '\'' || *cp == '\\' || ISSPACE (*cp))
-	    fputc ('\\', argfile);
-	  fputc (*cp, argfile);
-	}
-      fputc ('\n', argfile);
-    }
-  fclose (argfile);
-
-  rc = system (scmd);
-
-  {
-    int errno_save = errno;
-    remove (rf);
-    free (scmd);
-    errno = errno_save;
-  }
-#endif
-
-  if (rc == -1)
-    {
-      *errmsg_fmt = install_error_msg;
-      *errmsg_arg = (char *)program;
-      return -1;
-    }
-
-  /* Tuck the status away for pwait, and return a "pid".  */
-  last_status = rc << 8;
-  return last_pid;
-}
-
-/* Use ECHILD if available, otherwise use EINVAL.  */
-#ifdef ECHILD
-#define PWAIT_ERROR ECHILD
-#else
-#define PWAIT_ERROR EINVAL
-#endif
-
-int
-pwait (pid, status, flags)
-     int pid;
-     int *status;
-     int flags;
-{
-  /* On MSDOS each pexecute must be followed by it's 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?  */
-#ifdef __DJGPP__
-  *status = (last_status >> 8);
-#else
-  *status = last_status;
-#endif
-  last_reaped = last_pid;
-  return last_pid;
-}
-
-#endif /* MSDOS */
-
-#if defined (_WIN32) && ! defined (_UWIN)
-
-#include <process.h>
-
-#ifdef __CYGWIN__
-
-#define fix_argv(argvec) (argvec)
-
-extern int _spawnv ();
-extern int _spawnvp ();
-
-#else /* ! __CYGWIN__ */
-
-/* This is a kludge to get around the Microsoft C spawn functions' propensity
-   to remove the outermost set of double quotes from all arguments.  */
-
-static const char * const *
-fix_argv (argvec)
-     char **argvec;
-{
-  int i;
-
-  for (i = 1; argvec[i] != 0; i++)
-    {
-      int len, j;
-      char *temp, *newtemp;
-
-      temp = argvec[i];
-      len = strlen (temp);
-      for (j = 0; j < len; j++)
-        {
-          if (temp[j] == '"')
-            {
-              newtemp = xmalloc (len + 2);
-              strncpy (newtemp, temp, j);
-              newtemp [j] = '\\';
-              strncpy (&newtemp [j+1], &temp [j], len-j);
-              newtemp [len+1] = 0;
-              temp = newtemp;
-              len++;
-              j++;
-            }
-        }
-
-        argvec[i] = temp;
-      }
-
-  for (i = 0; argvec[i] != 0; i++)
-    {
-      if (strpbrk (argvec[i], " \t"))
-        {
-	  int len, trailing_backslash;
-	  char *temp;
-
-	  len = strlen (argvec[i]);
-	  trailing_backslash = 0;
-
-	  /* There is an added complication when an arg with embedded white
-	     space ends in a backslash (such as in the case of -iprefix arg
-	     passed to cpp). The resulting quoted strings gets misinterpreted
-	     by the command interpreter -- it thinks that the ending quote
-	     is escaped by the trailing backslash and things get confused. 
-	     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] != '\\')
-	    {
-	      trailing_backslash = 1;
-	      ++len;			/* to escape the final backslash. */
-	    }
-
-	  len += 2;			/* and for the enclosing quotes. */
-
-	  temp = xmalloc (len + 1);
-	  temp[0] = '"';
-	  strcpy (temp + 1, argvec[i]);
-	  if (trailing_backslash)
-	    temp[len-2] = '\\';
-	  temp[len-1] = '"';
-	  temp[len] = '\0';
-
-	  argvec[i] = temp;
-	}
-    }
-
-  return (const char * const *) argvec;
-}
-#endif /* __CYGWIN__ */
-
-#include <io.h>
-#include <fcntl.h>
-#include <signal.h>
-
-/* mingw32 headers may not define the following.  */
-
-#ifndef _P_WAIT
-#  define _P_WAIT	0
-#  define _P_NOWAIT	1
-#  define _P_OVERLAY	2
-#  define _P_NOWAITO	3
-#  define _P_DETACH	4
-
-#  define WAIT_CHILD	0
-#  define WAIT_GRANDCHILD	1
-#endif
-
-/* 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;
-     const char *temp_base;
-     char **errmsg_fmt, **errmsg_arg;
-     int flags;
-{
-  int pid;
-  int pdes[2], org_stdin, org_stdout;
-  int input_desc, output_desc;
-  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;
-
-  /* If this is the first process, initialize.  */
-  if (flags & PEXECUTE_FIRST)
-    last_pipe_input = STDIN_FILE_NO;
-
-  input_desc = last_pipe_input;
-
-  /* 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 (_pipe (pdes, 256, O_BINARY) < 0)
-	{
-	  *errmsg_fmt = "pipe";
-	  *errmsg_arg = NULL;
-	  return -1;
-	}
-      output_desc = pdes[WRITE_PORT];
-      last_pipe_input = pdes[READ_PORT];
-    }
-  else
-    {
-      /* Last process.  */
-      output_desc = STDOUT_FILE_NO;
-      last_pipe_input = STDIN_FILE_NO;
-    }
-
-  if (input_desc != STDIN_FILE_NO)
-    {
-      org_stdin = dup (STDIN_FILE_NO);
-      dup2 (input_desc, STDIN_FILE_NO);
-      close (input_desc); 
-    }
-
-  if (output_desc != STDOUT_FILE_NO)
-    {
-      org_stdout = dup (STDOUT_FILE_NO);
-      dup2 (output_desc, STDOUT_FILE_NO);
-      close (output_desc);
-    }
-
-  pid = (flags & PEXECUTE_SEARCH ? _spawnvp : _spawnv)
-    (_P_NOWAIT, program, fix_argv(argv));
-
-  if (input_desc != STDIN_FILE_NO)
-    {
-      dup2 (org_stdin, STDIN_FILE_NO);
-      close (org_stdin);
-    }
-
-  if (output_desc != STDOUT_FILE_NO)
-    {
-      dup2 (org_stdout, STDOUT_FILE_NO);
-      close (org_stdout);
-    }
-
-  if (pid == -1)
-    {
-      *errmsg_fmt = install_error_msg;
-      *errmsg_arg = program;
-      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;
-     int *status;
-     int flags;
-{
-#ifdef __CYGWIN__
-  return wait (status);
-#else
-  int termstat;
-
-  pid = _cwait (&termstat, pid, WAIT_CHILD);
-
-  /* ??? Here's an opportunity to canonicalize the values in STATUS.
-     Needed?  */
-
-  /* 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);
-
-  return pid;
-#endif /* __CYGWIN__ */
-}
-
-#endif /* _WIN32 && ! _UWIN */
-
-#ifdef OS2
-
-/* ??? Does OS2 have process.h?  */
-extern int spawnv ();
-extern int spawnvp ();
-
-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;
-     int flags;
-{
-  int pid;
-
-  if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
-    abort ();
-  /* ??? Presumably 1 == _P_NOWAIT.  */
-  pid = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (1, program, argv);
-  if (pid == -1)
-    {
-      *errmsg_fmt = install_error_msg;
-      *errmsg_arg = program;
-      return -1;
-    }
-  return pid;
-}
-
-int
-pwait (pid, status, flags)
-     int pid;
-     int *status;
-     int flags;
-{
-  /* ??? Here's an opportunity to canonicalize the values in STATUS.
-     Needed?  */
-  int pid = wait (status);
-  return pid;
-}
-
-#endif /* OS2 */
-
-#ifdef MPW
-
-/* MPW pexecute doesn't actually run anything; instead, it writes out
-   script commands that, when run, will do the actual executing.
-
-   For example, in GCC's case, GCC will write out several script commands:
-
-   cpp ...
-   cc1 ...
-   as ...
-   ld ...
-
-   and then exit.  None of the above programs will have run yet.  The task
-   that called GCC will then execute the script and cause cpp,etc. to run.
-   The caller must invoke pfinish before calling exit.  This adds
-   the finishing touches to the generated script.  */
-
-static int first_time = 1;
-
-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;
-     int flags;
-{
-  char tmpprogram[255];
-  char *cp, *tmpname;
-  int i;
-
-  mpwify_filename (program, tmpprogram);
-  if (first_time)
-    {
-      printf ("Set Failed 0\n");
-      first_time = 0;
-    }
-
-  fputs ("If {Failed} == 0\n", stdout);
-  /* If being verbose, output a copy of the command.  It should be
-     accurate enough and escaped enough to be "clickable".  */
-  if (flags & PEXECUTE_VERBOSE)
-    {
-      fputs ("\tEcho ", stdout);
-      fputc ('\'', stdout);
-      fputs (tmpprogram, stdout);
-      fputc ('\'', stdout);
-      fputc (' ', stdout);
-      for (i=1; argv[i]; i++)
-	{
-	  fputc ('\'', stdout);
-	  /* See if we have an argument that needs fixing.  */
-	  if (strchr(argv[i], '/'))
-	    {
-	      tmpname = (char *) xmalloc (256);
-	      mpwify_filename (argv[i], tmpname);
-	      argv[i] = tmpname;
-	    }
-	  for (cp = argv[i]; *cp; cp++)
-	    {
-	      /* Write an Option-d escape char in front of special chars.  */
-	      if (strchr("'+", *cp))
-		fputc ('\266', stdout);
-	      fputc (*cp, stdout);
-	    }
-	  fputc ('\'', stdout);
-	  fputc (' ', stdout);
-	}
-      fputs ("\n", stdout);
-    }
-  fputs ("\t", stdout);
-  fputs (tmpprogram, stdout);
-  fputc (' ', stdout);
-
-  for (i=1; argv[i]; i++)
-    {
-      /* See if we have an argument that needs fixing.  */
-      if (strchr(argv[i], '/'))
-	{
-	  tmpname = (char *) xmalloc (256);
-	  mpwify_filename (argv[i], tmpname);
-	  argv[i] = tmpname;
-	}
-      if (strchr (argv[i], ' '))
-	fputc ('\'', stdout);
-      for (cp = argv[i]; *cp; cp++)
-	{
-	  /* Write an Option-d escape char in front of special chars.  */
-	  if (strchr("'+", *cp))
-	    fputc ('\266', stdout);
-	  fputc (*cp, stdout);
-	}
-      if (strchr (argv[i], ' '))
-	fputc ('\'', stdout);
-      fputc (' ', stdout);
-    }
-
-  fputs ("\n", stdout);
-
-  /* Output commands that arrange to clean up and exit if a failure occurs.
-     We have to be careful to collect the status from the program that was
-     run, rather than some other script command.  Also, we don't exit
-     immediately, since necessary cleanups are at the end of the script.  */
-  fputs ("\tSet TmpStatus {Status}\n", stdout);
-  fputs ("\tIf {TmpStatus} != 0\n", stdout);
-  fputs ("\t\tSet Failed {TmpStatus}\n", stdout);
-  fputs ("\tEnd\n", stdout);
-  fputs ("End\n", stdout);
-
-  /* We're just composing a script, can't fail here.  */
-  return 0;
-}
-
-int
-pwait (pid, status, flags)
-     int pid;
-     int *status;
-     int flags;
-{
-  *status = 0;
-  return 0;
-}
-
-/* Write out commands that will exit with the correct error code
-   if something in the script failed.  */
-
-void
-pfinish ()
-{
-  printf ("\tExit \"{Failed}\"\n");
-}
-
-#endif /* MPW */
-
-/* include for Unix-like environments but not for Dos-like environments */
-#if ! defined (__MSDOS__) && ! defined (OS2) && ! defined (MPW) \
-    && ! (defined (_WIN32) && ! defined (_UWIN))
-
-extern int execv ();
-extern int execvp ();
-
-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 ATTRIBUTE_UNUSED;
-     char **errmsg_fmt, **errmsg_arg;
-     int flags;
-{
-  int (*func)() = (flags & PEXECUTE_SEARCH ? execvp : execv);
-  int pid;
-  int pdes[2];
-  int input_desc, output_desc;
-  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;
-
-  /* If this is the first process, initialize.  */
-  if (flags & PEXECUTE_FIRST)
-    last_pipe_input = STDIN_FILE_NO;
-
-  input_desc = last_pipe_input;
-
-  /* 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 (pipe (pdes) < 0)
-	{
-	  *errmsg_fmt = "pipe";
-	  *errmsg_arg = NULL;
-	  return -1;
-	}
-      output_desc = pdes[WRITE_PORT];
-      last_pipe_input = pdes[READ_PORT];
-    }
-  else
-    {
-      /* Last process.  */
-      output_desc = STDOUT_FILE_NO;
-      last_pipe_input = STDIN_FILE_NO;
-    }
-
-  /* Fork a subprocess; wait and retry if it fails.  */
-  sleep_interval = 1;
-  pid = -1;
-  for (retries = 0; retries < 4; retries++)
-    {
-      pid = fork ();
-      if (pid >= 0)
-	break;
-      sleep (sleep_interval);
-      sleep_interval *= 2;
-    }
-
-  switch (pid)
-    {
-    case -1:
-      *errmsg_fmt = "fork";
-      *errmsg_arg = NULL;
-      return -1;
-
-    case 0: /* child */
-      /* Move the input and output pipes into place, if necessary.  */
-      if (input_desc != STDIN_FILE_NO)
-	{
-	  close (STDIN_FILE_NO);
-	  dup (input_desc);
-	  close (input_desc);
-	}
-      if (output_desc != STDOUT_FILE_NO)
-	{
-	  close (STDOUT_FILE_NO);
-	  dup (output_desc);
-	  close (output_desc);
-	}
-
-      /* Close the parent's descs that aren't wanted here.  */
-      if (last_pipe_input != STDIN_FILE_NO)
-	close (last_pipe_input);
-
-      /* Exec the program.  */
-      (*func) (program, argv);
-
-      fprintf (stderr, "%s: ", this_pname);
-      fprintf (stderr, install_error_msg, program);
-      fprintf (stderr, ": %s\n", xstrerror (errno));
-      exit (-1);
-      /* NOTREACHED */
-      return 0;
-
-    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);
-
-      /* Return child's process number.  */
-      return pid;
-    }
-}
-
-int
-pwait (pid, status, flags)
-     int pid;
-     int *status;
-     int flags ATTRIBUTE_UNUSED;
-{
-  /* ??? Here's an opportunity to canonicalize the values in STATUS.
-     Needed?  */
-#ifdef VMS
-  pid = waitpid (-1, status, 0);
-#else
-  pid = wait (status);
-#endif
-  return pid;
-}
-
-#endif /* ! __MSDOS__ && ! OS2 && ! MPW && ! (_WIN32 && ! _UWIN) */



More information about the Binutils mailing list