diff --git a/reactos/base/shell/cmd/batch.c b/reactos/base/shell/cmd/batch.c index 93fc56dee23..be04cbd2848 100644 --- a/reactos/base/shell/cmd/batch.c +++ b/reactos/base/shell/cmd/batch.c @@ -405,19 +405,14 @@ LPTSTR ReadBatchLine () } /* At this point, fv points to parameter string */ + bc->forvalue = fv; + + /* Double up % signs so they will get through the parser intact */ while (*sp) { - if ((*sp == _T('%')) && (*(sp + 1) == bc->forvar)) - { - /* replace % var */ - dp = _stpcpy (dp, fv); - sp += 2; - } - else - { - /* Else just copy */ - *dp++ = *sp++; - } + if (*sp == _T('%')) + *dp++ = _T('%'); + *dp++ = *sp++; } *dp++ = _T('\n'); diff --git a/reactos/base/shell/cmd/batch.h b/reactos/base/shell/cmd/batch.h index 0939bb8aefe..00cc9d6bb4b 100644 --- a/reactos/base/shell/cmd/batch.h +++ b/reactos/base/shell/cmd/batch.h @@ -21,6 +21,7 @@ typedef struct tagBATCHCONTEXT HANDLE hFind; /* Preserve find handle when doing a for */ REDIRECTION *RedirList; TCHAR forvar; + LPTSTR forvalue; } BATCH_CONTEXT, *LPBATCH_CONTEXT; diff --git a/reactos/base/shell/cmd/cmd.c b/reactos/base/shell/cmd/cmd.c index 3232108159d..28ff509c0d4 100644 --- a/reactos/base/shell/cmd/cmd.c +++ b/reactos/base/shell/cmd/cmd.c @@ -1261,19 +1261,56 @@ too_long: #undef APPEND1 } +BOOL +SubstituteForVars(TCHAR *Src, TCHAR *Dest) +{ + TCHAR *DestEnd = &Dest[CMDLINE_LENGTH - 1]; + while (*Src) + { + if (Src[0] == _T('%') && Src[1] != _T('\0')) + { + /* This might be a variable. Search the list of contexts for it */ + BATCH_CONTEXT *Ctx = bc; + while (Ctx && Ctx->forvar != Src[1]) + Ctx = Ctx->prev; + if (Ctx) + { + /* Found it */ + if (Dest + _tcslen(Ctx->forvalue) > DestEnd) + return FALSE; + Dest = _stpcpy(Dest, Ctx->forvalue); + Src += 2; + continue; + } + } + /* Not a variable; just copy the character */ + if (Dest >= DestEnd) + return FALSE; + *Dest++ = *Src++; + } + *Dest = _T('\0'); + return TRUE; +} + LPTSTR DoDelayedExpansion(LPTSTR Line) { - TCHAR Buf[CMDLINE_LENGTH]; - if (!_tcschr(Line, _T('!'))) - return cmd_dup(Line); + TCHAR Buf1[CMDLINE_LENGTH]; + TCHAR Buf2[CMDLINE_LENGTH]; + + /* First, substitute FOR variables */ + if (!SubstituteForVars(Line, Buf1)) + return NULL; + + if (!_tcschr(Buf1, _T('!'))) + return cmd_dup(Buf1); /* FIXME: Delayed substitutions actually aren't quite the same as * immediate substitutions. In particular, it's possible to escape * the exclamation point using ^. */ - if (!SubstituteVars(Line, Buf, _T('!'))) + if (!SubstituteVars(Buf1, Buf2, _T('!'))) return NULL; - return cmd_dup(Buf); + return cmd_dup(Buf2); } diff --git a/reactos/base/shell/cmd/cmd.h b/reactos/base/shell/cmd/cmd.h index e236cf44237..3e2808b877b 100644 --- a/reactos/base/shell/cmd/cmd.h +++ b/reactos/base/shell/cmd/cmd.h @@ -102,6 +102,7 @@ BOOL ExecuteCommand(struct _PARSED_COMMAND *Cmd); LPCTSTR GetEnvVarOrSpecial ( LPCTSTR varName ); VOID AddBreakHandler (VOID); VOID RemoveBreakHandler (VOID); +BOOL SubstituteForVars(TCHAR *Src, TCHAR *Dest); LPTSTR DoDelayedExpansion(LPTSTR Line); BOOL DoCommand (LPTSTR line); BOOL ReadLine(TCHAR *commandline, BOOL bMore); diff --git a/reactos/base/shell/cmd/parser.c b/reactos/base/shell/cmd/parser.c index 6bbee17358b..762a6c8fbe7 100644 --- a/reactos/base/shell/cmd/parser.c +++ b/reactos/base/shell/cmd/parser.c @@ -610,18 +610,21 @@ ParseCommand(LPTSTR Line) return Cmd; } -/* Reconstruct a parse tree into text form; - * used for echoing batch file commands */ + +/* Reconstruct a parse tree into text form; used for echoing + * batch file commands and FOR instances. */ VOID EchoCommand(PARSED_COMMAND *Cmd) { + TCHAR Buf[CMDLINE_LENGTH]; PARSED_COMMAND *Sub; REDIRECTION *Redir; switch (Cmd->Type) { case C_COMMAND: - ConOutPrintf(_T("%s"), Cmd->Command.CommandLine); + if (SubstituteForVars(Cmd->Command.CommandLine, Buf)) + ConOutPrintf(_T("%s"), Buf); break; case C_QUIET: return; @@ -649,9 +652,11 @@ EchoCommand(PARSED_COMMAND *Cmd) ConOutPrintf(_T(" /I")); if (Cmd->If.Flags & IFFLAG_NEGATE) ConOutPrintf(_T(" not")); - if (Cmd->If.LeftArg) - ConOutPrintf(_T(" %s"), Cmd->If.LeftArg); - ConOutPrintf(_T(" %s %s "), IfOperatorString[Cmd->If.Operator], Cmd->If.RightArg); + if (Cmd->If.LeftArg && SubstituteForVars(Cmd->If.LeftArg, Buf)) + ConOutPrintf(_T(" %s"), Buf); + ConOutPrintf(_T(" %s"), IfOperatorString[Cmd->If.Operator]); + if (SubstituteForVars(Cmd->If.RightArg, Buf)) + ConOutPrintf(_T(" %s "), Buf); Sub = Cmd->Subcommands; EchoCommand(Sub); if (Sub->Next) @@ -664,8 +669,9 @@ EchoCommand(PARSED_COMMAND *Cmd) for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next) { - ConOutPrintf(_T(" %c%s%s"), _T('0') + Redir->Number, - RedirString[Redir->Type], Redir->Filename); + if (SubstituteForVars(Redir->Filename, Buf)) + ConOutPrintf(_T(" %c%s%s"), _T('0') + Redir->Number, + RedirString[Redir->Type], Buf); } }