diff options
author | Jarkko Hietaniemi <jhi@iki.fi> | 2001-10-28 20:55:57 +0000 |
---|---|---|
committer | Jarkko Hietaniemi <jhi@iki.fi> | 2001-10-28 20:55:57 +0000 |
commit | dd7038b3248009b72165c22a9d4a9159e93f8cfc (patch) | |
tree | c0fc74522ea584cb066505650e796e0e644afa86 /win32 | |
parent | 61c9453e130c5bb36186ed0c540dcc8a5994e905 (diff) | |
download | perl-dd7038b3248009b72165c22a9d4a9159e93f8cfc.tar.gz |
Integrate change #12747 from maintperl;
finishing touches to system() fixes on windows:
* detect cmd shell correctly even if it had full path in it
* more quoting needed for single-arg system if the argument
really had multiple quoted arguments within it
* be smarter about not calling the shell when the executable
has spaces, but otherwise does not need shell involvement
* add a testsuite (windows-specific currently)
p4raw-link: @12747 on //depot/maint-5.6/perl: 2bab9a31df533a6c8068e22c59c8dfb29a47c95e
p4raw-id: //depot/perl@12748
p4raw-branched: from //depot/maint-5.6/perl@12746 'branch in'
t/op/system.t t/op/system_tests
p4raw-edited: from //depot/maint-5.6/perl@12746 'ignore'
pod/perltodo.pod (@8171..) MANIFEST (@11426..)
p4raw-integrated: from //depot/maint-5.6/perl@12746 'merge in'
win32/win32.c (@12725..)
Diffstat (limited to 'win32')
-rw-r--r-- | win32/win32.c | 134 |
1 files changed, 97 insertions, 37 deletions
diff --git a/win32/win32.c b/win32/win32.c index f50436e6bf..b23ce65c36 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -586,6 +586,30 @@ do_aspawn(void *vreally, void **vmark, void **vsp) return (status); } +/* returns pointer to the next unquoted space or the end of the string */ +static char* +find_next_space(const char *s) +{ + bool in_quotes = FALSE; + 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)) + return (char*)s; + else + s++; + } + return (char*)s; +} + int do_spawn2(char *cmd, int exectype) { @@ -605,27 +629,11 @@ 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) { - /* 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++; - } + s = find_next_space(s); if (*s) *s++ = '\0'; } @@ -3092,7 +3100,7 @@ win32_chmod(const char *path, int mode) static char * -create_command_line(const char *cmdname, const char * const *args) +create_command_line(char *cname, STRLEN clen, const char * const *args) { dTHX; int index, argc; @@ -3102,7 +3110,7 @@ create_command_line(const char *cmdname, const char * const *args) bool bat_file = FALSE; bool cmd_shell = FALSE; bool extra_quotes = FALSE; - char *cname = (char*)cmdname; + bool quote_next = FALSE; if (!cname) cname = (char*)args[0]; @@ -3119,9 +3127,13 @@ create_command_line(const char *cmdname, const char * const *args) * 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). + * XXX the above rules (from "cmd /?") don't seem to be applied + * always, making for the convolutions below :-( */ if (cname) { - STRLEN clen = strlen(cname); + if (!clen) + clen = strlen(cname); + if (clen > 4 && (stricmp(&cname[clen-4], ".bat") == 0 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0))) @@ -3129,11 +3141,19 @@ create_command_line(const char *cmdname, const char * const *args) bat_file = TRUE; len += 3; } - else if (stricmp(cname, "cmd.exe") == 0 - || stricmp(cname, "cmd") == 0) - { - cmd_shell = TRUE; - len += 3; + else { + char *exe = strrchr(cname, '/'); + char *exe2 = strrchr(cname, '\\'); + if (exe2 > exe) + exe = exe2; + if (exe) + ++exe; + else + exe = cname; + if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) { + cmd_shell = TRUE; + len += 3; + } } } @@ -3175,6 +3195,13 @@ create_command_line(const char *cmdname, const char * const *args) i++; } } + else if (quote_next) { + /* ok, we know the argument already has quotes; see if it + * really is multiple arguments pretending to be one and + * force a set of quotes around it */ + if (*find_next_space(arg)) + do_quote = 1; + } if (do_quote) *ptr++ = '"'; @@ -3190,11 +3217,20 @@ create_command_line(const char *cmdname, const char * const *args) if (!extra_quotes && cmd_shell - && (stricmp(arg, "/x/c") == 0 || stricmp(arg, "/c") == 0) - && (argc-1 > index+1)) /* two or more arguments to cmd.exe? */ + && (stricmp(arg, "/x/c") == 0 || stricmp(arg, "/c") == 0)) { - *ptr++ = '"'; - extra_quotes = TRUE; + /* is there a next argument? */ + if (args[index+1]) { + /* are there two or more next arguments? */ + if (args[index+2]) { + *ptr++ = '"'; + extra_quotes = TRUE; + } + else { + /* single argument, force quoting if unquoted */ + quote_next = TRUE; + } + } } } @@ -3384,9 +3420,30 @@ win32_spawnvp(int mode, const char *cmdname, const char *const *argv) STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInformation; DWORD create = 0; - - char *cmd = create_command_line(cmdname, argv); + char *cmd; char *fullcmd = Nullch; + char *cname = (char *)cmdname; + STRLEN clen = 0; + + if (cname) { + clen = strlen(cname); + /* if command name contains dquotes, must remove them */ + if (strchr(cname, '"')) { + cmd = cname; + New(0,cname,clen+1,char); + clen = 0; + while (*cmd) { + if (*cmd != '"') { + cname[clen] = *cmd; + ++clen; + } + ++cmd; + } + cname[clen] = '\0'; + } + } + + cmd = create_command_line(cname, clen, argv); env = PerlEnv_get_childenv(); dir = PerlEnv_get_childdir(); @@ -3433,9 +3490,9 @@ win32_spawnvp(int mode, const char *cmdname, const char *const *argv) } DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n", - cmdname,cmd)); + cname,cmd)); RETRY: - if (!CreateProcess(cmdname, /* search PATH to find executable */ + if (!CreateProcess(cname, /* search PATH to find executable */ cmd, /* executable, and its arguments */ NULL, /* process attributes */ NULL, /* thread attributes */ @@ -3453,12 +3510,14 @@ RETRY: * jump through our own hoops by picking out the path * we really want it to use. */ if (!fullcmd) { - fullcmd = qualified_path(cmdname); + fullcmd = qualified_path(cname); if (fullcmd) { - cmdname = fullcmd; + if (cname != cmdname) + Safefree(cname); + cname = fullcmd; DEBUG_p(PerlIO_printf(Perl_debug_log, "Retrying [%s] with same args\n", - cmdname)); + cname)); goto RETRY; } } @@ -3491,7 +3550,8 @@ RETVAL: PerlEnv_free_childenv(env); PerlEnv_free_childdir(dir); Safefree(cmd); - Safefree(fullcmd); + if (cname != cmdname) + Safefree(cname); return ret; #endif } |