]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix invocation of commands whose file name includes extension (Bug#19817)
authorEli Zaretskii <eliz@gnu.org>
Tue, 10 Feb 2015 16:26:23 +0000 (18:26 +0200)
committerEli Zaretskii <eliz@gnu.org>
Tue, 10 Feb 2015 16:26:23 +0000 (18:26 +0200)
 nt/cmdproxy.c (get_next_token): Don't make backslashes disappear
 without a trace when they are not followed by a quote.
 (search_dir): Support searching programs whose file name already
 has an arbitrary extension.
 (main): When passing a command line to the shell, use cmd.exe
 rules for quoting command-line tail.

nt/ChangeLog
nt/cmdproxy.c

index cac8e054068e1d6060a658e80f2e6e6a5075b579..d1f953f9ac58300c32825d942db10b8db5cecbd8 100644 (file)
@@ -1,3 +1,12 @@
+2015-02-10  Eli Zaretskii  <eliz@gnu.org>
+
+       * cmdproxy.c (get_next_token): Don't make backslashes disappear
+       without a trace when they are not followed by a quote.
+       (search_dir): Support searching programs whose file name already
+       has an arbitrary extension.  (Bug#19817)
+       (main): When passing a command line to the shell, use cmd.exe
+       rules for quoting command-line tail.
+
 2014-11-17  Oscar Fuentes  <ofv@wanadoo.es>
 
        * inc/ms-w32.h: Define MINGW_W64.
index 7dbb529a6c9d66b3b978219537b7c19da45bd511..ce5815291dfee083d646f0cf66c4e0deb22f85ec 100644 (file)
@@ -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 preceed a quote.  */
+                 for ( ; escape_char_run > 0; escape_char_run--)
+                   *o++ = escape_char;
+               }
              *o++ = *p++;
            }
        }
@@ -229,13 +252,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;
@@ -769,7 +823,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.  */
@@ -784,10 +838,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