Make delayed environment-variable expansions actually be delayed.
authorJeffrey Morlan <mrnobo1024@yahoo.com>
Sat, 14 Feb 2009 01:13:17 +0000 (01:13 +0000)
committerJeffrey Morlan <mrnobo1024@yahoo.com>
Sat, 14 Feb 2009 01:13:17 +0000 (01:13 +0000)
svn path=/trunk/; revision=39597

reactos/base/shell/cmd/cmd.c
reactos/base/shell/cmd/cmd.h
reactos/base/shell/cmd/if.c
reactos/base/shell/cmd/redir.c

index 3959310..3232108 100644 (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
index 8446e6d..e236cf4 100644 (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[]);
index ae848e8..dd7372d 100644 (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 */
index a550c05..923638f 100644 (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;
 }