This fixes a hang in the WinTV 8.5 installer.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- programs/cmd/tests/test_cmdline.cmd | 19 +++-- programs/cmd/tests/test_cmdline.cmd.exp | 12 ++- programs/cmd/wcmdmain.c | 97 ++++++++++++------------- 3 files changed, 68 insertions(+), 60 deletions(-)
diff --git a/programs/cmd/tests/test_cmdline.cmd b/programs/cmd/tests/test_cmdline.cmd index 32a1ef2e48..7a7f8d7b63 100644 --- a/programs/cmd/tests/test_cmdline.cmd +++ b/programs/cmd/tests/test_cmdline.cmd @@ -183,12 +183,19 @@ echo ------- Testing CMD /C qualifier treatment ------------ rem no need for space after /c cmd /csay one cmd /c"say one" -rem ignore quote before qualifier -rem FIXME the next command in wine starts a sub-CMD -echo THIS FAILS: cmd "/c"say one -rem ignore anything before /c -rem FIXME the next command in wine starts a sub-CMD -echo THIS FAILS: cmd ignoreme/c say one +cmd /c"say one +cmd /c=say one +cmd /c,say one +cmd /c;say one +rem non-options are ignored before /c; quotes are not treated specially +cmd "/c"say one +cmd ignoreme/c say one +cmd abc "def ghi/c say one" +cmd -@$*'"/c say one +echo echo bar > foo.bat +cmd /qq/c foo +cmd /q "xyz /c foo" +del foo.bat
echo --------- Testing special characters -------------- echo @echo amp > "say&.bat" diff --git a/programs/cmd/tests/test_cmdline.cmd.exp b/programs/cmd/tests/test_cmdline.cmd.exp index 980f67411c..7978a249c9 100644 --- a/programs/cmd/tests/test_cmdline.cmd.exp +++ b/programs/cmd/tests/test_cmdline.cmd.exp @@ -90,8 +90,16 @@ Passed ------- Testing CMD /C qualifier treatment ------------ 0@space@ 1@space@ -THIS FAILS: cmd "/c"say one -THIS FAILS: cmd ignoreme/c say one +0@space@ +0@space@ +0@space@ +0@space@ +0@space@ +0@space@ +0@space@ +0@space@ +bar@space@ +bar@space@ --------- Testing special characters -------------- 0@space@ 0@space@ diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 90df222b16..2819f7fa99 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -2421,10 +2421,8 @@ void WCMD_free_commands(CMD_LIST *cmds) {
int __cdecl wmain (int argc, WCHAR *argvW[]) { - int args; WCHAR *cmdLine = NULL; WCHAR *cmd = NULL; - WCHAR *argPos = NULL; WCHAR string[1024]; WCHAR envvar[4]; BOOL promptNewLine = TRUE; @@ -2440,6 +2438,7 @@ int __cdecl wmain (int argc, WCHAR *argvW[]) RTL_OSVERSIONINFOEXW osv; char osver[50]; STARTUPINFOW startupInfo; + const WCHAR *arg;
if (!GetEnvironmentVariableW(comspecW, comspec, ARRAY_SIZE(comspec))) { @@ -2467,57 +2466,55 @@ int __cdecl wmain (int argc, WCHAR *argvW[]) */ cmdLine = GetCommandLineW(); WINE_TRACE("Full commandline '%s'\n", wine_dbgstr_w(cmdLine)); - args = 0; + + while (*cmdLine && *cmdLine != '/') ++cmdLine;
opt_c = opt_k = opt_q = opt_s = FALSE; - WCMD_parameter(cmdLine, args, &argPos, TRUE, TRUE); - while (argPos && argPos[0] != 0x00) - { - WCHAR c; - WINE_TRACE("Command line parm: '%s'\n", wine_dbgstr_w(argPos)); - if (argPos[0]!='/' || argPos[1]=='\0') { - args++; - WCMD_parameter(cmdLine, args, &argPos, TRUE, TRUE); - continue; - }
- c=argPos[1]; - if (towlower(c)=='c') { - opt_c = TRUE; - } else if (towlower(c)=='q') { - opt_q = TRUE; - } else if (towlower(c)=='k') { - opt_k = TRUE; - } else if (towlower(c)=='s') { - opt_s = TRUE; - } else if (towlower(c)=='a') { - unicodeOutput = FALSE; - } else if (towlower(c)=='u') { - unicodeOutput = TRUE; - } else if (towlower(c)=='v' && argPos[2]==':') { - delayedsubst = wcsnicmp(&argPos[3], offW, 3); - if (delayedsubst) WINE_TRACE("Delayed substitution is on\n"); - } else if (towlower(c)=='t' && argPos[2]==':') { - opt_t=wcstoul(&argPos[3], NULL, 16); - } else if (towlower(c)=='x' || towlower(c)=='y') { - /* Ignored for compatibility with Windows */ - } + for (arg = cmdLine; *arg; ++arg) + { + if (arg[0] != '/') + continue;
- if (argPos[2]==0 || argPos[2]==' ' || argPos[2]=='\t' || - towlower(c)=='v') { - args++; - WCMD_parameter(cmdLine, args, &argPos, TRUE, TRUE); - } - else /* handle `cmd /cnotepad.exe` and `cmd /x/c ...` */ - { - /* Do not step to next parameter, instead carry on parsing this one */ - argPos+=2; - } + switch (towlower(arg[1])) + { + case 'a': + unicodeOutput = FALSE; + break; + case 'c': + opt_c = TRUE; + break; + case 'k': + opt_k = TRUE; + break; + case 'q': + opt_q = TRUE; + break; + case 's': + opt_s = TRUE; + break; + case 't': + if (arg[2] == ':') + opt_t = wcstoul(&arg[3], NULL, 16); + break; + case 'u': + unicodeOutput = TRUE; + break; + case 'v': + if (arg[2] == ':') + delayedsubst = wcsnicmp(&arg[3], L"OFF", 3); + break; + }
- if (opt_c || opt_k) /* break out of parsing immediately after c or k */ - break; + if (opt_c || opt_k) + { + arg += 2; + break; + } }
+ while (*arg && wcschr(L" \t,=;", *arg)) arg++; + if (opt_q) { WCMD_echo(offW); } @@ -2531,12 +2528,8 @@ int __cdecl wmain (int argc, WCHAR *argvW[]) int len; WCHAR *q1 = NULL,*q2 = NULL,*p;
- /* Handle very edge case error scenario, "cmd.exe /c" ie when there are no - * parameters after the /C or /K by pretending there was a single space */ - if (argPos == NULL) argPos = (WCHAR *)spaceW; - /* Take a copy */ - cmd = heap_strdupW(argPos); + cmd = heap_strdupW(arg);
/* opt_s left unflagged if the command starts with and contains exactly * one quoted string (exactly two quote characters). The quoted string @@ -2545,7 +2538,7 @@ int __cdecl wmain (int argc, WCHAR *argvW[])
if (!opt_s) { /* 1. Confirm there is at least one quote */ - q1 = wcschr(argPos, '"'); + q1 = wcschr(arg, '"'); if (!q1) opt_s=1; }