[PATCH 2/2] [cmd] Fix basic cmd.exe /c "echo hello" type syntax

Ann and Jason Edmeades jason at edmeades.me.uk
Mon Oct 1 18:44:03 CDT 2012


Add checks for existance of command to run in order to keep the
new quote handling capabilities of cmd.exe /C or /K. If the command
cannot be found, drop back to /S processing mode as per cmd.exe help.

cmd.exe defaults /S off unless certain conditions are met - these
conditions are spelt out in cmd.exe /? help on windows. Specifically,
a command such as cmd.exe /c "echo hello" matches all the conditions
other than the string in quotes being an executable, which we do not
currently check.

[Fixes bug 21927 and possibly 25738]
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-patches/attachments/20121002/9ae54bc7/attachment.html>
-------------- next part --------------
From 87929ebfb7f68f179a103e917bc86278a991cbce Mon Sep 17 00:00:00 2001
From: Jason Edmeades <jason at edmeades.me.uk>
Date: Tue, 2 Oct 2012 00:35:47 +0100
Subject: [PATCH 2/2] [cmd] Fix basic cmd.exe /c "echo hello" type syntax

Add checks for existance of command to run in order to keep the
new quote handling capabilities of cmd.exe /C or /K. If the command
cannot be found, drop back to /S processing mode as per cmd.exe help.

cmd.exe defaults /S off unless certain conditions are met - these
conditions are spelt out in cmd.exe /? help on windows. Specifically,
a command such as cmd.exe /c "echo hello" matches all the conditions
other than the string in quotes being an executable, which we do not
currently check.

[Fixes bug 21927 and possibly 25738]
---
 programs/cmd/tests/test_builtins.cmd     |    1 +
 programs/cmd/tests/test_builtins.cmd.exp |    7 +--
 programs/cmd/wcmdmain.c                  |   71 +++++++++++++++++++++++++++++-
 3 files changed, 74 insertions(+), 5 deletions(-)

diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd
index 1c0f875..3e064b9 100644
--- a/programs/cmd/tests/test_builtins.cmd
+++ b/programs/cmd/tests/test_builtins.cmd
@@ -1829,6 +1829,7 @@ rem Basic test of command line. Note a section prefix per command
 rem to resync, as wine does not output anything in these cases yet.
 echo --- Test 1
 cmd.exe /c echo Line1
+cmd.exe /c echo "Line2"
 echo --- Test 2
 cmd.exe /c echo Test quotes "&" work
 echo --- Test 3
diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp
index e817706..6483f1e 100644
--- a/programs/cmd/tests/test_builtins.cmd.exp
+++ b/programs/cmd/tests/test_builtins.cmd.exp
@@ -910,6 +910,7 @@ value1
 ------------ cmd.exe command lines ------------
 --- Test 1
 Line1
+ at todo_wine@"Line2"
 --- Test 2
 @todo_wine at Test quotes "&" work
 --- Test 3
@@ -929,11 +930,11 @@ Line1
 --- Test 10
 --- Test 11
 --- Test 12
- at todo_wine@passed1
+passed1
 --- Test 13
- at todo_wine@passed2 at space@
+passed2 at space@
 --- Test 14
- at todo_wine@foobar
+foobar
 --- Test 15
 No prompts or I would not get here1
 No prompts or I would not get here2
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index 0e7a197..675256b 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -2419,10 +2419,12 @@ int wmain (int argc, WCHAR *argvW[])
           }
       }
 
+      /* If there is not exactly 2 quote characters, then /S (old behaviour) is enabled */
       if (qcount!=2)
           opt_s = TRUE;
 
-      /* check argvW[0] for a space and invalid characters */
+      /* check argvW[0] for a space and invalid characters. There must not be any invalid
+       * characters, but there must be one or more whitespace                             */
       if (!opt_s) {
           opt_s = TRUE;
           p=*argvW;
@@ -2432,7 +2434,7 @@ int wmain (int argc, WCHAR *argvW[])
                   opt_s = TRUE;
                   break;
               }
-              if (*p==' ')
+              if (*p==' ' || *p=='\t')
                   opt_s = FALSE;
               p++;
           }
@@ -2507,6 +2509,71 @@ int wmain (int argc, WCHAR *argvW[])
 
       WINE_TRACE("/c command line: '%s'\n", wine_dbgstr_w(cmd));
 
+      /* Finally, we only stay in new mode IF the first parameter is quoted and
+         is a valid executable, ie must exist, otherwise drop back to old mode  */
+      if (!opt_s) {
+        WCHAR *thisArg = WCMD_parameter(cmd, 0, NULL, NULL, FALSE);
+        static const WCHAR extEXEW[]    = {'.','e','x','e','\0'};
+        static const WCHAR extCOMW[]    = {'.','c','o','m','\0'};
+        BOOL found = FALSE;
+
+        /* If the supplied parameter has any directory information, look there */
+        WINE_TRACE("First parameter is '%s'\n", wine_dbgstr_w(thisArg));
+        if (strchrW(thisArg, '\\') != NULL) {
+
+          GetFullPathNameW(thisArg, sizeof(string)/sizeof(WCHAR), string, NULL);
+          WINE_TRACE("Full path name '%s'\n", wine_dbgstr_w(string));
+          p = string + strlenW(string);
+
+          /* Does file exist with this name? */
+          if (GetFileAttributesW(string) != INVALID_FILE_ATTRIBUTES) {
+            WINE_TRACE("Found file as '%s'\n", wine_dbgstr_w(string));
+            found = TRUE;
+          } else strcpyW(p, extEXEW);
+
+          /* Does file exist with .exe appended */
+          if (!found && GetFileAttributesW(string) != INVALID_FILE_ATTRIBUTES) {
+            WINE_TRACE("Found file as '%s'\n", wine_dbgstr_w(string));
+            found = TRUE;
+          } else strcpyW(p, extCOMW);
+
+          /* Does file exist with .com appended */
+          if (!found && GetFileAttributesW(string) != INVALID_FILE_ATTRIBUTES) {
+            WINE_TRACE("Found file as '%s'\n", wine_dbgstr_w(string));
+            found = TRUE;
+          }
+
+        /* Otherwise we now need to look in the path to see if we can find it */
+        } else {
+          p = thisArg + strlenW(thisArg);
+
+          /* Does file exist with this name? */
+          if (SearchPathW(NULL, thisArg, NULL, sizeof(string)/sizeof(WCHAR), string, NULL) != 0)  {
+            WINE_TRACE("Found on path as '%s'\n", wine_dbgstr_w(string));
+            found = TRUE;
+          }
+
+          /* Does file exist plus an extension of .exe? */
+          if (SearchPathW(NULL, thisArg, extEXEW, sizeof(string)/sizeof(WCHAR), string, NULL) != 0)  {
+            WINE_TRACE("Found on path as '%s'\n", wine_dbgstr_w(string));
+            found = TRUE;
+          }
+
+          /* Does file exist plus an extension of .com? */
+          if (SearchPathW(NULL, thisArg, extCOMW, sizeof(string)/sizeof(WCHAR), string, NULL) != 0)  {
+            WINE_TRACE("Found on path as '%s'\n", wine_dbgstr_w(string));
+            found = TRUE;
+          }
+        }
+
+        /* If not found, drop back to old behaviour */
+        if (!found) {
+          WINE_TRACE("Binary not found, dropping back to old behaviour\n");
+          opt_s = TRUE;
+        }
+
+      }
+
       /* strip first and last quote characters if opt_s; check for invalid
        * executable is done later */
       if (opt_s && *cmd=='\"')
-- 
1.7.9.5


More information about the wine-patches mailing list