OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / libiberty / pexecute.c
index fbbea40..347c4db 100644 (file)
@@ -1,6 +1,6 @@
 /* Utilities to execute a program in a subprocess (possibly linked by pipes
    with other subprocesses), and wait for it.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   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
@@ -23,24 +23,30 @@ Boston, MA 02111-1307, USA.  */
 /* This file lives in at least two places: libiberty and gcc.
    Don't change one without the other.  */
 
-#ifdef IN_GCC
+#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
 
-#ifdef IN_GCC
-#include "gansidecl.h"
-/* ??? Need to find a suitable header file.  */
-#define PEXECUTE_FIRST   1
-#define PEXECUTE_LAST    2
-#define PEXECUTE_ONE     (PEXECUTE_FIRST + PEXECUTE_LAST)
-#define PEXECUTE_SEARCH  4
-#define PEXECUTE_VERBOSE 8
-#else
 #include "libiberty.h"
-#endif
+#include "safe-ctype.h"
 
 /* stdin file number.  */
 #define STDIN_FILE_NO 0
@@ -58,53 +64,66 @@ static char *install_error_msg = "installation problem, cannot exec `%s'";
 
 /* pexecute: execute a program.
 
-   PROGRAM and ARGV are the arguments to execv/execvp.
+@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}.
 
-   THIS_PNAME is name of the calling program (i.e. argv[0]).
+(@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.
 
-   TEMP_BASE is the path name, sans suffix, of a temporary file to use
-   if needed.  This is currently only needed for MSDOS ports that don't use
-   GO32 (do any still exist?).  Ports that don't need it can pass NULL.
+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.
 
-   (FLAGS & PEXECUTE_SEARCH) is non-zero if $PATH should be searched
-   (??? It's not clear that GCC passes this flag correctly).
-   (FLAGS & PEXECUTE_FIRST) is nonzero for the first process in chain.
-   (FLAGS & PEXECUTE_FIRST) is nonzero for the last process in chain.
-   FIRST_LAST 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 @code{WEXITSTATUS} on systems like MS-DOS where we
+@code{spawn} and wait for the child here.
 
-   The result is the pid on systems like Unix where we fork/exec and on systems
-   like WIN32 and OS2 where we use spawn.  It is up to the caller to wait for
-   the child.
+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.
 
-   The result is the WEXITSTATUS on systems like MSDOS where we spawn and wait
-   for the child here.
+@end deftypefn
 
-   Upon failure, ERRMSG_FMT and ERRMSG_ARG are set to the text of the error
-   message with an optional argument (if not needed, ERRMSG_ARG is set to
-   NULL), and -1 is returned.  `errno' is available to the caller to use.
+@deftypefn Extension int pwait (int @var{pid}, int *@var{status}, int @var{flags})
 
-   pwait: cover function for wait.
+Waits for a program started by @code{pexecute} to finish.
 
-   PID is the process id of the task to wait for.
-   STATUS is the `status' argument to wait.
-   FLAGS is currently unused (allows future enhancement without breaking
-   upward compatibility).  Pass 0 for now.
+@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 (errno says why).
+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, PID is
-   ignored.  On systems like MSDOS that don't really multitask pwait
-   is just a mechanism to provide a consistent interface for the caller.
+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.
-*/
+   runs the requested programs.  */
 
 #ifdef __MSDOS__
 
@@ -138,14 +157,16 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
   if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
     abort ();
 
-#ifdef __GO32__
+#ifdef __DJGPP__
   /* ??? What are the possible return values from spawnv?  */
-  rc = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (1, program, argv);
+  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,
@@ -166,7 +187,7 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
       char *cp;
       for (cp = argv[i]; *cp; cp++)
        {
-         if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
+         if (*cp == '"' || *cp == '\'' || *cp == '\\' || ISSPACE (*cp))
            fputc ('\\', argfile);
          fputc (*cp, argfile);
        }
@@ -187,7 +208,7 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
   if (rc == -1)
     {
       *errmsg_fmt = install_error_msg;
-      *errmsg_arg = program;
+      *errmsg_arg = (char *)program;
       return -1;
     }
 
@@ -196,6 +217,13 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
   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;
@@ -207,71 +235,39 @@ pwait (pid, status, flags)
       /* Called twice for the same child?  */
       || pid == last_reaped)
     {
-      /* ??? ECHILD would be a better choice.  Can we use it here?  */
-      errno = EINVAL;
+      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)
+#if defined (_WIN32) && ! defined (_UWIN)
 
 #include <process.h>
 
-#ifdef __CYGWIN32__
+#ifdef __CYGWIN__
 
 #define fix_argv(argvec) (argvec)
 
 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 ();
-  pid = (flags & PEXECUTE_SEARCH ? _spawnvp : _spawnv)
-    (_P_NOWAIT, program, fix_argv(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?  */
-  return cwait (status, pid, WAIT_CHILD);
-}
-
-#else /* ! __CYGWIN32__ */
+#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.  */
 
-const char * const *
+static const char * const *
 fix_argv (argvec)
      char **argvec;
 {
@@ -302,8 +298,48 @@ fix_argv (argvec)
         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>
@@ -420,6 +456,9 @@ pwait (pid, status, flags)
      int *status;
      int flags;
 {
+#ifdef __CYGWIN__
+  return wait (status);
+#else
   int termstat;
 
   pid = _cwait (&termstat, pid, WAIT_CHILD);
@@ -437,11 +476,10 @@ pwait (pid, status, flags)
     *status = (((termstat) & 0xff) << 8);
 
   return pid;
+#endif /* __CYGWIN__ */
 }
 
-#endif /* ! defined (__CYGWIN32__) */
-
-#endif /* _WIN32 */
+#endif /* _WIN32 && ! _UWIN */
 
 #ifdef OS2
 
@@ -509,7 +547,7 @@ static int first_time = 1;
 int
 pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
      const char *program;
-     char **argv;
+     char * const *argv;
      const char *this_pname;
      const char *temp_base;
      char **errmsg_fmt, **errmsg_arg;
@@ -538,14 +576,18 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
       fputc (' ', stdout);
       for (i=1; argv[i]; i++)
        {
-         /* We have to quote every arg, so that when the echo is
-            executed, the quotes are stripped and the original arg
-            is left. */
          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 esc char in front of special chars.  */
-             if (strchr ("\"'+", *cp))
+             /* Write an Option-d escape char in front of special chars.  */
+             if (strchr("'+", *cp))
                fputc ('\266', stdout);
              fputc (*cp, stdout);
            }
@@ -560,15 +602,20 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
 
   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 esc char in front of special chars.  */
-         if (strchr ("\"'+", *cp))
-           {
-             fputc ('\266', stdout);
-           }
+         /* Write an Option-d escape char in front of special chars.  */
+         if (strchr("'+", *cp))
+           fputc ('\266', stdout);
          fputc (*cp, stdout);
        }
       if (strchr (argv[i], ' '))
@@ -615,16 +662,7 @@ pfinish ()
 
 /* include for Unix-like environments but not for Dos-like environments */
 #if ! defined (__MSDOS__) && ! defined (OS2) && ! defined (MPW) \
-    && ! defined (_WIN32)
-
-#ifdef VMS
-#define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \
-               lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1)
-#else
-#ifdef USG
-#define vfork fork
-#endif
-#endif
+    && ! (defined (_WIN32) && ! defined (_UWIN))
 
 extern int execv ();
 extern int execvp ();
@@ -634,7 +672,7 @@ 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;
+     const char *temp_base ATTRIBUTE_UNUSED;
      char **errmsg_fmt, **errmsg_arg;
      int flags;
 {
@@ -676,9 +714,10 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
 
   /* Fork a subprocess; wait and retry if it fails.  */
   sleep_interval = 1;
+  pid = -1;
   for (retries = 0; retries < 4; retries++)
     {
-      pid = vfork ();
+      pid = fork ();
       if (pid >= 0)
        break;
       sleep (sleep_interval);
@@ -688,15 +727,9 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
   switch (pid)
     {
     case -1:
-      {
-#ifdef vfork
-       *errmsg_fmt = "fork";
-#else
-       *errmsg_fmt = "vfork";
-#endif
-       *errmsg_arg = NULL;
-       return -1;
-      }
+      *errmsg_fmt = "fork";
+      *errmsg_arg = NULL;
+      return -1;
 
     case 0: /* child */
       /* Move the input and output pipes into place, if necessary.  */
@@ -720,14 +753,9 @@ pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
       /* Exec the program.  */
       (*func) (program, argv);
 
-      /* Note: Calling fprintf and exit here doesn't seem right for vfork.  */
       fprintf (stderr, "%s: ", this_pname);
       fprintf (stderr, install_error_msg, program);
-#ifdef IN_GCC
-      fprintf (stderr, ": %s\n", my_strerror (errno));
-#else
       fprintf (stderr, ": %s\n", xstrerror (errno));
-#endif
       exit (-1);
       /* NOTREACHED */
       return 0;
@@ -749,7 +777,7 @@ int
 pwait (pid, status, flags)
      int pid;
      int *status;
-     int flags;
+     int flags ATTRIBUTE_UNUSED;
 {
   /* ??? Here's an opportunity to canonicalize the values in STATUS.
      Needed?  */
@@ -761,4 +789,4 @@ pwait (pid, status, flags)
   return pid;
 }
 
-#endif /* ! __MSDOS__ && ! OS2 && ! MPW && ! _WIN32 */
+#endif /* ! __MSDOS__ && ! OS2 && ! MPW && ! (_WIN32 && ! _UWIN) */