]> code.delx.au - gnu-emacs/blobdiff - nt/cmdproxy.c
Merge from origin/emacs-25
[gnu-emacs] / nt / cmdproxy.c
index faef2f83496b6dc6cff9f95a39a4d1bbd653e78a..411a409bacaa0e1130ab31ae0c3e2c57589610f5 100644 (file)
@@ -1,5 +1,5 @@
 /* Proxy shell designed for use with Emacs on Windows 95 and NT.
-   Copyright (C) 1997, 2001-2015 Free Software Foundation, Inc.
+   Copyright (C) 1997, 2001-2016 Free Software Foundation, Inc.
 
    Accepts subset of Unix sh(1) command-line options, for compatibility
    with elisp code written for Unix.  When possible, executes external
@@ -16,8 +16,8 @@ This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -135,7 +135,10 @@ skip_nonspace (const char *str)
   return str;
 }
 
-int escape_char = '\\';
+/* This value is never changed by the code.  We keep the code that
+   supports also the value of '"', but let's allow the compiler to
+   optimize it out, until someone actually uses that.  */
+const int escape_char = '\\';
 
 /* Get next token from input, advancing pointer.  */
 int
@@ -196,11 +199,31 @@ get_next_token (char * buf, const char ** pSrc)
              /* End of string, but no ending quote found.  We might want to
                 flag this as an error, but for now will consider the end as
                 the end of the token.  */
+             if (escape_char == '\\')
+               {
+                 /* Output literal backslashes.  Note that if the
+                    token ends with an unpaired backslash, we eat it
+                    up here.  But since this case invokes undefined
+                    behavior anyway, it's okay.  */
+                 while (escape_char_run > 1)
+                   {
+                     *o++ = escape_char;
+                     escape_char_run -= 2;
+                   }
+               }
              *o = '\0';
              break;
            }
          else
            {
+             if (escape_char == '\\')
+               {
+                 /* Output literal backslashes.  Note that we don't
+                    treat a backslash as an escape character here,
+                    since it doesn't precede a quote.  */
+                 for ( ; escape_char_run > 0; escape_char_run--)
+                   *o++ = escape_char;
+               }
              *o++ = *p++;
            }
        }
@@ -251,13 +274,44 @@ search_dir (const char *dir, const char *exec, int bufsize, char *buffer)
   int n_exts = sizeof (exts) / sizeof (char *);
   char *dummy;
   int i, rc;
+  const char *pext = strrchr (exec, '\\');
+
+  /* Does EXEC already include an extension?  */
+  if (!pext)
+    pext = exec;
+  pext = strchr (pext, '.');
 
   /* Search the directory for the program.  */
-  for (i = 0; i < n_exts; i++)
+  if (pext)
     {
-      rc = SearchPath (dir, exec, exts[i], bufsize, buffer, &dummy);
+      /* SearchPath will not append an extension if the file already
+        has an extension, so we must append it ourselves.  */
+      char exec_ext[MAX_PATH], *p;
+
+      p = strcpy (exec_ext, exec) + strlen (exec);
+
+      /* Search first without any extension; if found, we are done.  */
+      rc = SearchPath (dir, exec_ext, NULL, bufsize, buffer, &dummy);
       if (rc > 0)
        return rc;
+
+      /* Try the known extensions.  */
+      for (i = 0; i < n_exts; i++)
+       {
+         strcpy (p, exts[i]);
+         rc = SearchPath (dir, exec_ext, NULL, bufsize, buffer, &dummy);
+         if (rc > 0)
+           return rc;
+       }
+    }
+  else
+    {
+      for (i = 0; i < n_exts; i++)
+       {
+         rc = SearchPath (dir, exec, exts[i], bufsize, buffer, &dummy);
+         if (rc > 0)
+           return rc;
+       }
     }
 
   return 0;
@@ -798,7 +852,7 @@ main (int argc, char ** argv)
             quotes, since they are illegal in path names).  */
 
          remlen = maxlen =
-           strlen (progname) + extra_arg_space + strlen (cmdline) + 16;
+           strlen (progname) + extra_arg_space + strlen (cmdline) + 16 + 2;
          buf = p = alloca (maxlen + 1);
 
          /* Quote progname in case it contains spaces.  */
@@ -813,10 +867,16 @@ main (int argc, char ** argv)
              remlen = maxlen - (p - buf);
            }
 
+         /* Now that we know we will be invoking the shell, quote the
+            command line after the "/c" switch as the shell expects:
+            a single pair of quotes enclosing the entire command
+            tail, no matter whether quotes are used in the command
+            line, and how many of them are there.  See the output of
+            "cmd /?" for how cmd.exe treats quotes.  */
          if (run_command_dot_com)
-           _snprintf (p, remlen, " /e:%d /c %s", envsize, cmdline);
+           _snprintf (p, remlen, " /e:%d /c \"%s\"", envsize, cmdline);
          else
-           _snprintf (p, remlen, " /c %s", cmdline);
+           _snprintf (p, remlen, " /c \"%s\"", cmdline);
          cmdline = buf;
        }
       else