[PATCH 11/12] CMD.exe: Fix FOR so it works as 'well' as before

Jason Edmeades jason.edmeades at googlemail.com
Thu Jun 14 17:06:47 CDT 2007


After this patch almost all my testcases (see 0th patch) work, except
one, which is certainly good enough to submit. This resolves a number
of issues, and makes the IF and FOR processing of the multipart/multiline
commands into a single function
---
 programs/cmd/batch.c    |   20 +---
 programs/cmd/builtins.c |  339 ++++++++++++++++++++++++++++++-----------------
 programs/cmd/wcmd.h     |    9 +-
 programs/cmd/wcmdmain.c |   61 ++++++---
 4 files changed, 272 insertions(+), 157 deletions(-)

diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c
index 0990b7e..8f0187c 100644
--- a/programs/cmd/batch.c
+++ b/programs/cmd/batch.c
@@ -109,7 +109,7 @@ void WCMD_batch (WCHAR *file, WCHAR *command, int called, WCHAR *startLabel, HAN
       CMD_LIST *toExecute = NULL;         /* Commands left to be executed */
       if (WCMD_ReadAndParseLine(NULL, &toExecute, h) == NULL)
         break;
-      WCMD_process_commands(toExecute, FALSE);
+      WCMD_process_commands(toExecute, FALSE, NULL, NULL);
       WCMD_free_commands(toExecute);
       toExecute = NULL;
   }
@@ -168,21 +168,9 @@ WCHAR *WCMD_parameter (WCHAR *s, int n, WCHAR **where) {
           i++;
         p = param;
 	break;
-      case '(':
-        if (where != NULL && i==n) *where = s;
-	s++;
-	while ((*s != '\0') && (*s != ')')) {
-	  *p++ = *s++;
-	}
-        if (i == n) {
-          *p = '\0';
-          return param;
-        }
-	if (*s == ')') s++;
-          param[0] = '\0';
-          i++;
-        p = param;
-	break;
+      /* The code to handle bracketed parms is removed because it should no longer
+         be necessary after the multiline support has been added and the for loop
+         set of data is now parseable individually. */
       case '\0':
         return param;
       default:
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 0f10d05..add4cce 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -40,7 +40,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(cmd);
 
-void WCMD_execute (WCHAR *orig_command, WCHAR *parameter, WCHAR *substitution, CMD_LIST **cmdList);
+static void WCMD_part_execute(CMD_LIST **commands, WCHAR *firstcmd, WCHAR *variable,
+                               WCHAR *value, BOOL isIF, BOOL conditionTRUE);
 
 struct env_stack *saved_environment;
 struct env_stack *pushd_directories;
@@ -571,6 +572,12 @@ void WCMD_echo (const WCHAR *command) {
  * WCMD_for
  *
  * Batch file loop processing.
+ *
+ * On entry: cmdList       contains the syntax up to the set
+ *           next cmdList and all in that bracket contain the set data
+ *           next cmdlist  contains the DO cmd
+ *           following that is either brackets or && entries (as per if)
+ *
  * FIXME: We don't exhaustively check syntax. Any command which works in MessDOS
  * will probably work here, but the reverse is not necessarily the case...
  */
@@ -579,45 +586,211 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) {
 
   WIN32_FIND_DATA fd;
   HANDLE hff;
-  WCHAR *cmd, *item;
-  WCHAR set[MAX_PATH], param[MAX_PATH];
   int i;
   const WCHAR inW[] = {'i', 'n', '\0'};
-  const WCHAR doW[] = {'d', 'o', '\0'};
-
+  const WCHAR doW[] = {'d', 'o', ' ','\0'};
+  CMD_LIST *setStart, *thisSet, *cmdStart, *cmdEnd;
+  WCHAR variable[4];
+  WCHAR *firstCmd;
+  int thisDepth;
+
+  /* Check:
+     the first line includes the % variable name as first parm
+     we have been provided with more parts to the command
+     and there is at least some set data
+     and IN as the one after that                                   */
   if (lstrcmpiW (WCMD_parameter (p, 1, NULL), inW)
-	|| lstrcmpiW (WCMD_parameter (p, 3, NULL), doW)
-	|| (param1[0] != '%')) {
+      || (*cmdList) == NULL
+      || (*cmdList)->nextcommand == NULL
+      || (param1[0] != '%')
+      || (strlenW(param1) > 3)) {
     WCMD_output (WCMD_LoadMessage(WCMD_SYNTAXERR));
     return;
   }
-  lstrcpynW (set, WCMD_parameter (p, 2, NULL), sizeof(set)/sizeof(WCHAR));
-  WCMD_parameter (p, 4, &cmd);
-  strcpyW (param, param1);
 
-/*
- *	If the parameter within the set has a wildcard then search for matching files
- *	otherwise do a literal substitution.
- */
+  /* Save away where the set of data starts and the variable */
+  strcpyW(variable, param1);
+  thisDepth = (*cmdList)->bracketDepth;
+  *cmdList = (*cmdList)->nextcommand;
+  setStart = (*cmdList);
 
-  i = 0;
-  while (*(item = WCMD_parameter (set, i, NULL))) {
-    static const WCHAR wildcards[] = {'*','?','\0'};
-    if (strpbrkW (item, wildcards)) {
-      hff = FindFirstFile (item, &fd);
-      if (hff == INVALID_HANDLE_VALUE) {
-	return;
+  /* Skip until the close bracket */
+  WINE_TRACE("Searching %p as the set\n", *cmdList);
+  while (*cmdList &&
+         (*cmdList)->command != NULL &&
+         (*cmdList)->bracketDepth > thisDepth) {
+    WINE_TRACE("Skipping %p which is part of the set\n", *cmdList);
+    *cmdList = (*cmdList)->nextcommand;
+  }
+
+  /* Skip the close bracket, if there is one */
+  if (*cmdList) *cmdList = (*cmdList)->nextcommand;
+
+  /* Syntax error if missing close bracket, or nothing following it
+     and once we have the complete set, we expect a DO              */
+  WINE_TRACE("Looking for 'do' in %p\n", *cmdList);
+  if ((*cmdList == NULL) ||
+      (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
+                            (*cmdList)->command, 3, doW, -1) != 2)) {
+      WCMD_output (WCMD_LoadMessage(WCMD_SYNTAXERR));
+      return;
+  }
+
+  /* Save away the starting position for the commands (and offset for the
+     first one                                                           */
+  cmdStart = *cmdList;
+  cmdEnd   = *cmdList;
+  firstCmd = (*cmdList)->command + 3; /* Skip 'do ' */
+
+  thisSet = setStart;
+  /* Loop through all set entries */
+  while (thisSet &&
+         thisSet->command != NULL &&
+         thisSet->bracketDepth >= thisDepth) {
+
+    /* Loop through all entries on the same line */
+    WCHAR *item;
+
+    WINE_TRACE("Processing for set %p\n", thisSet);
+    i = 0;
+    while (*(item = WCMD_parameter (thisSet->command, i, NULL))) {
+
+      /*
+       * If the parameter within the set has a wildcard then search for matching files
+       * otherwise do a literal substitution.
+       */
+      static const WCHAR wildcards[] = {'*','?','\0'};
+      CMD_LIST *thisCmdStart = cmdStart;
+
+      WINE_TRACE("Processing for item '%s'\n", wine_dbgstr_w(item));
+      if (strpbrkW (item, wildcards)) {
+        hff = FindFirstFile (item, &fd);
+        if (hff != INVALID_HANDLE_VALUE) {
+          do {
+            thisCmdStart = cmdStart;
+            WINE_TRACE("Processing FOR filename %s\n", wine_dbgstr_w(fd.cFileName));
+            WCMD_part_execute (&thisCmdStart, firstCmd, variable,
+                                         fd.cFileName, FALSE, TRUE);
+
+          } while (FindNextFile(hff, &fd) != 0);
+          FindClose (hff);
+        }
+      } else {
+        WCMD_part_execute(&thisCmdStart, firstCmd, variable, item, FALSE, TRUE);
       }
-      do {
-	WCMD_execute (cmd, param, fd.cFileName, cmdList);
-      } while (FindNextFile(hff, &fd) != 0);
-      FindClose (hff);
+
+      WINE_TRACE("Post-command, cmdEnd = %p\n", cmdEnd);
+      cmdEnd = thisCmdStart;
+      i++;
     }
-    else {
-      WCMD_execute (cmd, param, item, cmdList);
+
+    /* Move onto the next set line */
+    thisSet = thisSet->nextcommand;
+  }
+
+  /* When the loop ends, either something like a GOTO or EXIT /b has terminated
+     all processing, OR it should be pointing to the end of && processing OR
+     it should be pointing at the NULL end of bracket for the DO. The return
+     value needs to be the NEXT command to execute, which it either is, or
+     we need to step over the closing bracket                                  */
+  *cmdList = cmdEnd;
+  if (cmdEnd && cmdEnd->command == NULL) *cmdList = cmdEnd->nextcommand;
+}
+
+
+/*****************************************************************************
+ * WCMD_part_execute
+ *
+ * Execute a command, and any && or bracketed follow on to the command. The
+ * first command to be executed may not be at the front of the
+ * commands->thiscommand string (eg. it may point after a DO or ELSE
+ * Returns TRUE if something like exit or goto has aborted all processing
+ */
+void WCMD_part_execute(CMD_LIST **cmdList, WCHAR *firstcmd, WCHAR *variable,
+                       WCHAR *value, BOOL isIF, BOOL conditionTRUE) {
+
+  CMD_LIST *curPosition = *cmdList;
+  int myDepth = (*cmdList)->bracketDepth;
+
+  WINE_TRACE("cmdList(%p), firstCmd(%p), with '%s'='%s', doIt(%d)\n",
+             cmdList, wine_dbgstr_w(firstcmd),
+             wine_dbgstr_w(variable), wine_dbgstr_w(value),
+             conditionTRUE);
+
+  /* Skip leading whitespace between condition and the command */
+  while (firstcmd && *firstcmd && (*firstcmd==' ' || *firstcmd=='\t')) firstcmd++;
+
+  /* Process the first command, if there is one */
+  if (conditionTRUE && firstcmd && *firstcmd) {
+    WCHAR *command = WCMD_strdupW(firstcmd);
+    WCMD_execute (firstcmd, variable, value, cmdList);
+    free (command);
+  }
+
+
+  /* If it didnt move the position, step to next command */
+  if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
+
+  /* Process any other parts of the command */
+  if (*cmdList) {
+    BOOL processThese = TRUE;
+
+    if (isIF) processThese = conditionTRUE;
+
+    while (*cmdList) {
+      const WCHAR ifElse[] = {'e','l','s','e',' ','\0'};
+
+      /* execute all appropriate commands */
+      curPosition = *cmdList;
+
+      WINE_TRACE("Processing cmdList(%p) - &(%d) bd(%d / %d)\n",
+                 *cmdList,
+                 (*cmdList)->isAmphersand,
+                 (*cmdList)->bracketDepth, myDepth);
+
+      /* Execute any appended to the statement with &&'s */
+      if ((*cmdList)->isAmphersand) {
+        if (processThese) {
+          WCMD_execute ((*cmdList)->command, variable, value, cmdList);
+        }
+        if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
+
+      /* Execute any appended to the statement with (...) */
+      } else if ((*cmdList)->bracketDepth > myDepth) {
+        if (processThese) {
+          *cmdList = WCMD_process_commands(*cmdList, TRUE, variable, value);
+          WINE_TRACE("Back from processing commands, (next = %p)\n", *cmdList);
+        }
+        if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
+
+      /* End of the command - does 'ELSE ' follow as the next command? */
+      } else {
+        if (isIF && CompareString (LOCALE_USER_DEFAULT,
+                                   NORM_IGNORECASE | SORT_STRINGSORT,
+                           (*cmdList)->command, 5, ifElse, -1) == 2) {
+
+          /* Swap between if and else processing */
+          processThese = !processThese;
+
+          /* Process the ELSE part */
+          if (processThese) {
+            WCHAR *cmd = ((*cmdList)->command) + strlenW(ifElse);
+
+            /* Skip leading whitespace between condition and the command */
+            while (*cmd && (*cmd==' ' || *cmd=='\t')) cmd++;
+            if (*cmd) {
+              WCMD_execute (cmd, variable, value, cmdList);
+            }
+          }
+          if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
+        } else {
+          WINE_TRACE("Found end of this IF statement (next = %p)\n", *cmdList);
+          break;
+        }
+      }
     }
-    i++;
   }
+  return;
 }
 
 /*****************************************************************************
@@ -631,22 +804,26 @@ void WCMD_execute (WCHAR *orig_cmd, WCHAR *param, WCHAR *subst, CMD_LIST **cmdLi
   WCHAR *new_cmd, *p, *s, *dup;
   int size;
 
-  size = strlenW (orig_cmd);
-  new_cmd = (WCHAR *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, size);
-  dup = s = WCMD_strdupW(orig_cmd);
-
-  while ((p = strstrW (s, param))) {
-    *p = '\0';
-    size += strlenW (subst);
-    new_cmd = (WCHAR *) LocalReAlloc ((HANDLE)new_cmd, size, 0);
+  if (param) {
+    size = (strlenW (orig_cmd) + 1) * sizeof(WCHAR);
+    new_cmd = (WCHAR *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, size);
+    dup = s = WCMD_strdupW(orig_cmd);
+
+    while ((p = strstrW (s, param))) {
+      *p = '\0';
+      size += strlenW (subst) * sizeof(WCHAR);
+      new_cmd = (WCHAR *) LocalReAlloc ((HANDLE)new_cmd, size, 0);
+      strcatW (new_cmd, s);
+      strcatW (new_cmd, subst);
+      s = p + strlenW (param);
+    }
     strcatW (new_cmd, s);
-    strcatW (new_cmd, subst);
-    s = p + strlenW (param);
+    WCMD_process_command (new_cmd, cmdList);
+    free (dup);
+    LocalFree ((HANDLE)new_cmd);
+  } else {
+    WCMD_process_command (orig_cmd, cmdList);
   }
-  strcatW (new_cmd, s);
-  WCMD_process_command (new_cmd, cmdList);
-  free (dup);
-  LocalFree ((HANDLE)new_cmd);
 }
 
 
@@ -810,8 +987,6 @@ void WCMD_if (WCHAR *p, CMD_LIST **cmdList) {
   static const WCHAR existW[]  = {'e','x','i','s','t','\0'};
   static const WCHAR defdW[]   = {'d','e','f','i','n','e','d','\0'};
   static const WCHAR eqeqW[]   = {'=','=','\0'};
-  CMD_LIST *curPosition;
-  int myDepth;
 
   if (!lstrcmpiW (param1, notW)) {
     negate = 1;
@@ -848,81 +1023,7 @@ void WCMD_if (WCHAR *p, CMD_LIST **cmdList) {
 
   /* Process rest of IF statement which is on the same line
      Note: This may process all or some of the cmdList (eg a GOTO) */
-  curPosition = *cmdList;
-  myDepth     = (*cmdList)->bracketDepth;
-
-  if (test != negate) {
-    WCHAR *cmd = command;
-
-    /* Skip leading whitespace between condition and the command */
-    while (cmd && *cmd && (*cmd==' ' || *cmd=='\t')) cmd++;
-
-    if (cmd && *cmd) {
-      command = WCMD_strdupW(cmd);
-      WCMD_process_command (command, cmdList);
-      free (command);
-    }
-  }
-
-  /* If it didnt move the position, step to next command */
-  if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
-
-  /* Process any other parts of the IF */
-  if (*cmdList) {
-    BOOL processThese = (test != negate);
-
-    while (*cmdList) {
-      const WCHAR ifElse[] = {'e','l','s','e',' ','\0'};
-
-      /* execute all appropriate commands */
-      curPosition = *cmdList;
-
-      WINE_TRACE("Processing cmdList(%p) - &(%d) bd(%d / %d)\n",
-                 *cmdList,
-                 (*cmdList)->isAmphersand,
-                 (*cmdList)->bracketDepth, myDepth);
-
-      /* Execute any appended to the statement with &&'s */
-      if ((*cmdList)->isAmphersand) {
-        if (processThese) {
-          WCMD_process_command((*cmdList)->command, cmdList);
-        }
-        if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
-
-      /* Execute any appended to the statement with (...) */
-      } else if ((*cmdList)->bracketDepth > myDepth) {
-        if (processThese) {
-          *cmdList = WCMD_process_commands(*cmdList, TRUE);
-          WINE_TRACE("Back from processing commands, (next = %p)\n", *cmdList);
-        }
-        if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
-
-      /* End of the command - does 'ELSE ' follow as the next command? */
-      } else {
-        if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
-                           (*cmdList)->command, 5, ifElse, -1) == 2) {
-
-            /* Swap between if and else processing */
-            processThese = !processThese;
-
-            /* Process the ELSE part */
-            if (processThese) {
-              WCHAR *cmd = ((*cmdList)->command) + strlenW(ifElse);
-
-              /* Skip leading whitespace between condition and the command */
-              while (*cmd && (*cmd==' ' || *cmd=='\t')) cmd++;
-              if (*cmd) {
-                WCMD_process_command(cmd, cmdList);
-              }
-            }
-            if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand;
-        } else {
-          WINE_TRACE("Found end of this IF statement (next = %p)\n", *cmdList);
-          break;
-        }
-      }
-    }
-  }
+  WCMD_part_execute(cmdList, command, NULL, NULL, TRUE, (test != negate));
 }
 
 /****************************************************************************
diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h
index 90f0179..0781fb6 100644
--- a/programs/cmd/wcmd.h
+++ b/programs/cmd/wcmd.h
@@ -62,7 +62,7 @@ void WCMD_output (const WCHAR *format, ...);
 void WCMD_output_asis (const WCHAR *message);
 void WCMD_parse (WCHAR *s, WCHAR *q, WCHAR *p1, WCHAR *p2);
 void WCMD_pause (void);
-void WCMD_pipe (CMD_LIST **command);
+void WCMD_pipe (CMD_LIST **command, WCHAR *var, WCHAR *val);
 void WCMD_popd (void);
 void WCMD_print_error (void);
 void WCMD_process_command (WCHAR *command, CMD_LIST **cmdList);
@@ -101,9 +101,10 @@ WCHAR *WCMD_strdupW(WCHAR *input);
 BOOL WCMD_ReadFile(const HANDLE hIn, WCHAR *intoBuf, const DWORD maxChars,
                    LPDWORD charsRead, const LPOVERLAPPED unused);
 
-WCHAR *WCMD_ReadAndParseLine(WCHAR *initialcmd, CMD_LIST **output, HANDLE readFrom);
-CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket);
-void   WCMD_free_commands(CMD_LIST *cmds);
+WCHAR    *WCMD_ReadAndParseLine(WCHAR *initialcmd, CMD_LIST **output, HANDLE readFrom);
+CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket, WCHAR *var, WCHAR *val);
+void      WCMD_free_commands(CMD_LIST *cmds);
+void      WCMD_execute (WCHAR *orig_command, WCHAR *parameter, WCHAR *substitution, CMD_LIST **cmdList);
 
 /*	Data structure to hold context when executing batch files */
 
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index 0a9c4d2..36b8612 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -324,7 +324,7 @@ int wmain (int argc, WCHAR *argvW[])
 
       /* Parse the command string, without reading any more input */
       WCMD_ReadAndParseLine(cmd, &toExecute, INVALID_HANDLE_VALUE);
-      WCMD_process_commands(toExecute, FALSE);
+      WCMD_process_commands(toExecute, FALSE, NULL, NULL);
       WCMD_free_commands(toExecute);
       toExecute = NULL;
 
@@ -417,7 +417,7 @@ int wmain (int argc, WCHAR *argvW[])
   if (opt_k) {
       /* Parse the command string, without reading any more input */
       WCMD_ReadAndParseLine(cmd, &toExecute, INVALID_HANDLE_VALUE);
-      WCMD_process_commands(toExecute, FALSE);
+      WCMD_process_commands(toExecute, FALSE, NULL, NULL);
       WCMD_free_commands(toExecute);
       toExecute = NULL;
       HeapFree(GetProcessHeap(), 0, cmd);
@@ -449,7 +449,7 @@ int wmain (int argc, WCHAR *argvW[])
     if (WCMD_ReadAndParseLine(NULL, &toExecute,
                               GetStdHandle(STD_INPUT_HANDLE)) == NULL)
       break;
-    WCMD_process_commands(toExecute, FALSE);
+    WCMD_process_commands(toExecute, FALSE, NULL, NULL);
     WCMD_free_commands(toExecute);
     toExecute = NULL;
   }
@@ -497,8 +497,12 @@ void WCMD_process_command (WCHAR *command, CMD_LIST **cmdList)
     while ((p = strchrW(p, '%'))) {
       i = *(p+1) - '0';
 
+      /* Dont touch %% */
+      if (*(p+1) == '%') {
+        p+=2;
+
       /* Replace %~ modifications if in batch program */
-      if (context && *(p+1) == '~') {
+      } else if (context && *(p+1) == '~') {
         WCMD_HandleTildaModifiers(&p, NULL);
         p++;
 
@@ -531,13 +535,17 @@ void WCMD_process_command (WCHAR *command, CMD_LIST **cmdList)
     if (context) {
       p = cmd;
       while ((p = strchrW(p, '%'))) {
-        s = strchrW(p+1, '%');
-        if (!s) {
-          *p=0x00;
+        if (*(p+1) == '%') {
+          p+=2;
         } else {
-          t = WCMD_strdupW(s+1);
-          strcpyW(p, t);
-          free(t);
+          s = strchrW(p+1, '%');
+          if (!s) {
+            *p=0x00;
+          } else {
+            t = WCMD_strdupW(s+1);
+            strcpyW(p, t);
+            free(t);
+          }
         }
       }
 
@@ -1487,7 +1495,7 @@ void WCMD_opt_s_strip_quotes(WCHAR *cmd) {
  *	Handle pipes within a command - the DOS way using temporary files.
  */
 
-void WCMD_pipe (CMD_LIST **cmdEntry) {
+void WCMD_pipe (CMD_LIST **cmdEntry, WCHAR *var, WCHAR *val) {
 
   WCHAR *p;
   WCHAR *command = (*cmdEntry)->command;
@@ -1503,19 +1511,19 @@ void WCMD_pipe (CMD_LIST **cmdEntry) {
   p = strchrW(command, '|');
   *p++ = '\0';
   wsprintf (temp_cmd, redirOut, command, temp_file);
-  WCMD_process_command (temp_cmd, cmdEntry);
+  WCMD_execute (temp_cmd, var, val, cmdEntry);
   command = p;
   while ((p = strchrW(command, '|'))) {
     *p++ = '\0';
     GetTempFileName (temp_path, cmdW, 0, temp_file2);
     wsprintf (temp_cmd, redirBoth, command, temp_file, temp_file2);
-    WCMD_process_command (temp_cmd, cmdEntry);
+    WCMD_execute (temp_cmd, var, val, cmdEntry);
     DeleteFile (temp_file);
     strcpyW (temp_file, temp_file2);
     command = p;
   }
   wsprintf (temp_cmd, redirIn, command, temp_file);
-  WCMD_process_command (temp_cmd, cmdEntry);
+  WCMD_execute (temp_cmd, var, val, cmdEntry);
   DeleteFile (temp_file);
 }
 
@@ -1913,6 +1921,7 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
     const WCHAR ifElse[] = {'e','l','s','e',' ','\0'};
     BOOL      inRem = FALSE;
     BOOL      inFor = FALSE;
+    BOOL      inIn  = FALSE;
     BOOL      inIf  = FALSE;
     BOOL      inElse= FALSE;
     BOOL      onlyWhiteSpace = FALSE;
@@ -2057,11 +2066,15 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
                            onlyWhiteSpace,
                            inFor, lastWasIn, lastWasDo,
                            inIf, inElse, lastWasElse);
-                if (curLen == 0) {
+
+                /* Ignore open brackets inside the for set */
+                if (curLen == 0 && !inIn) {
+                    WINE_TRACE("@@@4\n");
                   curDepth++;
 
                 /* If in quotes, ignore brackets */
                 } else if (inQuotes) {
+                    WINE_TRACE("@@@3\n");
                   curString[curLen++] = *curPos;
 
                 /* In a FOR loop, an unquoted '(' may occur straight after
@@ -2075,6 +2088,13 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
                            (inElse && lastWasElse && onlyWhiteSpace) ||
                            (inFor && (lastWasIn || lastWasDo) && onlyWhiteSpace)) {
 
+                  WINE_TRACE("@@@2\n");
+                   /* If entering into an 'IN', set inIn */
+                  if (inFor && lastWasIn && onlyWhiteSpace) {
+                    WINE_TRACE("Inside an IN\n");
+                    inIn = TRUE;
+                  }
+
                   /* Add the current command */
                   thisEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(CMD_LIST));
                   thisEntry->command = HeapAlloc(GetProcessHeap(), 0,
@@ -2094,6 +2114,7 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
 
                   curDepth++;
                 } else {
+                  WINE_TRACE("@@@1\n");
                   curString[curLen++] = *curPos;
                 }
                 break;
@@ -2159,6 +2180,9 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
                     *output = thisEntry;
                   }
                   lastEntry = thisEntry;
+
+                  /* Leave inIn if necessary */
+                  if (inIn) inIn =  FALSE;
                 } else {
                   curString[curLen++] = *curPos;
                 }
@@ -2227,7 +2251,8 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
  *
  * Process all the commands read in so far
  */
-CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket) {
+CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket,
+                                WCHAR *var, WCHAR *val) {
 
     int bdepth = -1;
 
@@ -2255,9 +2280,9 @@ CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket) {
         WINE_TRACE("Executing command: '%s'\n", wine_dbgstr_w(thisCmd->command));
 
         if (strchrW(thisCmd->command,'|') != NULL) {
-          WCMD_pipe (&thisCmd);
+          WCMD_pipe (&thisCmd, var, val);
         } else {
-          WCMD_process_command (thisCmd->command, &thisCmd);
+          WCMD_execute (thisCmd->command, var, val, &thisCmd);
         }
       }
 
-- 
1.5.0




More information about the wine-patches mailing list