summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2015-02-10 18:26:23 +0200
committerEli Zaretskii <eliz@gnu.org>2015-02-10 18:26:23 +0200
commit4b0b27d0018f040bda6a2ec885fa54c666d9c083 (patch)
tree03bd3405355205ee121268785581e432dc7d8be1
parent87fc99fee17ef1df4c22db15ec783a7735d3fc6b (diff)
downloademacs-4b0b27d0018f040bda6a2ec885fa54c666d9c083.tar.gz
Fix invocation of commands whose file name includes extension (Bug#19817)
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.
-rw-r--r--nt/ChangeLog9
-rw-r--r--nt/cmdproxy.c72
2 files changed, 75 insertions, 6 deletions
diff --git a/nt/ChangeLog b/nt/ChangeLog
index cac8e054068..d1f953f9ac5 100644
--- a/nt/ChangeLog
+++ b/nt/ChangeLog
@@ -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.
diff --git a/nt/cmdproxy.c b/nt/cmdproxy.c
index 7dbb529a6c9..ce5815291df 100644
--- a/nt/cmdproxy.c
+++ b/nt/cmdproxy.c
@@ -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