mirror of
https://github.com/reactos/reactos.git
synced 2025-06-01 23:48:12 +00:00
Don't expand FOR variables until execution time, so that special characters in them won't cause unwanted syntactic effects.
For example, "for %a in (^>) do echo %a" should just echo the greater than sign. svn path=/trunk/; revision=39611
This commit is contained in:
parent
a5d9170830
commit
9b0334da19
5 changed files with 64 additions and 24 deletions
|
@ -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');
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue