bug-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

OS/2 patches (3)


From: Andreas Buening
Subject: OS/2 patches (3)
Date: Sun, 23 Jun 2002 01:18:31 +0200

Hello!

I've put the CLOSE_ON_EXEC definition from job.c into job.h
because I needed it in main.c. I've also added return type int
to the declaration of exec_command() and child_execute_job()

-------------------------------------------
--- old/make-CVS/job.h  Mon Aug 23 22:15:22 1999
+++ gnu/make-3.79.2a1/job.h     Sat Jun 22 17:13:40 2002
@@ -20,6 +20,24 @@
 #ifndef SEEN_JOB_H
 #define SEEN_JOB_H
 
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#else
+# include <sys/file.h>
+#endif
+
+
+/* How to set close-on-exec for a file descriptor.  */
+
+#if !defined F_SETFD
+# define CLOSE_ON_EXEC(_d)
+#else
+# ifndef FD_CLOEXEC
+#  define FD_CLOEXEC 1
+# endif
+# define CLOSE_ON_EXEC(_d) (void) fcntl ((_d), F_SETFD, FD_CLOEXEC)
+#endif
+
 /* Structure describing a running or dead child process.  */
 
 struct child
@@ -58,12 +76,20 @@
 #ifdef VMS
 extern int child_execute_job PARAMS ((char *argv, struct child *child));
 #else
+# ifdef __EMX__
+extern int child_execute_job PARAMS ((int stdin_fd, int stdout_fd, char 
**argv, char **envp));
+# else
 extern void child_execute_job PARAMS ((int stdin_fd, int stdout_fd, char 
**argv, char **envp));
+# endif /* !__EMX__ */
 #endif
 #ifdef _AMIGA
 extern void exec_command PARAMS ((char **argv));
 #else
+# ifdef __EMX__
+extern int exec_command PARAMS ((char **argv, char **envp));
+# else
 extern void exec_command PARAMS ((char **argv, char **envp));
+# endif /* !__EMX__ */
 #endif
 
 extern unsigned int job_slots_used;
-------------------------------------------


Due to principle differences in the system implementation
make has to use spawn() instead of fork()/exec().
exec() ends the current process and starts a new one with
a new pid so that make cannot take care of its child processes.
This implies that exec_command() and child_execute_job()
return the pid of the child process. Additionally it's
necessary to take care of all the file handles, which
to CLOSE_ON_EXEC before starting a child and which one
to "keep open on exec" after the child has been started.
Unfortunately, the code looks sometimes odd.

-------------------------------------------
--- old/make-CVS/function.c     Fri May 10 03:15:08 2002
+++ gnu/make-3.79.2a1/function.c        Sat Jun 22 17:16:26 2002
@@ -1393,18 +1393,30 @@
       perror_with_name (error_prefix, "pipe");
       return o;
     }
-# else
+# else /* !__MSDOS__ */
   if (pipe (pipedes) < 0)
     {
       perror_with_name (error_prefix, "pipe");
       return o;
     }
 
+#  ifdef __EMX__
+  /* close some handles that are unnecessary for the child process */
+  CLOSE_ON_EXEC(pipedes[1]);
+  CLOSE_ON_EXEC(pipedes[0]);
+  /* Never use fork()/exec() here! Use spawn() instead in exec_command() */
+  pid = child_execute_job (0, pipedes[1], command_argv, envp);
+  if (pid < 0)
+    perror_with_name (error_prefix, "spawn");
+
+#  else /* ! __EMX__ */
+
   pid = vfork ();
   if (pid < 0)
     perror_with_name (error_prefix, "fork");
   else if (pid == 0)
     child_execute_job (0, pipedes[1], command_argv, envp);
+#  endif /* __EMX__ */
   else
 # endif /* ! __MSDOS__ */
 
@@ -1457,8 +1469,8 @@
       (void) close (pipedes[0]);
 #endif
 
-      /* Loop until child_handler sets shell_function_completed
-        to the status of our child shell.  */
+      /* Loop until child_handler or reap_children() sets
+         shell_function_completed to the status of our child shell.  */
       while (shell_function_completed == 0)
        reap_children (1, 0);
-------------------------------------------


According to my Posix docu setvbuf(FILE*, char*, int, size_t)
is the default.
A SIGCHLD handler on OS/2 must call wait() itself otherwise
the signal is immediatly called again and the program hangs.
Therefore child_handler() must never be used for EMX.

-------------------------------------------
--- old/make-CVS/main.c Fri May 10 03:15:08 2002
+++ gnu/make-3.79.2a1/main.c    Sat Jun 22 23:42:28 2002
@@ -36,6 +36,10 @@
 #include <windows.h>
 #include "pathstuff.h"
 #endif
+#ifdef __EMX__
+# include<sys/types.h>
+# include<sys/wait.h>
+#endif
 #if defined(MAKE_JOBSERVER) && defined(HAVE_FCNTL_H)
 # include <fcntl.h>
 #endif
@@ -811,6 +815,9 @@
   char **p;
   struct dep *read_makefiles;
   PATH_VAR (current_directory);
+
+  initialize_main(&argc, &argv);
+
 #ifdef WINDOWS32
   char *unix_path = NULL;
   char *windows32_path = NULL;
@@ -905,7 +912,7 @@
   /* Make sure stdout is line-buffered.  */
 
 #ifdef HAVE_SETVBUF
-# ifdef SETVBUF_REVERSED
+# ifndef SETVBUF_REVERSED
   setvbuf (stdout, (char *) 0, _IOLBF, BUFSIZ);
 # else /* setvbuf not reversed.  */
   /* Some buggy systems lose if we pass 0 instead of allocating ourselves.  */
@@ -928,7 +935,7 @@
 #else
       program = strrchr (argv[0], '/');
 #endif
-#ifdef __MSDOS__
+#if defined (__MSDOS__) || defined (__EMX__)
       if (program == 0)
        program = strrchr (argv[0], '\\');
       else
@@ -1106,7 +1113,7 @@
       strneq(argv[0], "//", 2))
     argv[0] = xstrdup(w32ify(argv[0],1));
 #else /* WINDOWS32 */
-#ifdef __MSDOS__
+#if defined (__MSDOS__) || defined (__EMX__)
   if (strchr (argv[0], '\\'))
     {
       char *p;
@@ -1295,7 +1302,7 @@
 #define DEFAULT_TMPFILE     "GmXXXXXX"
 
            if (((tmpdir = getenv ("TMPDIR")) == NULL || *tmpdir == '\0')
-#if defined __MSDOS__ || defined(WINDOWS32)
+#if defined __MSDOS__ || defined(WINDOWS32) || defined(__EMX__)
                 /* These are also used commonly on these platforms.  */
                 && ((tmpdir = getenv ("TEMP")) == NULL || *tmpdir == '\0')
                 && ((tmpdir = getenv ("TMP")) == NULL || *tmpdir == '\0')
@@ -1307,7 +1314,7 @@
                                         + sizeof (DEFAULT_TMPFILE) + 1);
            strcpy (template, tmpdir);
 
-#if defined __MSDOS__ || defined(WINDOWS32)
+#if defined __MSDOS__ || defined(WINDOWS32) || defined(__EMX__)
            if (strchr ("/\\", template[strlen (template) - 1]) == NULL)
              strcat (template, "/");
 #else
@@ -1359,15 +1366,18 @@
      jobserver pipe in job.c if we're waiting for a token.
 
      If none of these are true, we don't need a signal handler at all.  */
+# ifndef __EMX__
+  /* Do NEVER use a SIGCHLD handler for EMX unless the handler calls wait() 
itself! */
   {
     extern RETSIGTYPE child_handler PARAMS ((int sig));
-# if defined SIGCHLD
+#  if defined SIGCHLD
     bsd_signal (SIGCHLD, child_handler);
-# endif
-# if defined SIGCLD && SIGCLD != SIGCHLD
+#  endif
+#  if defined SIGCLD && SIGCLD != SIGCHLD
     bsd_signal (SIGCLD, child_handler);
-# endif
+#  endif
   }
+# endif /* ! __EMX__ */
 #endif
 
   /* Let the user send us SIGUSR1 to toggle the -d flag during the run.  */
@@ -1418,7 +1428,7 @@
   }
 #endif /* WINDOWS32 */
 
-#ifdef __MSDOS__
+#if defined (__MSDOS__) || defined (__EMX__)
   /* We need to know what kind of shell we will be using.  */
   {
     extern int _is_unixy_shell (const char *_path);
@@ -1438,7 +1448,7 @@
          default_shell = shell_path;
       }
   }
-#endif /* __MSDOS__ */
+#endif /* __MSDOS__ || __EMX__ */
 
   /* Decode switches again, in case the variables were set by the makefile.  */
   decode_env_switches ("MAKEFLAGS", 9);
@@ -1446,8 +1456,12 @@
   decode_env_switches ("MFLAGS", 6);
 #endif
 
-#ifdef __MSDOS__
-  if (job_slots != 1)
+#if defined (__MSDOS__) || defined (__EMX__)
+  if (job_slots != 1
+# ifdef __EMX__
+      && _osmode != OS2_MODE /* turn off -j if we are in DOS mode */
+# endif
+     )
     {
       error (NILF,
              _("Parallel jobs (-j) are not supported on this platform."));
@@ -1849,12 +1863,34 @@
           if (job_rfd >= 0)
             close (job_rfd);
 
-#ifndef _AMIGA
+#if !defined(_AMIGA) && !defined(__EMX__)
          exec_command (nargv, environ);
 #else
+# ifdef __EMX__
+         { 
+           /* It is not possible to use execve() here because this
+              would cause the parent process to be terminated with
+              exit code 0 before the child process has been terminated.
+              Therefore it may be the best solution simply to spawn the
+              child process including all file handles and to wait for its
+              termination. */
+           int pid;
+           int status;
+           pid = child_execute_job(0, 1, nargv, environ);
+
+           /* is this loop really necessary? */
+           do {
+             pid = wait(&status);
+           } while(pid <= 0);
+           /* use the exit code of the child process */
+           exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
+         }
+# endif /* __EMX__ */
+# ifdef _AMIGA
          exec_command (nargv);
          exit (0);
-#endif
+# endif /* _AMIGA */
+#endif /* !_AMIGA && !__EMX__ */
          /* NOTREACHED */
 
        default:
-------------------------------------------
 

job.c contains the really critical code.
The only code I haven't written myself is the list of
internal commands (sh_cmds_os2). I just trusted the porter
of the former make port for OS/2 that this list is complete.
That port has never been submitted to gnu.org. Everything else
is my own work (the former make port is broken in the way it
handles shells so I had to start from scratch).
However, job.c is huge, I've put a lot of comments into the code.
Please ask if something is unclear.

-------------------------------------------
--- old/make-CVS/job.c  Sun Nov 18 18:38:02 2001
+++ gnu/make-3.79.2a1/job.c     Sat Jun 22 23:43:56 2002
@@ -51,7 +51,11 @@
 #    include <descrip.h>
 char default_shell[] = "";
 #   else
+#    ifdef __EMX__
+char *default_shell = "/bin/sh";
+#    else
 char default_shell[] = "/bin/sh";
+#    endif /* __EMX__ */
 #   endif /* VMS */
 #  endif /* __MSDOS__ */
 int batch_mode_shell = 0;
@@ -91,10 +95,8 @@
 # include "pathstuff.h"
 #endif /* WINDOWS32 */
 
-#ifdef HAVE_FCNTL_H
-# include <fcntl.h>
-#else
-# include <sys/file.h>
+#ifdef __EMX__
+# include<process.h>
 #endif
 
 #if defined (HAVE_SYS_WAIT_H) || defined (HAVE_UNION_WAIT)
@@ -157,17 +159,6 @@
 
 #endif /* Don't have `union wait'.  */
 
-/* How to set close-on-exec for a file descriptor.  */
-
-#if !defined F_SETFD
-# define CLOSE_ON_EXEC(_d)
-#else
-# ifndef FD_CLOEXEC
-#  define FD_CLOEXEC 1
-# endif
-# define CLOSE_ON_EXEC(_d) (void) fcntl ((_d), F_SETFD, FD_CLOEXEC)
-#endif
-
 #ifdef VMS
 static int vms_jobsefnmask = 0;
 #endif /* !VMS */
@@ -234,6 +225,51 @@
 }
 #endif /* WINDOWS32 */
 
+#ifdef __EMX__
+/* returns whether path is assumed to be a unix like shell. */
+int
+_is_unixy_shell(const char *path)
+{
+  /* list of non unix shells */
+  const char *known_os2shells[] = {
+    "cmd.exe",
+    "cmd",
+    "4os2.exe",
+    "4os2",
+    "4dos.exe",
+    "4dos",
+    "command.com",
+    "command",
+    NULL
+  };
+
+  /* find the rightmost '/' or '\\' */
+  const char *name = strrchr(path, '/');
+  const char *p = strrchr(path, '\\');
+  unsigned i;
+
+  if (name && p)    /* take the max */
+    name = (name > p) ? name : p;
+  else if (p)       /* name must be 0 */
+    name = p;
+  else if (!name)   /* name and p must be 0 */
+    name = path;
+
+  if (*name == '/' || *name == '\\') name++;
+
+  i = 0;
+  while(known_os2shells[i] != NULL) {
+    if (stricmp(name, known_os2shells[i]) == 0) /* strcasecmp() */
+      return 0; /* not a unix shell */
+    i++;
+  }
+
+  /* in doubt assume a unix like shell */
+  return 1;
+}
+#endif /* __EMX__ */
+
+
 /* Write an error message describing the exit status given in
    EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME.
    Append "(ignored)" if IGNORED is nonzero.  */
@@ -389,12 +425,14 @@
 
 static unsigned int dead_children = 0;
 
+#ifndef __EMX__
+/* Never use this SIGCHLD handler for EMX! */
+
 RETSIGTYPE
 child_handler (sig)
      int sig;
 {
   ++dead_children;
-
   if (job_rfd >= 0)
     {
       close (job_rfd);
@@ -403,6 +441,7 @@
 
   DB (DB_JOBS, (_("Got a SIGCHLD; %u unreaped children.\n"), dead_children));
 }
+#endif
 
 
 extern int shell_function_pid, shell_function_completed;
@@ -534,6 +573,18 @@
              exit_code = WEXITSTATUS (status);
              exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0;
              coredump = WCOREDUMP (status);
+
+#ifdef __EMX__
+             /* the SIGCHLD handler must not be used on OS/2 because
+                unlike on UNIX systems it had to call wait() itself
+                therefore job_rfd has to be closed here */
+             if (job_rfd >= 0)
+               {
+                 close (job_rfd);
+                 job_rfd = -1;
+               }
+#endif __EMX__
+
            }
          else
            {
@@ -840,6 +891,11 @@
 #endif
 
 #ifdef MAKE_JOBSERVER
+# ifdef __EMX__
+/* Never install the SIGCHLD handler for EMX!!! */
+#  define set_child_handler_action_flags(x)
+# else
+
 /* Set the child handler action flags to FLAGS.  */
 static void
 set_child_handler_action_flags (flags)
@@ -849,13 +905,14 @@
   bzero ((char *) &sa, sizeof sa);
   sa.sa_handler = child_handler;
   sa.sa_flags = flags;
-#if defined SIGCHLD
+#  if defined SIGCHLD
   sigaction (SIGCHLD, &sa, NULL);
-#endif
-#if defined SIGCLD && SIGCLD != SIGCHLD
+#  endif
+#  if defined SIGCLD && SIGCLD != SIGCHLD
   sigaction (SIGCLD, &sa, NULL);
-#endif
+#  endif
 }
+# endif /* !__EMX__ */
 #endif
 
 
@@ -1006,7 +1063,7 @@
 
 #if !defined(VMS) && !defined(_AMIGA)
   if (
-#ifdef __MSDOS__
+#if defined (__MSDOS__) || defined (__EMX__)
       unixy_shell      /* the test is complicated and we already did it */
 #else
       (argv[0] && !strcmp (argv[0], "/bin/sh"))
@@ -1129,6 +1186,40 @@
 #else
 
       parent_environ = environ;
+
+# ifdef __EMX__
+      /* If we aren't running a recursive command and we have a jobserver
+         pipe, close it before exec'ing.  */
+      if (!(flags & COMMANDS_RECURSE) && job_fds[0] >= 0)
+       {
+         CLOSE_ON_EXEC (job_fds[0]);
+         CLOSE_ON_EXEC (job_fds[1]);
+       }
+      if (job_rfd >= 0)
+       CLOSE_ON_EXEC (job_rfd);
+    
+      /* Never use fork()/exec() here! Use spawn() instead in exec_command() */
+      child->pid = child_execute_job (child->good_stdin ? 0 : bad_stdin, 1,
+                                      argv, child->environment);
+      if (child->pid < 0)
+       {
+         /* spawn failed!  */
+         unblock_sigs ();
+         perror_with_name ("spawn", "");
+         goto error;
+       }
+
+      /* undo CLOSE_ON_EXEC() after the child process has been started */
+      if (!(flags & COMMANDS_RECURSE) && job_fds[0] >= 0)
+       {
+         fcntl(job_fds[0], F_SETFD, 0);
+         fcntl(job_fds[1], F_SETFD, 0);
+       }
+      if (job_rfd >= 0)
+       fcntl(job_rfd, F_SETFD, 0);
+
+#else /* ! __EMX__ */
+
       child->pid = vfork ();
       environ = parent_environ;        /* Restore value child may have 
clobbered.  */
       if (child->pid == 0)
@@ -1156,6 +1247,7 @@
          perror_with_name ("vfork", "");
          goto error;
        }
+# endif /* !__EMX__ */
 #endif /* !VMS */
     }
 
@@ -2225,15 +2317,62 @@
    STDIN_FD and STDOUT_FD are used as the process's stdin and stdout; ENVP is
    the environment of the new program.  This function does not return.  */
 
+/* EMX:
+   Start a child process. This function returns the new pid. */
+# ifdef __EMX__
+int
+# else
 void
+# endif
 child_execute_job (stdin_fd, stdout_fd, argv, envp)
      int stdin_fd, stdout_fd;
      char **argv, **envp;
 {
+# ifdef __EMX__
+  int pid;
+  /* stdin_fd == 0 means: nothing to do for stdin; 
+     stdout_fd == 1 means: nothing to do for stdout */
+  /* duplicate stdin if necessary */
+  int save_stdin = (stdin_fd != 0) ? dup (0) : 0; 
+  /* duplicate stdout if necessary */
+  int save_stdout = (stdout_fd != 1) ? dup (1): 1; 
+
+  if (save_stdin < 0) /* < 0 only if dup() failed */
+    fatal (NILF, _("could not duplicate stdin\n")); /* new gettext message 
required! */
+  else
+    if (save_stdin != 0)
+      /* close an unnecessary file handle for the child */
+      CLOSE_ON_EXEC (save_stdin);
+
+  if (save_stdout < 0) /* < 0 only if dup() failed */
+    fatal (NILF, _("could not duplicate stdout\n")); /* new gettext message 
required! */
+  else
+    if (save_stdout != 1)
+      /* close an unnecessary file handle for the child */
+      CLOSE_ON_EXEC (save_stdout);
+# endif
+
+  /* connect the pipe output to stdin of the child process */
   if (stdin_fd != 0)
     (void) dup2 (stdin_fd, 0);
+
+  /* connect the pipe input to stdout of the child process */
   if (stdout_fd != 1)
     (void) dup2 (stdout_fd, 1);
+
+# ifdef __EMX__
+  /* stdin_fd and stdout_fd must be closed on exit because we are
+     still in the parent process */
+  if (stdin_fd != 0) 
+    CLOSE_ON_EXEC (stdin_fd);
+  if (stdout_fd != 1)
+    CLOSE_ON_EXEC (stdout_fd);
+
+  /* Run the command.  */
+  pid = exec_command (argv, envp);
+
+# else /* ! __EMX__ */
+
   if (stdin_fd != 0)
     (void) close (stdin_fd);
   if (stdout_fd != 1)
@@ -2241,6 +2380,21 @@
 
   /* Run the command.  */
   exec_command (argv, envp);
+# endif /* !__EMX__ */
+
+# ifdef __EMX__
+  /* restore stdin of the parent process */
+  if (stdin_fd != 0)
+    if (dup2 (save_stdin, 0) != 0)
+      fatal (NILF, _("restoring of stdin failed\n")); /* new gettext message 
required! */
+
+  /* restore stdout of the parent process */
+  if (stdout_fd != 1)
+    if (dup2 (save_stdout, 1) != 1)
+      fatal (NILF, _("restoring of stdout failed\n")); /* new gettext message 
required! */
+
+  return pid;
+# endif /* __EMX__ */
 }
 #endif /* !AMIGA && !__MSDOS__ */
 #endif /* !VMS */
@@ -2249,8 +2403,12 @@
 #ifndef _AMIGA
 /* Replace the current process with one running the command in ARGV,
    with environment ENVP.  This function does not return.  */
-
+/* EMX: This function returns the pid of the child process */
+# ifdef __EMX__
+int
+# else
 void
+# endif
 exec_command (argv, envp)
      char **argv, **envp;
 {
@@ -2319,12 +2477,27 @@
 
 #else  /* !WINDOWS32 */
 
+# ifdef __EMX__
+  int pid;
+# endif
+
   /* Be the user, permanently.  */
   child_access ();
 
+# ifdef __EMX__
+  /* Run the program.  */
+  pid = spawnvpe(P_NOWAIT, argv[0], argv, envp);
+
+  /* the file might have a strange shell extension */
+  if (pid < 0 && errno == ENOENT) errno = ENOEXEC;
+
+  if (pid < 0)
+# else
+
   /* Run the program.  */
   environ = envp;
   execvp (argv[0], argv);
+# endif /* !__EMX__ */
 
   switch (errno)
     {
@@ -2339,7 +2512,16 @@
        char **new_argv;
        int argc;
 
+# ifdef __EMX__
+        /* do not use $SHELL */
+       struct variable *p = lookup_variable("SHELL", 5);
+
+       if (p) 
+         shell = p->value;
+# else
+
        shell = getenv ("SHELL");
+# endif /* !__EMX__ */
        if (shell == 0)
          shell = default_shell;
 
@@ -2356,20 +2538,43 @@
            --argc;
          }
 
+# ifdef __EMX__
+       pid = spawnvpe(P_NOWAIT, shell, new_argv, envp);
+       if (pid < 0) { /* note: opening brace! */
+# else
        execvp (shell, new_argv);
+# endif
        if (errno == ENOENT)
          error (NILF, _("%s: Shell program not found"), shell);
        else
          perror_with_name ("execvp: ", shell);
+# ifdef __EMX__
+       } /* note: closing brace! */
+# endif
        break;
       }
 
+# ifdef __EMX__
+    case EINVAL:
+      /* this nasty error was driving me nuts :-( */
+      error(NILF, _("spawnvpe: environment space might be exhausted")); /* new 
gettext message required */
+      /* no break! */
+# endif
+
     default:
+# ifdef __EMX__
+      perror_with_name ("spawnvpe: ", argv[0]);
+# else
       perror_with_name ("execvp: ", argv[0]);
+# endif
       break;
     }
 
+# ifdef __EMX__
+  return pid; /* if we reach this point then pid > 0 */
+# else
   _exit (127);
+# endif /* !__EMX__ */
 #endif /* !WINDOWS32 */
 #endif /* !VMS */
 }
@@ -2478,13 +2683,44 @@
                  0 };
   char*  sh_chars;
   char** sh_cmds;
-#else  /* must be UNIX-ish */
+#else /* !WINDOWS32 */
+# ifdef __EMX__
+  static char sh_chars_dos[] = "*?[];|<>%^&()";
+  static char *sh_cmds_dos[] = { "break", "call", "cd", "chcp", "chdir", "cls",
+                                "copy", "ctty", "date", "del", "dir", "echo",
+                                "erase", "exit", "for", "goto", "if", "md",
+                                "mkdir", "path", "pause", "prompt", "rd",
+                                "rmdir", "rem", "ren", "rename", "set",
+                                "shift", "time", "type", "ver", "verify",
+                                "vol", ":", 0 };
+
+  static char sh_chars_os2[] = "*?[];|<>%^()\"'&";
+  static char *sh_cmds_os2[] = { "call", "cd", "chcp", "chdir", "cls", "copy",
+                            "date", "del", "detach", "dir", "echo",
+                            "endlocal", "erase", "exit", "for", "goto", "if",
+                            "keys", "md", "mkdir", "move", "path", "pause",
+                            "prompt", "rd", "rem", "ren", "rename", "rmdir",
+                            "set", "setlocal", "shift", "start", "time",
+                             "type", "ver", "verify", "vol", ":", 0 };
+
+  static char sh_chars_sh[]  = "#;\"*?[]&|<>(){}$`^";
+  static char *sh_cmds_sh[]  = { "echo", "cd", "eval", "exec", "exit", "login",
+                                "logout", "set", "umask", "wait", "while",
+                                "for", "case", "if", ":", ".", "break",
+                                "continue", "export", "read", "readonly",
+                                "shift", "times", "trap", "switch", "unset",
+                                 0 };
+  char *sh_chars;
+  char **sh_cmds;
+
+# else  /* must be UNIX-ish */
   static char sh_chars[] = "#;\"*?[]&|<>(){}$`^~";
   static char *sh_cmds[] = { "cd", "eval", "exec", "exit", "login",
                             "logout", "set", "umask", "wait", "while", "for",
                             "case", "if", ":", ".", "break", "continue",
                             "export", "read", "readonly", "shift", "times",
                             "trap", "switch", 0 };
+# endif /* __EMX__ */
 #endif /* WINDOWS32 */
 #endif /* Amiga */
 #endif /* __MSDOS__ */
@@ -2534,14 +2770,17 @@
   if (slow_flag)
     goto slow;
 #else  /* not WINDOWS32 */
-#ifdef __MSDOS__
+#if defined (__MSDOS__) || defined (__EMX__)
   else if (stricmp (shell, default_shell))
     {
       extern int _is_unixy_shell (const char *_path);
 
       message (1, _("$SHELL changed (was `%s', now `%s')"), default_shell, 
shell);
       unixy_shell = _is_unixy_shell (shell);
-      default_shell = shell;
+      /* we must allocate a copy of shell for default_shell because
+       construct_command_argv() will free shell after this function returns */
+      default_shell = xmalloc(strlen(shell) + 1);
+      strcpy(default_shell, shell);
     }
   if (unixy_shell)
     {
@@ -2550,13 +2789,25 @@
     }
   else
     {
-      sh_chars = sh_chars_dos;
-      sh_cmds  = sh_cmds_dos;
+# ifdef __EMX__
+      if (_osmode == OS2_MODE)
+        {
+          sh_chars = sh_chars_os2;
+          sh_cmds = sh_cmds_os2;
+        }
+      else
+        {
+# endif __EMX__
+          sh_chars = sh_chars_dos;
+          sh_cmds  = sh_cmds_dos;
+# ifdef __EMX__
+        }
+# endif
     }
-#else  /* not __MSDOS__ */
+#else  /* not __MSDOS__ && not __EMX__ */
   else if (strcmp (shell, default_shell))
     goto slow;
-#endif /* not __MSDOS__ */
+#endif /* not __MSDOS__ && not __EMX__ */
 #endif /* not WINDOWS32 */
 
   if (ifs != 0)
@@ -2667,7 +2918,7 @@
              }
            else if (p[1] != '\0')
               {
-#if defined(__MSDOS__) || defined(WINDOWS32)
+#if defined(__MSDOS__) || defined(WINDOWS32) || defined (__EMX__)
                 /* Only remove backslashes before characters special
                    to Unixy shells.  All other backslashes are copied
                    verbatim, since they are probably DOS-style
@@ -2859,6 +3110,10 @@
                                      + (line_len * 2) + 1);
     char *command_ptr = NULL; /* used for batch_mode_shell mode */
 
+# ifdef __EMX__ /* is this necessary? */
+    if (!unixy_shell) minus_c[1] = '/'; /* " /c " */
+# endif
+
     ap = new_line;
     bcopy (shell, ap, shell_len);
     ap += shell_len;
@@ -2972,24 +3227,129 @@
       new_argv = construct_command_argv_internal (new_line, (char **) NULL,
                                                   (char *) 0, (char *) 0,
                                                   (char **) 0);
-#ifdef  __MSDOS__
+
+#if defined (__EMX__) || defined (__MSDOS__)
+# ifdef __EMX__
+    else if (!unixy_shell)
+      {
+       /* new_line is local, must not be freed therefore */
+       char *p, *q;
+       int quote;
+       size_t index;
+       size_t len;
+
+       /* handle quotes
+          We have to remove all double quotes and to split the line
+          into distinct arguments because of the strange handling
+          of builtin commands by cmd: 'echo "bla"' prints "bla"
+          (with quotes) while 'c:\bin\echo.exe "bla"' prints bla
+          (without quotes). Some programs like autoconf rely
+          on the second behaviour. */
+       
+       len = strlen (new_line) + 1;
+
+       /* More than 1 arg per character is impossible.  */
+       new_argv = (char **) xmalloc (len * sizeof (char *));
+
+       /* All the args can fit in a buffer as big as new_line is.   */
+       new_argv[0] = (char *) xmalloc (len);
+
+       index = 0;
+       quote = 0;
+       q = new_line;
+       p = new_argv[index];
+       while(*q != '\0')
+         {
+           /* searching for closing quote */
+           if (quote)
+             { 
+               if (*q == quote)
+                 {
+                   /* remove the quote */
+                   while(*q == quote) /* do not ask */
+                     q++;
+                   quote = 0;
+                 }
+               else /* normal character: copy it */
+                 *p++ = *q++; 
+             }
+           
+           /* searching for opening quote */
+           else if (*q == '\"'
+#  ifndef NO_CMD_DEFAULT
+                    || *q == '\''
+#  endif
+                    )
+             { 
+               /* remove opening quote */
+               quote = *q;
+               while(*q == quote) /* do not ask */
+                 q++;
+             }
+           
+           /* spaces outside of a quoted string: remove them
+              and start a new argument */
+           else if (*q == ' ' || *q == '\t')
+             { 
+               *p++ = '\0'; /* trailing '\0' for last argument */
+               
+               /* remove all successive spaces */
+               do 
+                 {
+                   q++;
+                 }
+               while(*q == ' ' || *q == '\t');
+               
+               /* start new argument */
+               index++;
+               new_argv[index] = p;
+             }
+           
+           /* normal character (no space) outside a quoted string*/
+           else
+             *p++ = *q++;
+         } /* end while() */
+       
+       *p = '\0'; /* trailing '\0' for the last argument */
+       new_argv[index + 1] = NULL;
+
+#  ifndef NO_CMD_DEFAULT
+       /* special case: echo x="y"
+          (e.g. autoconf uses this to determine whether make works) 
+          this is pure idioty but cmd works this way:
+          if 'echo' and 'x="y"' are two different arguments cmd
+          will print '"x="y""' but if they are only one argument
+          cmd will print 'bla="blurb"' as it should be
+          note: if we do not allow cmd to be the default shell
+          we do not need this kind of voodoo */
+       if (index == 3 && strcasecmp(new_argv[2], "echo") == 0)
+         {
+           new_argv[2][4] = ' ';
+           new_argv[3] = NULL;
+         }
+#  endif
+      }
+# endif /* __EMX__ */
+
+# ifdef  __MSDOS__
     else
       {
-      /* With MSDOS shells, we must construct the command line here
-         instead of recursively calling ourselves, because we
-         cannot backslash-escape the special characters (see above).  */
-      new_argv = (char **) xmalloc (sizeof (char *));
-      line_len = strlen (new_line) - shell_len - sizeof (minus_c) + 1;
-      new_argv[0] = xmalloc (line_len + 1);
-      strncpy (new_argv[0],
-               new_line + shell_len + sizeof (minus_c) - 1, line_len);
-      new_argv[0][line_len] = '\0';
+       /* With MSDOS shells, we must construct the command line here
+          instead of recursively calling ourselves, because we
+          cannot backslash-escape the special characters (see above).  */
+       new_argv = (char **) xmalloc (sizeof (char *));
+       line_len = strlen (new_line) - shell_len - sizeof (minus_c) + 1;
+       new_argv[0] = xmalloc (line_len + 1);
+       strncpy (new_argv[0],
+                new_line + shell_len + sizeof (minus_c) - 1, line_len);
+       new_argv[0][line_len] = '\0';
       }
-#else
+# endif /* __MSDOS__ */
+#else /* ! __EMX__ && ! __MSDOS__ */
     else
       fatal (NILF, _("%s (line %d) Bad shell context (!unixy && 
!batch_mode_shell)\n"),
-            __FILE__, __LINE__);
-#endif
+            __FILE__, __LINE__);
+#endif /* ! __EMX__ && ! __MSDOS__ */
   }
 #endif /* ! AMIGA */
 
@@ -3076,6 +3436,51 @@
       strcpy(shell, p);
     }
 #endif
+#ifdef __EMX__
+    {
+      /* some static variables to avoid testing the same stuff ever and ever 
again */
+      static const char *unixroot = NULL;
+      static const char *last_shell = "";
+      static int init = 0;
+      if (init == 0)
+       {
+         unixroot = getenv ("UNIXROOT");
+         /* unixroot must be NULL or not empty */
+         if (unixroot && unixroot[0] == '\0') unixroot = NULL;
+         init = 1;
+       }
+
+      /* if we have an unixroot drive and if shell is not default_shell (which 
means
+       it's either cmd.exe or the test has already been performed)
+       and if shell is an absolute path without drive letter, try whether it 
exists
+       e.g.: if "/bin/sh" does not exist use "$UNIXROOT/bin/sh" instead */
+      if (unixroot && shell && strcmp (shell, last_shell) != 0
+         && (shell[0] == '/' || shell[0] == '\\'))
+       {
+         /* trying a new shell, check whether it exists */
+         size_t size = strlen (shell);
+         char *buf = xmalloc (size + 7);
+         memcpy (buf, shell, size);
+         memcpy (buf + size, ".exe", 5); /* including the trailing '\0' */
+          if (access (shell, F_OK) != 0 && access (buf, F_OK) != 0)
+           {
+             /* try the same for the unixroot drive */
+             memmove (buf + 2, buf, size + 5);
+             buf[0] = unixroot[0];
+             buf[1] = unixroot[1];
+             if (access (buf, F_OK) == 0)
+               /* we have found a shell! */
+               /* free(shell); */
+               shell = buf;
+             else
+               free (buf);
+           }
+         else
+            free (buf);
+       }
+    }
+#endif __EMX__
+
     ifs = allocated_variable_expand_for_file ("$(IFS)", file);
 
     warn_undefined_variables_flag = save;
@@ -3107,4 +3512,4 @@
 
   return fd;
 }
-#endif /* !HAPE_DUP2 && !_AMIGA */
+#endif /* !HAVE_DUP2 && !_AMIGA */
-------------------------------------------

bye,
Andreas



reply via email to

[Prev in Thread] Current Thread [Next in Thread]