diff --git a/reactos/base/shell/cmd/cmd.c b/reactos/base/shell/cmd/cmd.c index 39593108f7a..3232108159d 100644 --- a/reactos/base/shell/cmd/cmd.c +++ b/reactos/base/shell/cmd/cmd.c @@ -868,6 +868,7 @@ ExecuteCommand(PARSED_COMMAND *Cmd) { BOOL bNewBatch = TRUE; PARSED_COMMAND *Sub; + LPTSTR ExpandedLine; BOOL Success = TRUE; if (!PerformRedirection(Cmd->Redirections)) @@ -879,7 +880,14 @@ ExecuteCommand(PARSED_COMMAND *Cmd) if(bc) bNewBatch = FALSE; - Success = DoCommand(Cmd->Command.CommandLine); + ExpandedLine = DoDelayedExpansion(Cmd->Command.CommandLine); + if (!ExpandedLine) + { + Success = FALSE; + break; + } + Success = DoCommand(ExpandedLine); + cmd_free(ExpandedLine); if(bNewBatch && bc) AddBatchRedirection(&Cmd->Redirections); @@ -1097,8 +1105,11 @@ GetBatchVar ( LPCTSTR varName, UINT* varNameLen ) return NULL; } +BOOL bNoInteractive; +BOOL bIsBatch; + BOOL -SubstituteVars(TCHAR *Src, TCHAR *Dest, TCHAR Delim, BOOL bIsBatch) +SubstituteVars(TCHAR *Src, TCHAR *Dest, TCHAR Delim) { #define APPEND(From, Length) { \ if (Dest + (Length) > DestEnd) \ @@ -1250,15 +1261,27 @@ too_long: #undef APPEND1 } +LPTSTR +DoDelayedExpansion(LPTSTR Line) +{ + TCHAR Buf[CMDLINE_LENGTH]; + if (!_tcschr(Line, _T('!'))) + return cmd_dup(Line); + + /* 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('!'))) + return NULL; + return cmd_dup(Buf); +} + /* * do the prompt/input/process loop * */ -BOOL bNoInteractive; -BOOL bIsBatch; - BOOL ReadLine (TCHAR *commandline, BOOL bMore) { @@ -1299,15 +1322,7 @@ ReadLine (TCHAR *commandline, BOOL bMore) bIsBatch = TRUE; } - if (!SubstituteVars(ip, commandline, _T('%'), bIsBatch)) - return FALSE; - - /* FIXME: !vars! should be substituted later, after parsing. */ - if (!SubstituteVars(commandline, readline, _T('!'), bIsBatch)) - return FALSE; - _tcscpy(commandline, readline); - - return TRUE; + return SubstituteVars(ip, commandline, _T('%')); } static INT diff --git a/reactos/base/shell/cmd/cmd.h b/reactos/base/shell/cmd/cmd.h index 8446e6dbd60..e236cf44237 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); +LPTSTR DoDelayedExpansion(LPTSTR Line); BOOL DoCommand (LPTSTR line); BOOL ReadLine(TCHAR *commandline, BOOL bMore); int cmd_main (int argc, const TCHAR *argv[]); diff --git a/reactos/base/shell/cmd/if.c b/reactos/base/shell/cmd/if.c index ae848e8e0c8..dd7372d02cc 100644 --- a/reactos/base/shell/cmd/if.c +++ b/reactos/base/shell/cmd/if.c @@ -67,15 +67,30 @@ BOOL ExecuteIf(PARSED_COMMAND *Cmd) { INT result = FALSE; /* when set cause 'then' clause to be executed */ LPTSTR param; + LPTSTR Left = NULL, Right; + + if (Cmd->If.LeftArg) + { + Left = DoDelayedExpansion(Cmd->If.LeftArg); + if (!Left) + return FALSE; + } + Right = DoDelayedExpansion(Cmd->If.RightArg); + if (!Right) + { + cmd_free(Left); + return FALSE; + } if (Cmd->If.Operator == IF_CMDEXTVERSION) { /* IF CMDEXTVERSION n: check if Command Extensions version * is greater or equal to n */ - DWORD n = _tcstoul(Cmd->If.RightArg, ¶m, 10); + DWORD n = _tcstoul(Right, ¶m, 10); if (*param != _T('\0')) { - error_syntax(Cmd->If.RightArg); + error_syntax(Right); + cmd_free(Right); return FALSE; } result = (2 >= n); @@ -83,7 +98,7 @@ BOOL ExecuteIf(PARSED_COMMAND *Cmd) else if (Cmd->If.Operator == IF_DEFINED) { /* IF DEFINED var: check if environment variable exists */ - result = (GetEnvVarOrSpecial(Cmd->If.RightArg) != NULL); + result = (GetEnvVarOrSpecial(Right) != NULL); } else if (Cmd->If.Operator == IF_ERRORLEVEL) { @@ -91,7 +106,8 @@ BOOL ExecuteIf(PARSED_COMMAND *Cmd) INT n = _tcstol(Cmd->If.RightArg, ¶m, 10); if (*param != _T('\0')) { - error_syntax(Cmd->If.RightArg); + error_syntax(Right); + cmd_free(Right); return FALSE; } result = (nErrorLevel >= n); @@ -102,9 +118,9 @@ BOOL ExecuteIf(PARSED_COMMAND *Cmd) WIN32_FIND_DATA f; HANDLE hFind; - StripQuotes(Cmd->If.RightArg); + StripQuotes(Right); - hFind = FindFirstFile(Cmd->If.RightArg, &f); + hFind = FindFirstFile(Right, &f); if (hFind != INVALID_HANDLE_VALUE) { result = TRUE; @@ -120,11 +136,11 @@ BOOL ExecuteIf(PARSED_COMMAND *Cmd) if (Cmd->If.Operator == IF_STRINGEQ) { /* IF str1 == str2 */ - result = StringCmp(Cmd->If.LeftArg, Cmd->If.RightArg) == 0; + result = StringCmp(Left, Right) == 0; } else { - result = GenericCmp(StringCmp, Cmd->If.LeftArg, Cmd->If.RightArg); + result = GenericCmp(StringCmp, Left, Right); switch (Cmd->If.Operator) { case IF_EQU: result = (result == 0); break; @@ -137,6 +153,9 @@ BOOL ExecuteIf(PARSED_COMMAND *Cmd) } } + cmd_free(Left); + cmd_free(Right); + if (result ^ ((Cmd->If.Flags & IFFLAG_NEGATE) != 0)) { /* full condition was true, do the command */ diff --git a/reactos/base/shell/cmd/redir.c b/reactos/base/shell/cmd/redir.c index a550c055b52..923638f181c 100644 --- a/reactos/base/shell/cmd/redir.c +++ b/reactos/base/shell/cmd/redir.c @@ -54,7 +54,7 @@ BOOL PerformRedirection(REDIRECTION *RedirList) { REDIRECTION *Redir; - TCHAR Filename[MAX_PATH]; + LPTSTR Filename; HANDLE hNew; UINT DupNumber; static SECURITY_ATTRIBUTES SecAttr = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; @@ -78,8 +78,9 @@ PerformRedirection(REDIRECTION *RedirList) for (Redir = RedirList; Redir; Redir = Redir->Next) { - *Filename = _T('\0'); - _tcsncat(Filename, Redir->Filename, MAX_PATH - 1); + Filename = DoDelayedExpansion(Redir->Filename); + if (!Filename) + goto redir_error; StripQuotes(Filename); if (*Filename == _T('&')) @@ -112,6 +113,8 @@ PerformRedirection(REDIRECTION *RedirList) { ConErrResPrintf(Redir->Type == REDIR_READ ? STRING_CMD_ERROR1 : STRING_CMD_ERROR3, Filename); + cmd_free(Filename); +redir_error: /* Undo all the redirections before this one */ UndoRedirection(RedirList, Redir); return FALSE; @@ -123,6 +126,7 @@ PerformRedirection(REDIRECTION *RedirList) SetHandle(Redir->Number, hNew); TRACE("%d redirected to: %s\n", Redir->Number, debugstr_aw(Filename)); + cmd_free(Filename); } return TRUE; }