cmd: Ignore quotes when parsing command line parameters.

This fixes a hang in the WinTV 8.5 installer.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Zebediah Figura 2020-04-25 22:53:38 -05:00 committed by Alexandre Julliard
parent 16c938cb66
commit 2e45fdb194
3 changed files with 68 additions and 60 deletions

View File

@ -183,12 +183,19 @@ echo ------- Testing CMD /C qualifier treatment ------------
rem no need for space after /c rem no need for space after /c
cmd /csay one cmd /csay one
cmd /c"say one" cmd /c"say one"
rem ignore quote before qualifier cmd /c"say one
rem FIXME the next command in wine starts a sub-CMD cmd /c=say one
echo THIS FAILS: cmd "/c"say one cmd /c,say one
rem ignore anything before /c cmd /c;say one
rem FIXME the next command in wine starts a sub-CMD rem non-options are ignored before /c; quotes are not treated specially
echo THIS FAILS: cmd ignoreme/c say one 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 --------- Testing special characters --------------
echo @echo amp > "say&.bat" echo @echo amp > "say&.bat"

View File

@ -90,8 +90,16 @@ Passed
------- Testing CMD /C qualifier treatment ------------ ------- Testing CMD /C qualifier treatment ------------
0@space@ 0@space@
1@space@ 1@space@
THIS FAILS: cmd "/c"say one 0@space@
THIS FAILS: cmd ignoreme/c say one 0@space@
0@space@
0@space@
0@space@
0@space@
0@space@
0@space@
bar@space@
bar@space@
--------- Testing special characters -------------- --------- Testing special characters --------------
0@space@ 0@space@
0@space@ 0@space@

View File

@ -2421,10 +2421,8 @@ void WCMD_free_commands(CMD_LIST *cmds) {
int __cdecl wmain (int argc, WCHAR *argvW[]) int __cdecl wmain (int argc, WCHAR *argvW[])
{ {
int args;
WCHAR *cmdLine = NULL; WCHAR *cmdLine = NULL;
WCHAR *cmd = NULL; WCHAR *cmd = NULL;
WCHAR *argPos = NULL;
WCHAR string[1024]; WCHAR string[1024];
WCHAR envvar[4]; WCHAR envvar[4];
BOOL promptNewLine = TRUE; BOOL promptNewLine = TRUE;
@ -2440,6 +2438,7 @@ int __cdecl wmain (int argc, WCHAR *argvW[])
RTL_OSVERSIONINFOEXW osv; RTL_OSVERSIONINFOEXW osv;
char osver[50]; char osver[50];
STARTUPINFOW startupInfo; STARTUPINFOW startupInfo;
const WCHAR *arg;
if (!GetEnvironmentVariableW(comspecW, comspec, ARRAY_SIZE(comspec))) if (!GetEnvironmentVariableW(comspecW, comspec, ARRAY_SIZE(comspec)))
{ {
@ -2467,57 +2466,55 @@ int __cdecl wmain (int argc, WCHAR *argvW[])
*/ */
cmdLine = GetCommandLineW(); cmdLine = GetCommandLineW();
WINE_TRACE("Full commandline '%s'\n", wine_dbgstr_w(cmdLine)); 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; opt_c = opt_k = opt_q = opt_s = FALSE;
WCMD_parameter(cmdLine, args, &argPos, TRUE, TRUE);
while (argPos && argPos[0] != 0x00) for (arg = cmdLine; *arg; ++arg)
{ {
WCHAR c; if (arg[0] != '/')
WINE_TRACE("Command line parm: '%s'\n", wine_dbgstr_w(argPos)); continue;
if (argPos[0]!='/' || argPos[1]=='\0') {
args++;
WCMD_parameter(cmdLine, args, &argPos, TRUE, TRUE);
continue;
}
c=argPos[1]; switch (towlower(arg[1]))
if (towlower(c)=='c') { {
opt_c = TRUE; case 'a':
} else if (towlower(c)=='q') { unicodeOutput = FALSE;
opt_q = TRUE; break;
} else if (towlower(c)=='k') { case 'c':
opt_k = TRUE; opt_c = TRUE;
} else if (towlower(c)=='s') { break;
opt_s = TRUE; case 'k':
} else if (towlower(c)=='a') { opt_k = TRUE;
unicodeOutput = FALSE; break;
} else if (towlower(c)=='u') { case 'q':
unicodeOutput = TRUE; opt_q = TRUE;
} else if (towlower(c)=='v' && argPos[2]==':') { break;
delayedsubst = wcsnicmp(&argPos[3], offW, 3); case 's':
if (delayedsubst) WINE_TRACE("Delayed substitution is on\n"); opt_s = TRUE;
} else if (towlower(c)=='t' && argPos[2]==':') { break;
opt_t=wcstoul(&argPos[3], NULL, 16); case 't':
} else if (towlower(c)=='x' || towlower(c)=='y') { if (arg[2] == ':')
/* Ignored for compatibility with Windows */ 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 (argPos[2]==0 || argPos[2]==' ' || argPos[2]=='\t' || if (opt_c || opt_k)
towlower(c)=='v') { {
args++; arg += 2;
WCMD_parameter(cmdLine, args, &argPos, TRUE, TRUE); break;
} }
else /* handle `cmd /cnotepad.exe` and `cmd /x/c ...` */
{
/* Do not step to next parameter, instead carry on parsing this one */
argPos+=2;
}
if (opt_c || opt_k) /* break out of parsing immediately after c or k */
break;
} }
while (*arg && wcschr(L" \t,=;", *arg)) arg++;
if (opt_q) { if (opt_q) {
WCMD_echo(offW); WCMD_echo(offW);
} }
@ -2531,12 +2528,8 @@ int __cdecl wmain (int argc, WCHAR *argvW[])
int len; int len;
WCHAR *q1 = NULL,*q2 = NULL,*p; 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 */ /* Take a copy */
cmd = heap_strdupW(argPos); cmd = heap_strdupW(arg);
/* opt_s left unflagged if the command starts with and contains exactly /* opt_s left unflagged if the command starts with and contains exactly
* one quoted string (exactly two quote characters). The quoted string * one quoted string (exactly two quote characters). The quoted string
@ -2545,7 +2538,7 @@ int __cdecl wmain (int argc, WCHAR *argvW[])
if (!opt_s) { if (!opt_s) {
/* 1. Confirm there is at least one quote */ /* 1. Confirm there is at least one quote */
q1 = wcschr(argPos, '"'); q1 = wcschr(arg, '"');
if (!q1) opt_s=1; if (!q1) opt_s=1;
} }