diff options
| author | Eli Zaretskii | 2015-02-10 18:26:23 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2015-02-10 18:26:23 +0200 |
| commit | 4b0b27d0018f040bda6a2ec885fa54c666d9c083 (patch) | |
| tree | 03bd3405355205ee121268785581e432dc7d8be1 /nt/cmdproxy.c | |
| parent | 87fc99fee17ef1df4c22db15ec783a7735d3fc6b (diff) | |
| download | emacs-4b0b27d0018f040bda6a2ec885fa54c666d9c083.tar.gz emacs-4b0b27d0018f040bda6a2ec885fa54c666d9c083.zip | |
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.
Diffstat (limited to 'nt/cmdproxy.c')
| -rw-r--r-- | nt/cmdproxy.c | 72 |
1 files changed, 66 insertions, 6 deletions
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) | |||
| 135 | return str; | 135 | return str; |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | int escape_char = '\\'; | 138 | /* This value is never changed by the code. We keep the code that |
| 139 | supports also the value of '"', but let's allow the compiler to | ||
| 140 | optimize it out, until someone actually uses that. */ | ||
| 141 | const int escape_char = '\\'; | ||
| 139 | 142 | ||
| 140 | /* Get next token from input, advancing pointer. */ | 143 | /* Get next token from input, advancing pointer. */ |
| 141 | int | 144 | int |
| @@ -196,11 +199,31 @@ get_next_token (char * buf, const char ** pSrc) | |||
| 196 | /* End of string, but no ending quote found. We might want to | 199 | /* End of string, but no ending quote found. We might want to |
| 197 | flag this as an error, but for now will consider the end as | 200 | flag this as an error, but for now will consider the end as |
| 198 | the end of the token. */ | 201 | the end of the token. */ |
| 202 | if (escape_char == '\\') | ||
| 203 | { | ||
| 204 | /* Output literal backslashes. Note that if the | ||
| 205 | token ends with an unpaired backslash, we eat it | ||
| 206 | up here. But since this case invokes undefined | ||
| 207 | behavior anyway, it's okay. */ | ||
| 208 | while (escape_char_run > 1) | ||
| 209 | { | ||
| 210 | *o++ = escape_char; | ||
| 211 | escape_char_run -= 2; | ||
| 212 | } | ||
| 213 | } | ||
| 199 | *o = '\0'; | 214 | *o = '\0'; |
| 200 | break; | 215 | break; |
| 201 | } | 216 | } |
| 202 | else | 217 | else |
| 203 | { | 218 | { |
| 219 | if (escape_char == '\\') | ||
| 220 | { | ||
| 221 | /* Output literal backslashes. Note that we don't | ||
| 222 | treat a backslash as an escape character here, | ||
| 223 | since it doesn't preceed a quote. */ | ||
| 224 | for ( ; escape_char_run > 0; escape_char_run--) | ||
| 225 | *o++ = escape_char; | ||
| 226 | } | ||
| 204 | *o++ = *p++; | 227 | *o++ = *p++; |
| 205 | } | 228 | } |
| 206 | } | 229 | } |
| @@ -229,13 +252,44 @@ search_dir (const char *dir, const char *exec, int bufsize, char *buffer) | |||
| 229 | int n_exts = sizeof (exts) / sizeof (char *); | 252 | int n_exts = sizeof (exts) / sizeof (char *); |
| 230 | char *dummy; | 253 | char *dummy; |
| 231 | int i, rc; | 254 | int i, rc; |
| 255 | const char *pext = strrchr (exec, '\\'); | ||
| 256 | |||
| 257 | /* Does EXEC already include an extension? */ | ||
| 258 | if (!pext) | ||
| 259 | pext = exec; | ||
| 260 | pext = strchr (pext, '.'); | ||
| 232 | 261 | ||
| 233 | /* Search the directory for the program. */ | 262 | /* Search the directory for the program. */ |
| 234 | for (i = 0; i < n_exts; i++) | 263 | if (pext) |
| 235 | { | 264 | { |
| 236 | rc = SearchPath (dir, exec, exts[i], bufsize, buffer, &dummy); | 265 | /* SearchPath will not append an extension if the file already |
| 266 | has an extension, so we must append it ourselves. */ | ||
| 267 | char exec_ext[MAX_PATH], *p; | ||
| 268 | |||
| 269 | p = strcpy (exec_ext, exec) + strlen (exec); | ||
| 270 | |||
| 271 | /* Search first without any extension; if found, we are done. */ | ||
| 272 | rc = SearchPath (dir, exec_ext, NULL, bufsize, buffer, &dummy); | ||
| 237 | if (rc > 0) | 273 | if (rc > 0) |
| 238 | return rc; | 274 | return rc; |
| 275 | |||
| 276 | /* Try the known extensions. */ | ||
| 277 | for (i = 0; i < n_exts; i++) | ||
| 278 | { | ||
| 279 | strcpy (p, exts[i]); | ||
| 280 | rc = SearchPath (dir, exec_ext, NULL, bufsize, buffer, &dummy); | ||
| 281 | if (rc > 0) | ||
| 282 | return rc; | ||
| 283 | } | ||
| 284 | } | ||
| 285 | else | ||
| 286 | { | ||
| 287 | for (i = 0; i < n_exts; i++) | ||
| 288 | { | ||
| 289 | rc = SearchPath (dir, exec, exts[i], bufsize, buffer, &dummy); | ||
| 290 | if (rc > 0) | ||
| 291 | return rc; | ||
| 292 | } | ||
| 239 | } | 293 | } |
| 240 | 294 | ||
| 241 | return 0; | 295 | return 0; |
| @@ -769,7 +823,7 @@ main (int argc, char ** argv) | |||
| 769 | quotes, since they are illegal in path names). */ | 823 | quotes, since they are illegal in path names). */ |
| 770 | 824 | ||
| 771 | remlen = maxlen = | 825 | remlen = maxlen = |
| 772 | strlen (progname) + extra_arg_space + strlen (cmdline) + 16; | 826 | strlen (progname) + extra_arg_space + strlen (cmdline) + 16 + 2; |
| 773 | buf = p = alloca (maxlen + 1); | 827 | buf = p = alloca (maxlen + 1); |
| 774 | 828 | ||
| 775 | /* Quote progname in case it contains spaces. */ | 829 | /* Quote progname in case it contains spaces. */ |
| @@ -784,10 +838,16 @@ main (int argc, char ** argv) | |||
| 784 | remlen = maxlen - (p - buf); | 838 | remlen = maxlen - (p - buf); |
| 785 | } | 839 | } |
| 786 | 840 | ||
| 841 | /* Now that we know we will be invoking the shell, quote the | ||
| 842 | command line after the "/c" switch as the shell expects: | ||
| 843 | a single pair of quotes enclosing the entire command | ||
| 844 | tail, no matter whether quotes are used in the command | ||
| 845 | line, and how many of them are there. See the output of | ||
| 846 | "cmd /?" for how cmd.exe treats quotes. */ | ||
| 787 | if (run_command_dot_com) | 847 | if (run_command_dot_com) |
| 788 | _snprintf (p, remlen, " /e:%d /c %s", envsize, cmdline); | 848 | _snprintf (p, remlen, " /e:%d /c \"%s\"", envsize, cmdline); |
| 789 | else | 849 | else |
| 790 | _snprintf (p, remlen, " /c %s", cmdline); | 850 | _snprintf (p, remlen, " /c \"%s\"", cmdline); |
| 791 | cmdline = buf; | 851 | cmdline = buf; |
| 792 | } | 852 | } |
| 793 | else | 853 | else |