]> git.eshelyaron.com Git - emacs.git/commitdiff
(get_env_size): New function.
authorGeoff Voelker <voelker@cs.washington.edu>
Wed, 3 Sep 1997 02:18:32 +0000 (02:18 +0000)
committerGeoff Voelker <voelker@cs.washington.edu>
Wed, 3 Sep 1997 02:18:32 +0000 (02:18 +0000)
(spawn): Explicitly pass in environment when creating subprocess.
(main): Cleaup error messages.
Specify dynamically sized environment block for real shell.
Pass on unhandled switches to real shell.
Quote program name.

(get_next_token): Null terminate token returned.

nt/cmdproxy.c

index 4a270cfadce7e37415ffcbeda00610d513d4f44b..18705af47f55c8928dc1909fce2eeaf444062c9d 100644 (file)
@@ -209,6 +209,7 @@ get_next_token (char * buf, char ** pSrc)
       char * p1 = skip_nonspace (p);
       memcpy (o, p, p1 - p);
       o += (p1 - p);
+      *o = '\0';
       p = p1;
     }
 
@@ -371,6 +372,7 @@ spawn (char * progname, char * cmdline)
   DWORD rc = 0xff;
   SECURITY_ATTRIBUTES sec_attrs;
   STARTUPINFO start;
+  char * envblock = GetEnvironmentStrings ();
 
   sec_attrs.nLength = sizeof (sec_attrs);
   sec_attrs.lpSecurityDescriptor = NULL;
@@ -380,7 +382,7 @@ spawn (char * progname, char * cmdline)
   start.cb = sizeof (start);
 
   if (CreateProcess (progname, cmdline, &sec_attrs, NULL, TRUE,
-                    0, NULL, NULL, &start, &child))
+                    0, envblock, NULL, &start, &child))
   {
     /* wait for completion and pass on return code */
     WaitForSingleObject (child.hProcess, INFINITE);
@@ -390,9 +392,24 @@ spawn (char * progname, char * cmdline)
     child.hProcess = NULL;
   }
 
+  FreeEnvironmentStrings (envblock);
+
   return (int) rc;
 }
 
+/* Return size of current environment block.  */
+int
+get_env_size ()
+{
+  char * start = GetEnvironmentStrings ();
+  char * tmp = start;
+
+  while (tmp[0] || tmp[1])
+    ++tmp;
+  FreeEnvironmentStrings (start);
+  return  tmp + 2 - start;
+}
+
 /*******  Main program  ********************************************/
 
 int
@@ -403,6 +420,8 @@ main (int argc, char ** argv)
   char * cmdline;
   char * progname;
   int envsize;
+  char **pass_through_args;
+  int num_pass_through_args;
   char modname[MAX_PATH];
   char path[MAX_PATH];
 
@@ -424,7 +443,7 @@ main (int argc, char ** argv)
      from the command line.)  */
 
   if (!GetModuleFileName (NULL, modname, sizeof (modname)))
-    fail ("GetModuleFileName failed");
+    fail ("error: GetModuleFileName failed\n");
 
   /* Although Emacs always sets argv[0] to an absolute pathname, we
      might get run in other ways as well, so convert argv[0] to an
@@ -453,45 +472,72 @@ main (int argc, char ** argv)
   /* If no args, spawn real shell for interactive use.  */
   need_shell = TRUE;
   interactive = TRUE;
-  /* Ask for a reasonable size environment for command.com.  */
-  envsize = 1024;
+  /* Ask command.com to create an environment block with a reasonable
+     amount of free space.  */
+  envsize = get_env_size () + 300;
+  pass_through_args = (char **) alloca (argc * sizeof(char *));
+  num_pass_through_args = 0;
 
   while (--argc > 0)
     {
       ++argv;
-      /* Only support single letter switches (except for -e); allow / as
+      /* Act on switches we recognize (mostly single letter switches,
+        except for -e); all unrecognised switches and extra args are
+        passed on to real shell if used (only really of benefit for
+        interactive use, but allow for batch use as well).  Accept / as
         switch char for compatability with cmd.exe.  */
-      if ( ((*argv)[0] == '-' || (*argv)[0] == '/')
-          && (*argv)[1] != '\0' && (*argv)[2] == '\0' )
+      if ( ((*argv)[0] == '-' || (*argv)[0] == '/') && (*argv)[1] != '\0' )
        {
          if ( ((*argv)[1] == 'c') && ((*argv)[2] == '\0')  )
            {
              if (--argc == 0)
-               fail ("error: expecting arg for %s", *argv);
+               fail ("error: expecting arg for %s\n", *argv);
              cmdline = *(++argv);
              interactive = FALSE;
            }
          else if ( ((*argv)[1] == 'i') && ((*argv)[2] == '\0')  )
            {
              if (cmdline)
-               warn ("warning: %s ignored because of -c", *argv);
+               warn ("warning: %s ignored because of -c\n", *argv);
            }
          else if ( ((*argv)[1] == 'e') && ((*argv)[2] == ':')  )
            {
-             envsize = atoi (*argv + 3);
-             /* Enforce a reasonable minimum size.  */
-             if (envsize < 256)
-               envsize = 256;
+             int requested_envsize = atoi (*argv + 3);
+             /* Enforce a reasonable minimum size, as above.  */
+             if (requested_envsize > envsize)
+               envsize = requested_envsize;
+             /* For sanity, enforce a reasonable maximum.  */
+             if (envsize > 32768)
+               envsize = 32768;
            }
          else
            {
-             warn ("warning: unknown option %s ignored", *argv);
+             /* warn ("warning: unknown option %s ignored", *argv); */
+             pass_through_args[num_pass_through_args++] = *argv;
            }
        }
       else
        break;
     }
 
+#if 0
+  /* I think this is probably not useful - cmd.exe ignores extra
+     (non-switch) args in interactive mode, and they cannot be passed on
+     when -c was given.  */
+
+  /* Collect any remaining args after (initial) switches.  */
+  while (argc-- > 0)
+    {
+      pass_through_args[num_pass_through_args++] = *argv++;
+    }
+#else
+  /* Probably a mistake for there to be extra args; not fatal.  */
+  if (argc > 0)
+    warn ("warning: extra args ignored after %s\n", argv[-1]);
+#endif
+
+  pass_through_args[num_pass_through_args] = NULL;
+
   /* If -c option, determine if we must spawn a real shell, or if we can
      execute the command directly ourself.  */
   if (cmdline)
@@ -525,26 +571,47 @@ main (int argc, char ** argv)
   if (need_shell)
     {
       char * p;
+      int    extra_arg_space = 0;
 
       progname = getenv ("COMSPEC");
       if (!progname)
-       fail ("error: COMSPEC is not set");
+       fail ("error: COMSPEC is not set\n");
 
       canon_filename (progname);
       progname = make_absolute (progname);
 
       if (progname == NULL || strchr (progname, '\\') == NULL)
-       fail ("make_absolute failed");
+       fail ("error: the program %s could not be found.\n", getenv ("COMSPEC"));
+
+      /* Work out how much extra space is required for
+         pass_through_args.  */
+      for (argv = pass_through_args; *argv != NULL; ++argv)
+       /* We don't expect to have to quote switches.  */
+       extra_arg_space += strlen (*argv) + 2;
 
       if (cmdline)
        {
+         char * buf;
+
          /* Convert to syntax expected by cmd.exe/command.com for
             running non-interactively.  Always quote program name in
             case path contains spaces (fortunately it can't contain
             quotes, since they are illegal in path names).  */
-         wsprintf (p = alloca (strlen (cmdline) + strlen (progname) + 7),
-                   "\"%s\" /c %s", progname, cmdline);
-         cmdline = p;
+
+         buf = p = alloca (strlen (progname) + extra_arg_space +
+                           strlen (cmdline) + 16);
+
+         /* Quote progname in case it contains spaces.  */
+         p += wsprintf (p, "\"%s\"", progname);
+
+         /* Include pass_through_args verbatim; these are just switches
+             so should not need quoting.  */
+         for (argv = pass_through_args; *argv != NULL; ++argv)
+           p += wsprintf (p, " %s", *argv);
+
+         /* Always set environment size to something reasonable.  */
+         wsprintf(p, " /e:%d /c %s", envsize, cmdline);
+         cmdline = buf;
        }
       else
        {
@@ -556,15 +623,23 @@ main (int argc, char ** argv)
             - command.com doesn't like it), we always use the 8.3 form.  */
          GetShortPathName (progname, path, sizeof (path));
          p = strrchr (path, '\\');
-         /* Trailing slash is acceptable.  */
-         p++;
+         /* Trailing slash is acceptable, so always leave it.  */
+         *(++p) = '\0';
 
-         /* Set environment size - again cmd.exe ignores this silently.  */
-         wsprintf (p, " /e:%d", envsize);
+         cmdline = p = alloca (strlen (progname) + extra_arg_space +
+                               strlen (path) + 13);
 
          /* Quote progname in case it contains spaces.  */
-         wsprintf (cmdline = alloca (strlen (progname) + strlen (path) + 4),
-                   "\"%s\" %s", progname, path);
+         p += wsprintf (p, "\"%s\" %s", progname, path);
+
+         /* Include pass_through_args verbatim; these are just switches
+             so should not need quoting.  */
+         for (argv = pass_through_args; *argv != NULL; ++argv)
+           p += wsprintf (p, " %s", *argv);
+
+         /* Always set environment size to something reasonable - again
+             cmd.exe ignores this silently.  */
+         wsprintf (p, " /e:%d", envsize);
        }
     }