Zebediah Figura : cmd: Ignore quotes when parsing command line parameters.
Alexandre Julliard
julliard at winehq.org
Mon Apr 27 15:19:28 CDT 2020
Module: wine
Branch: master
Commit: 2e45fdb194efe383189c9ce44c6c51b4be837c79
URL: https://source.winehq.org/git/wine.git/?a=commit;h=2e45fdb194efe383189c9ce44c6c51b4be837c79
Author: Zebediah Figura <z.figura12 at gmail.com>
Date: Sat Apr 25 22:53:38 2020 -0500
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 at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
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 at space@
1 at space@
-THIS FAILS: cmd "/c"say one
-THIS FAILS: cmd ignoreme/c say one
+0 at space@
+0 at space@
+0 at space@
+0 at space@
+0 at space@
+0 at space@
+0 at space@
+0 at space@
+bar at space@
+bar at space@
--------- Testing special characters --------------
0 at space@
0 at 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;
}
More information about the wine-cvs
mailing list