summaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
authorJarkko Hietaniemi <jhi@iki.fi>2001-10-22 12:15:19 +0000
committerJarkko Hietaniemi <jhi@iki.fi>2001-10-22 12:15:19 +0000
commitb309b8ae430d85542056be4d1a80055ed0cb7b0e (patch)
tree16c900819c95157850c6d0cb3d86d46eae92c935 /win32
parent5a04aac43d82e938aa8c048274a0e4e842595586 (diff)
downloadperl-b309b8ae430d85542056be4d1a80055ed0cb7b0e.tar.gz
Integrate change #12559 from maintperl;
various fixes for system() and backticks under windows p4raw-link: @12559 on //depot/maint-5.6/perl: c196af81e4de7395bbcca7607214cb47be8a55c0 p4raw-id: //depot/perl@12563 p4raw-integrated: from //depot/maint-5.6/perl@12562 'merge in' win32/win32.c (@12146..)
Diffstat (limited to 'win32')
-rw-r--r--win32/win32.c113
1 files changed, 100 insertions, 13 deletions
diff --git a/win32/win32.c b/win32/win32.c
index 19bb1dc2e5..3ebf182b91 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -605,12 +605,27 @@ do_spawn2(char *cmd, int exectype)
strcpy(cmd2, cmd);
a = argv;
for (s = cmd2; *s;) {
+ bool in_quotes = FALSE;
while (*s && isSPACE(*s))
s++;
if (*s)
*(a++) = s;
- while (*s && !isSPACE(*s))
- s++;
+ while (*s) {
+ /* ignore doubled backslashes, or backslash+quote */
+ if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
+ s += 2;
+ }
+ /* keep track of when we're within quotes */
+ else if (*s == '"') {
+ s++;
+ in_quotes = !in_quotes;
+ }
+ /* break it up only at spaces that aren't in quotes */
+ else if (!in_quotes && isSPACE(*s))
+ break;
+ else
+ s++;
+ }
if (*s)
*s++ = '\0';
}
@@ -3047,26 +3062,94 @@ win32_chmod(const char *path, int mode)
static char *
-create_command_line(const char* command, const char * const *args)
+create_command_line(const char * const *args)
{
dTHX;
- int index;
- char *cmd, *ptr, *arg;
- STRLEN len = strlen(command) + 1;
+ int index, argc;
+ char *cmd, *ptr;
+ const char *arg;
+ STRLEN len = 0;
+ bool cmd_shell = FALSE;
+ bool extra_quotes = FALSE;
+
+ /* The NT cmd.exe shell has the following peculiarity that needs to be
+ * worked around. It strips a leading and trailing dquote when any
+ * of the following is true:
+ * 1. the /S switch was used
+ * 2. there are more than two dquotes
+ * 3. there is a special character from this set: &<>()@^|
+ * 4. no whitespace characters within the two dquotes
+ * 5. string between two dquotes isn't an executable file
+ * To work around this, we always add a leading and trailing dquote
+ * to the string, if the first argument is either "cmd.exe" or "cmd",
+ * and there were at least two or more arguments passed to cmd.exe
+ * (not including switches).
+ */
+ if (args[0]
+ && (stricmp(args[0], "cmd.exe") == 0
+ || stricmp(args[0], "cmd") == 0))
+ {
+ cmd_shell = TRUE;
+ len += 3;
+ }
- for (index = 0; (ptr = (char*)args[index]) != NULL; ++index)
- len += strlen(ptr) + 1;
+ DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
+ for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
+ STRLEN curlen = strlen(arg);
+ if (!(arg[0] == '"' && arg[curlen-1] == '"'))
+ len += 2; /* assume quoting needed (worst case) */
+ len += curlen + 1;
+ DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
+ }
+ DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
+ argc = index;
New(1310, cmd, len, char);
ptr = cmd;
- strcpy(ptr, command);
for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
- ptr += strlen(ptr);
- *ptr++ = ' ';
+ bool do_quote = 0;
+ STRLEN curlen = strlen(arg);
+
+ /* we want to protect arguments with spaces with dquotes,
+ * but only if they aren't already there */
+ if (!(arg[0] == '"' && arg[curlen-1] == '"')) {
+ STRLEN i = 0;
+ while (i < curlen) {
+ if (isSPACE(arg[i])) {
+ do_quote = 1;
+ break;
+ }
+ i++;
+ }
+ }
+
+ if (do_quote)
+ *ptr++ = '"';
+
strcpy(ptr, arg);
+ ptr += curlen;
+
+ if (do_quote)
+ *ptr++ = '"';
+
+ if (args[index+1])
+ *ptr++ = ' ';
+
+ if (cmd_shell && !extra_quotes
+ && (stricmp(arg, "/x/c") == 0 || stricmp(arg, "/c") == 0)
+ && (argc-1 > index+1)) /* two or more arguments to cmd.exe? */
+ {
+ *ptr++ = '"';
+ extra_quotes = TRUE;
+ }
}
+ if (extra_quotes)
+ *ptr++ = '"';
+
+ *ptr = '\0';
+
return cmd;
}
@@ -3229,8 +3312,7 @@ win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
PROCESS_INFORMATION ProcessInformation;
DWORD create = 0;
- char *cmd = create_command_line(cmdname, strcmp(cmdname, argv[0]) == 0
- ? &argv[1] : argv);
+ char *cmd = create_command_line(argv);
char *fullcmd = Nullch;
env = PerlEnv_get_childenv();
@@ -3277,6 +3359,8 @@ win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
create |= CREATE_NEW_CONSOLE;
}
+ DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
+ cmdname,cmd));
RETRY:
if (!CreateProcess(cmdname, /* search PATH to find executable */
cmd, /* executable, and its arguments */
@@ -3299,6 +3383,9 @@ RETRY:
fullcmd = qualified_path(cmdname);
if (fullcmd) {
cmdname = fullcmd;
+ DEBUG_p(PerlIO_printf(Perl_debug_log,
+ "Retrying [%s] with same args\n",
+ cmdname));
goto RETRY;
}
}