Make delayed environment-variable expansions actually be delayed.

svn path=/trunk/; revision=39597
This commit is contained in:
Jeffrey Morlan 2009-02-14 01:13:17 +00:00
parent 5d62c3b3a5
commit 122c236111
4 changed files with 64 additions and 25 deletions

View file

@ -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

View file

@ -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[]);

View file

@ -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, &param, 10);
DWORD n = _tcstoul(Right, &param, 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, &param, 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 */

View file

@ -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;
}