RESEND [PATCH 08/11] CMD.exe: Correctly parse IF ELSE plus multipart/multiline

Jason Edmeades jason.edmeades at googlemail.com
Fri Jun 15 14:59:26 CDT 2007


Note the handling of the multipart/multiline is wrong, but the
parsed output is almost correct. It fails to handle one silly case,
if an '(' outside of double quotes as part of the expression, but
it did not seem a case worth worrying about for now
---
 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));
-- 
1.5.0




More information about the wine-patches mailing list