1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-27 07:37:33 +00:00

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.
This commit is contained in:
Eli Zaretskii 2015-02-10 18:26:23 +02:00
parent 87fc99fee1
commit 4b0b27d001
2 changed files with 75 additions and 6 deletions

View 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> 2014-11-17 Oscar Fuentes <ofv@wanadoo.es>
* inc/ms-w32.h: Define MINGW_W64. * inc/ms-w32.h: Define MINGW_W64.

View File

@ -135,7 +135,10 @@ skip_nonspace (const char *str)
return 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. */ /* Get next token from input, advancing pointer. */
int 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 /* 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 flag this as an error, but for now will consider the end as
the end of the token. */ 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'; *o = '\0';
break; break;
} }
else 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++; *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 *); int n_exts = sizeof (exts) / sizeof (char *);
char *dummy; char *dummy;
int i, rc; 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. */ /* 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) if (rc > 0)
return rc; 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; return 0;
@ -769,7 +823,7 @@ main (int argc, char ** argv)
quotes, since they are illegal in path names). */ quotes, since they are illegal in path names). */
remlen = maxlen = remlen = maxlen =
strlen (progname) + extra_arg_space + strlen (cmdline) + 16; strlen (progname) + extra_arg_space + strlen (cmdline) + 16 + 2;
buf = p = alloca (maxlen + 1); buf = p = alloca (maxlen + 1);
/* Quote progname in case it contains spaces. */ /* Quote progname in case it contains spaces. */
@ -784,10 +838,16 @@ main (int argc, char ** argv)
remlen = maxlen - (p - buf); 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) if (run_command_dot_com)
_snprintf (p, remlen, " /e:%d /c %s", envsize, cmdline); _snprintf (p, remlen, " /e:%d /c \"%s\"", envsize, cmdline);
else else
_snprintf (p, remlen, " /c %s", cmdline); _snprintf (p, remlen, " /c \"%s\"", cmdline);
cmdline = buf; cmdline = buf;
} }
else else