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