Jason Edmeades : cmd.exe: Correctly parse IF ELSE plus multipart/multiline.

Alexandre Julliard julliard at wine.codeweavers.com
Mon Jun 18 08:05:15 CDT 2007


Module: wine
Branch: master
Commit: 345cb891752d6f594c488a371f702b013a6e7aca
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=345cb891752d6f594c488a371f702b013a6e7aca

Author: Jason Edmeades <jason.edmeades at googlemail.com>
Date:   Fri Jun 15 20:59:26 2007 +0100

cmd.exe: Correctly parse IF ELSE plus multipart/multiline.

---

 programs/cmd/wcmdmain.c |   49 +++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index 5ccd6d8..a9beb61 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -1909,12 +1909,17 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
     static WCHAR    *extraSpace = NULL;  /* Deliberately never freed */
     const WCHAR remCmd[] = {'r','e','m',' ','\0'};
     const WCHAR forCmd[] = {'f','o','r',' ','\0'};
+    const WCHAR ifCmd[]  = {'i','f',' ','\0'};
+    const WCHAR ifElse[] = {'e','l','s','e',' ','\0'};
     BOOL      inRem = FALSE;
     BOOL      inFor = FALSE;
+    BOOL      inIf  = FALSE;
+    BOOL      inElse= FALSE;
     BOOL      onlyWhiteSpace = FALSE;
     BOOL      lastWasWhiteSpace = FALSE;
-    BOOL      lastWasDo = FALSE;
-    BOOL      lastWasIn = FALSE;
+    BOOL      lastWasDo   = FALSE;
+    BOOL      lastWasIn   = FALSE;
+    BOOL      lastWasElse = FALSE;
 
     /* Allocate working space for a command read from keyboard, file etc */
     if (!extraSpace)
@@ -1952,7 +1957,7 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
 
      /* Certain commands need special handling */
       if (curLen == 0) {
-        const WCHAR forDO[] = {'d','o',' ','\0'};
+        const WCHAR forDO[]  = {'d','o',' ','\0'};
 
         /* If command starts with 'rem', ignore any &&, ( etc */
         if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
@@ -1964,6 +1969,26 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
           curPos, 4, forCmd, -1) == 2) {
           inFor = TRUE;
 
+        /* If command starts with 'if' or 'else', handle ('s mid line. We should ensure this
+           is only true in the command portion of the IF statement, but this
+           should suffice for now
+            FIXME: Silly syntax like "if 1(==1( (
+                                        echo they equal
+                                      )" will be parsed wrong */
+        } else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
+          curPos, 3, ifCmd, -1) == 2) {
+          inIf = TRUE;
+
+        } else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
+          curPos, 5, ifElse, -1) == 2) {
+          inElse = TRUE;
+          lastWasElse = TRUE;
+          onlyWhiteSpace = TRUE;
+          memcpy(&curString[curLen], curPos, 5*sizeof(WCHAR));
+          curLen+=5;
+          curPos+=5;
+          continue;
+
         /* In a for loop, the DO command will follow a close bracket followed by
            whitespace, followed by DO, ie closeBracket inserts a NULL entry, curLen
            is then 0, and all whitespace is skipped                                */
@@ -2025,10 +2050,12 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
                    ie start of line or just after &&, then we read until an
                    unquoted ) is found                                       */
                 WINE_TRACE("Found '(' conditions: curLen(%d), inQ(%d), onlyWS(%d)"
-                           ", for(%d, In:%d, Do:%d)\n",
+                           ", for(%d, In:%d, Do:%d)"
+                           ", if(%d, else:%d, lwe:%d)\n",
                            curLen, inQuotes,
                            onlyWhiteSpace,
-                           inFor, lastWasIn, lastWasDo);
+                           inFor, lastWasIn, lastWasDo,
+                           inIf, inElse, lastWasElse);
                 if (curLen == 0) {
                   curDepth++;
 
@@ -2037,8 +2064,15 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
                   curString[curLen++] = *curPos;
 
                 /* In a FOR loop, an unquoted '(' may occur straight after
-                   IN or DO                                                */
-                } else if (inFor && (lastWasIn || lastWasDo) && onlyWhiteSpace) {
+                      IN or DO
+                   In an IF statement just handle it regardless as we don't
+                      parse the operands
+                   In an ELSE statement, only allow it straight away after
+                      the ELSE and whitespace
+                 */
+                } else if (inIf ||
+                           (inElse && lastWasElse && onlyWhiteSpace) ||
+                           (inFor && (lastWasIn || lastWasDo) && onlyWhiteSpace)) {
 
                   /* Add the current command */
                   thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CMD_LIST));
@@ -2166,7 +2200,6 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
       /* If we have reached the end of the string, see if bracketing outstanding */
       if (*curPos == 0x00 && curDepth > 0 && readFrom != INVALID_HANDLE_VALUE) {
         inRem = FALSE;
-        inFor = FALSE;
         isAmphersand = FALSE;
         inQuotes = FALSE;
         memset(extraSpace, 0x00, (MAXSTRING+1) * sizeof(WCHAR));




More information about the wine-cvs mailing list