aboutsummaryrefslogtreecommitdiffstats
path: root/nt/cmdproxy.c
diff options
context:
space:
mode:
authorEli Zaretskii2015-02-10 18:26:23 +0200
committerEli Zaretskii2015-02-10 18:26:23 +0200
commit4b0b27d0018f040bda6a2ec885fa54c666d9c083 (patch)
tree03bd3405355205ee121268785581e432dc7d8be1 /nt/cmdproxy.c
parent87fc99fee17ef1df4c22db15ec783a7735d3fc6b (diff)
downloademacs-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.c72
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
138int 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. */
141const int escape_char = '\\';
139 142
140/* Get next token from input, advancing pointer. */ 143/* Get next token from input, advancing pointer. */
141int 144int
@@ -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