mirror of
https://github.com/reactos/reactos.git
synced 2025-07-31 11:51:58 +00:00
[CMD] Reduce stack memory usage when parsing or echoing commands recursively.
- Use a common large string buffer for temporary command substitutions/expansions, instead of having such a buffer in the local stack of the parsing and echoing functions that may be called recursively. Since CMD executes synchronously we know that this common buffer can only be used once at a time. - Also do a small code cleanup in ParseIf(), ParseFor() and ParseCommandPart().
This commit is contained in:
parent
26cfadc352
commit
c93f511241
1 changed files with 59 additions and 69 deletions
|
@ -57,6 +57,9 @@ enum
|
||||||
TOK_END_BLOCK
|
TOK_END_BLOCK
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Scratch buffer for temporary command substitutions / expansions */
|
||||||
|
static TCHAR TempBuf[CMDLINE_LENGTH];
|
||||||
|
|
||||||
static BOOL bParseError;
|
static BOOL bParseError;
|
||||||
static BOOL bLineContinuations;
|
static BOOL bLineContinuations;
|
||||||
static TCHAR ParseLine[CMDLINE_LENGTH];
|
static TCHAR ParseLine[CMDLINE_LENGTH];
|
||||||
|
@ -370,7 +373,6 @@ static PARSED_COMMAND *ParseBlock(REDIRECTION *RedirList)
|
||||||
/* Parse an IF statement */
|
/* Parse an IF statement */
|
||||||
static PARSED_COMMAND *ParseIf(void)
|
static PARSED_COMMAND *ParseIf(void)
|
||||||
{
|
{
|
||||||
int Type;
|
|
||||||
PARSED_COMMAND *Cmd;
|
PARSED_COMMAND *Cmd;
|
||||||
|
|
||||||
Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
|
Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
|
||||||
|
@ -383,24 +385,19 @@ static PARSED_COMMAND *ParseIf(void)
|
||||||
memset(Cmd, 0, sizeof(PARSED_COMMAND));
|
memset(Cmd, 0, sizeof(PARSED_COMMAND));
|
||||||
Cmd->Type = C_IF;
|
Cmd->Type = C_IF;
|
||||||
|
|
||||||
Type = CurrentTokenType;
|
|
||||||
if (_tcsicmp(CurrentToken, _T("/I")) == 0)
|
if (_tcsicmp(CurrentToken, _T("/I")) == 0)
|
||||||
{
|
{
|
||||||
Cmd->If.Flags |= IFFLAG_IGNORECASE;
|
Cmd->If.Flags |= IFFLAG_IGNORECASE;
|
||||||
Type = ParseToken(0, STANDARD_SEPS);
|
ParseToken(0, STANDARD_SEPS);
|
||||||
}
|
}
|
||||||
if (_tcsicmp(CurrentToken, _T("not")) == 0)
|
if (_tcsicmp(CurrentToken, _T("not")) == 0)
|
||||||
{
|
{
|
||||||
Cmd->If.Flags |= IFFLAG_NEGATE;
|
Cmd->If.Flags |= IFFLAG_NEGATE;
|
||||||
Type = ParseToken(0, STANDARD_SEPS);
|
ParseToken(0, STANDARD_SEPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Type != TOK_NORMAL)
|
if (CurrentTokenType != TOK_NORMAL)
|
||||||
{
|
goto error;
|
||||||
FreeCommand(Cmd);
|
|
||||||
ParseError();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for unary operators */
|
/* Check for unary operators */
|
||||||
for (; Cmd->If.Operator <= IF_MAX_UNARY; Cmd->If.Operator++)
|
for (; Cmd->If.Operator <= IF_MAX_UNARY; Cmd->If.Operator++)
|
||||||
|
@ -408,11 +405,7 @@ static PARSED_COMMAND *ParseIf(void)
|
||||||
if (_tcsicmp(CurrentToken, IfOperatorString[Cmd->If.Operator]) == 0)
|
if (_tcsicmp(CurrentToken, IfOperatorString[Cmd->If.Operator]) == 0)
|
||||||
{
|
{
|
||||||
if (ParseToken(0, STANDARD_SEPS) != TOK_NORMAL)
|
if (ParseToken(0, STANDARD_SEPS) != TOK_NORMAL)
|
||||||
{
|
goto error;
|
||||||
FreeCommand(Cmd);
|
|
||||||
ParseError();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
Cmd->If.RightArg = cmd_dup(CurrentToken);
|
Cmd->If.RightArg = cmd_dup(CurrentToken);
|
||||||
goto condition_done;
|
goto condition_done;
|
||||||
}
|
}
|
||||||
|
@ -435,33 +428,30 @@ static PARSED_COMMAND *ParseIf(void)
|
||||||
if (_tcsicmp(CurrentToken, IfOperatorString[Cmd->If.Operator]) == 0)
|
if (_tcsicmp(CurrentToken, IfOperatorString[Cmd->If.Operator]) == 0)
|
||||||
{
|
{
|
||||||
if (ParseToken(0, STANDARD_SEPS) != TOK_NORMAL)
|
if (ParseToken(0, STANDARD_SEPS) != TOK_NORMAL)
|
||||||
break;
|
goto error;
|
||||||
Cmd->If.RightArg = cmd_dup(CurrentToken);
|
Cmd->If.RightArg = cmd_dup(CurrentToken);
|
||||||
goto condition_done;
|
goto condition_done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FreeCommand(Cmd);
|
goto error;
|
||||||
ParseError();
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
condition_done:
|
condition_done:
|
||||||
Cmd->Subcommands = ParseCommandOp(C_OP_LOWEST);
|
Cmd->Subcommands = ParseCommandOp(C_OP_LOWEST);
|
||||||
if (Cmd->Subcommands == NULL)
|
if (Cmd->Subcommands == NULL)
|
||||||
{
|
goto error;
|
||||||
FreeCommand(Cmd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (_tcsicmp(CurrentToken, _T("else")) == 0)
|
if (_tcsicmp(CurrentToken, _T("else")) == 0)
|
||||||
{
|
{
|
||||||
Cmd->Subcommands->Next = ParseCommandOp(C_OP_LOWEST);
|
Cmd->Subcommands->Next = ParseCommandOp(C_OP_LOWEST);
|
||||||
if (Cmd->Subcommands->Next == NULL)
|
if (Cmd->Subcommands->Next == NULL)
|
||||||
{
|
goto error;
|
||||||
FreeCommand(Cmd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Cmd;
|
return Cmd;
|
||||||
|
|
||||||
|
error:
|
||||||
|
FreeCommand(Cmd);
|
||||||
|
ParseError();
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -471,7 +461,7 @@ condition_done:
|
||||||
static PARSED_COMMAND *ParseFor(void)
|
static PARSED_COMMAND *ParseFor(void)
|
||||||
{
|
{
|
||||||
PARSED_COMMAND *Cmd;
|
PARSED_COMMAND *Cmd;
|
||||||
TCHAR List[CMDLINE_LENGTH];
|
TCHAR* List = TempBuf;
|
||||||
TCHAR *Pos = List;
|
TCHAR *Pos = List;
|
||||||
|
|
||||||
Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
|
Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
|
||||||
|
@ -487,7 +477,9 @@ static PARSED_COMMAND *ParseFor(void)
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (_tcsicmp(CurrentToken, _T("/D")) == 0)
|
if (_tcsicmp(CurrentToken, _T("/D")) == 0)
|
||||||
|
{
|
||||||
Cmd->For.Switches |= FOR_DIRS;
|
Cmd->For.Switches |= FOR_DIRS;
|
||||||
|
}
|
||||||
else if (_tcsicmp(CurrentToken, _T("/F")) == 0)
|
else if (_tcsicmp(CurrentToken, _T("/F")) == 0)
|
||||||
{
|
{
|
||||||
Cmd->For.Switches |= FOR_F;
|
Cmd->For.Switches |= FOR_F;
|
||||||
|
@ -500,7 +492,9 @@ static PARSED_COMMAND *ParseFor(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_tcsicmp(CurrentToken, _T("/L")) == 0)
|
else if (_tcsicmp(CurrentToken, _T("/L")) == 0)
|
||||||
|
{
|
||||||
Cmd->For.Switches |= FOR_LOOP;
|
Cmd->For.Switches |= FOR_LOOP;
|
||||||
|
}
|
||||||
else if (_tcsicmp(CurrentToken, _T("/R")) == 0)
|
else if (_tcsicmp(CurrentToken, _T("/R")) == 0)
|
||||||
{
|
{
|
||||||
Cmd->For.Switches |= FOR_RECURSIVE;
|
Cmd->For.Switches |= FOR_RECURSIVE;
|
||||||
|
@ -514,7 +508,10 @@ static PARSED_COMMAND *ParseFor(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ParseToken(0, STANDARD_SEPS);
|
ParseToken(0, STANDARD_SEPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,24 +537,22 @@ static PARSED_COMMAND *ParseFor(void)
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
int Type;
|
|
||||||
|
|
||||||
/* Pretend we're inside a block so the tokenizer will stop on ')' */
|
/* Pretend we're inside a block so the tokenizer will stop on ')' */
|
||||||
InsideBlock++;
|
InsideBlock++;
|
||||||
Type = ParseToken(0, STANDARD_SEPS);
|
ParseToken(0, STANDARD_SEPS);
|
||||||
InsideBlock--;
|
InsideBlock--;
|
||||||
|
|
||||||
if (Type == TOK_END_BLOCK)
|
if (CurrentTokenType == TOK_END_BLOCK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (Type == TOK_END)
|
if (CurrentTokenType == TOK_END)
|
||||||
{
|
{
|
||||||
/* Skip past the \n */
|
/* Skip past the \n */
|
||||||
ParseChar();
|
ParseChar();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Type != TOK_NORMAL)
|
if (CurrentTokenType != TOK_NORMAL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (Pos != List)
|
if (Pos != List)
|
||||||
|
@ -576,10 +571,7 @@ static PARSED_COMMAND *ParseFor(void)
|
||||||
|
|
||||||
Cmd->Subcommands = ParseCommandOp(C_OP_LOWEST);
|
Cmd->Subcommands = ParseCommandOp(C_OP_LOWEST);
|
||||||
if (Cmd->Subcommands == NULL)
|
if (Cmd->Subcommands == NULL)
|
||||||
{
|
goto error;
|
||||||
FreeCommand(Cmd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Cmd;
|
return Cmd;
|
||||||
|
|
||||||
|
@ -631,8 +623,8 @@ static DECLSPEC_NOINLINE PARSED_COMMAND *ParseCommandPart(REDIRECTION *RedirList
|
||||||
/* Now get the tail */
|
/* Now get the tail */
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
int Type = ParseToken(0, NULL);
|
ParseToken(0, NULL);
|
||||||
if (Type == TOK_NORMAL)
|
if (CurrentTokenType == TOK_NORMAL)
|
||||||
{
|
{
|
||||||
if (Pos + _tcslen(CurrentToken) >= &ParsedLine[CMDLINE_LENGTH])
|
if (Pos + _tcslen(CurrentToken) >= &ParsedLine[CMDLINE_LENGTH])
|
||||||
{
|
{
|
||||||
|
@ -642,7 +634,7 @@ static DECLSPEC_NOINLINE PARSED_COMMAND *ParseCommandPart(REDIRECTION *RedirList
|
||||||
}
|
}
|
||||||
Pos = _stpcpy(Pos, CurrentToken);
|
Pos = _stpcpy(Pos, CurrentToken);
|
||||||
}
|
}
|
||||||
else if (Type == TOK_REDIRECTION)
|
else if (CurrentTokenType == TOK_REDIRECTION)
|
||||||
{
|
{
|
||||||
if (!ParseRedirection(&RedirList))
|
if (!ParseRedirection(&RedirList))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1123,7 +1115,6 @@ dump:
|
||||||
VOID
|
VOID
|
||||||
EchoCommand(PARSED_COMMAND *Cmd)
|
EchoCommand(PARSED_COMMAND *Cmd)
|
||||||
{
|
{
|
||||||
TCHAR Buf[CMDLINE_LENGTH];
|
|
||||||
PARSED_COMMAND *Sub;
|
PARSED_COMMAND *Sub;
|
||||||
REDIRECTION *Redir;
|
REDIRECTION *Redir;
|
||||||
|
|
||||||
|
@ -1131,14 +1122,14 @@ EchoCommand(PARSED_COMMAND *Cmd)
|
||||||
{
|
{
|
||||||
case C_COMMAND:
|
case C_COMMAND:
|
||||||
{
|
{
|
||||||
if (SubstituteForVars(Cmd->Command.First, Buf))
|
if (SubstituteForVars(Cmd->Command.First, TempBuf))
|
||||||
ConOutPrintf(_T("%s"), Buf);
|
ConOutPrintf(_T("%s"), TempBuf);
|
||||||
if (SubstituteForVars(Cmd->Command.Rest, Buf))
|
if (SubstituteForVars(Cmd->Command.Rest, TempBuf))
|
||||||
{
|
{
|
||||||
ConOutPrintf(_T("%s"), Buf);
|
ConOutPrintf(_T("%s"), TempBuf);
|
||||||
#ifdef MSCMD_ECHO_COMMAND_COMPAT
|
#ifdef MSCMD_ECHO_COMMAND_COMPAT
|
||||||
/* NOTE: For Windows compatibility, add a trailing space after printing the command parameter, if present */
|
/* NOTE: For Windows compatibility, add a trailing space after printing the command parameter, if present */
|
||||||
if (*Buf) ConOutChar(_T(' '));
|
if (*TempBuf) ConOutChar(_T(' '));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1214,11 +1205,11 @@ EchoCommand(PARSED_COMMAND *Cmd)
|
||||||
ConOutPuts(_T(" /I"));
|
ConOutPuts(_T(" /I"));
|
||||||
if (Cmd->If.Flags & IFFLAG_NEGATE)
|
if (Cmd->If.Flags & IFFLAG_NEGATE)
|
||||||
ConOutPuts(_T(" not"));
|
ConOutPuts(_T(" not"));
|
||||||
if (Cmd->If.LeftArg && SubstituteForVars(Cmd->If.LeftArg, Buf))
|
if (Cmd->If.LeftArg && SubstituteForVars(Cmd->If.LeftArg, TempBuf))
|
||||||
ConOutPrintf(_T(" %s"), Buf);
|
ConOutPrintf(_T(" %s"), TempBuf);
|
||||||
ConOutPrintf(_T(" %s"), IfOperatorString[Cmd->If.Operator]);
|
ConOutPrintf(_T(" %s"), IfOperatorString[Cmd->If.Operator]);
|
||||||
if (SubstituteForVars(Cmd->If.RightArg, Buf))
|
if (SubstituteForVars(Cmd->If.RightArg, TempBuf))
|
||||||
ConOutPrintf(_T(" %s "), Buf);
|
ConOutPrintf(_T(" %s "), TempBuf);
|
||||||
Sub = Cmd->Subcommands;
|
Sub = Cmd->Subcommands;
|
||||||
EchoCommand(Sub);
|
EchoCommand(Sub);
|
||||||
if (Sub->Next)
|
if (Sub->Next)
|
||||||
|
@ -1238,8 +1229,8 @@ EchoCommand(PARSED_COMMAND *Cmd)
|
||||||
if (Cmd->For.Switches & FOR_RECURSIVE) ConOutPuts(_T(" /R"));
|
if (Cmd->For.Switches & FOR_RECURSIVE) ConOutPuts(_T(" /R"));
|
||||||
if (Cmd->For.Params)
|
if (Cmd->For.Params)
|
||||||
ConOutPrintf(_T(" %s"), Cmd->For.Params);
|
ConOutPrintf(_T(" %s"), Cmd->For.Params);
|
||||||
if (Cmd->For.List && SubstituteForVars(Cmd->For.List, Buf))
|
if (Cmd->For.List && SubstituteForVars(Cmd->For.List, TempBuf))
|
||||||
ConOutPrintf(_T(" %%%c in (%s) do "), Cmd->For.Variable, Buf);
|
ConOutPrintf(_T(" %%%c in (%s) do "), Cmd->For.Variable, TempBuf);
|
||||||
else
|
else
|
||||||
ConOutPrintf(_T(" %%%c in (%s) do "), Cmd->For.Variable, Cmd->For.List);
|
ConOutPrintf(_T(" %%%c in (%s) do "), Cmd->For.Variable, Cmd->For.List);
|
||||||
EchoCommand(Cmd->Subcommands);
|
EchoCommand(Cmd->Subcommands);
|
||||||
|
@ -1253,16 +1244,16 @@ EchoCommand(PARSED_COMMAND *Cmd)
|
||||||
|
|
||||||
for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next)
|
for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next)
|
||||||
{
|
{
|
||||||
if (SubstituteForVars(Redir->Filename, Buf))
|
if (SubstituteForVars(Redir->Filename, TempBuf))
|
||||||
{
|
{
|
||||||
#ifdef MSCMD_ECHO_COMMAND_COMPAT
|
#ifdef MSCMD_ECHO_COMMAND_COMPAT
|
||||||
ConOutPrintf(_T("%c%s%s "),
|
ConOutPrintf(_T("%c%s%s "),
|
||||||
_T('0') + Redir->Number,
|
_T('0') + Redir->Number,
|
||||||
RedirString[Redir->Mode], Buf);
|
RedirString[Redir->Mode], TempBuf);
|
||||||
#else
|
#else
|
||||||
ConOutPrintf(_T(" %c%s%s"),
|
ConOutPrintf(_T(" %c%s%s"),
|
||||||
_T('0') + Redir->Number,
|
_T('0') + Redir->Number,
|
||||||
RedirString[Redir->Mode], Buf);
|
RedirString[Redir->Mode], TempBuf);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1276,7 +1267,6 @@ EchoCommand(PARSED_COMMAND *Cmd)
|
||||||
TCHAR *
|
TCHAR *
|
||||||
Unparse(PARSED_COMMAND *Cmd, TCHAR *Out, TCHAR *OutEnd)
|
Unparse(PARSED_COMMAND *Cmd, TCHAR *Out, TCHAR *OutEnd)
|
||||||
{
|
{
|
||||||
TCHAR Buf[CMDLINE_LENGTH];
|
|
||||||
PARSED_COMMAND *Sub;
|
PARSED_COMMAND *Sub;
|
||||||
REDIRECTION *Redir;
|
REDIRECTION *Redir;
|
||||||
|
|
||||||
|
@ -1313,10 +1303,10 @@ do { \
|
||||||
/* This is fragile since there could be special characters, but
|
/* This is fragile since there could be special characters, but
|
||||||
* Windows doesn't bother escaping them, so for compatibility
|
* Windows doesn't bother escaping them, so for compatibility
|
||||||
* we probably shouldn't do it either */
|
* we probably shouldn't do it either */
|
||||||
if (!SubstituteForVars(Cmd->Command.First, Buf)) return NULL;
|
if (!SubstituteForVars(Cmd->Command.First, TempBuf)) return NULL;
|
||||||
STRING(Buf);
|
STRING(TempBuf);
|
||||||
if (!SubstituteForVars(Cmd->Command.Rest, Buf)) return NULL;
|
if (!SubstituteForVars(Cmd->Command.Rest, TempBuf)) return NULL;
|
||||||
STRING(Buf);
|
STRING(TempBuf);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case C_QUIET:
|
case C_QUIET:
|
||||||
|
@ -1351,11 +1341,11 @@ do { \
|
||||||
STRING(_T(" /I"));
|
STRING(_T(" /I"));
|
||||||
if (Cmd->If.Flags & IFFLAG_NEGATE)
|
if (Cmd->If.Flags & IFFLAG_NEGATE)
|
||||||
STRING(_T(" not"));
|
STRING(_T(" not"));
|
||||||
if (Cmd->If.LeftArg && SubstituteForVars(Cmd->If.LeftArg, Buf))
|
if (Cmd->If.LeftArg && SubstituteForVars(Cmd->If.LeftArg, TempBuf))
|
||||||
PRINTF(_T(" %s"), Buf);
|
PRINTF(_T(" %s"), TempBuf);
|
||||||
PRINTF(_T(" %s"), IfOperatorString[Cmd->If.Operator]);
|
PRINTF(_T(" %s"), IfOperatorString[Cmd->If.Operator]);
|
||||||
if (!SubstituteForVars(Cmd->If.RightArg, Buf)) return NULL;
|
if (!SubstituteForVars(Cmd->If.RightArg, TempBuf)) return NULL;
|
||||||
PRINTF(_T(" %s "), Buf);
|
PRINTF(_T(" %s "), TempBuf);
|
||||||
Sub = Cmd->Subcommands;
|
Sub = Cmd->Subcommands;
|
||||||
RECURSE(Sub);
|
RECURSE(Sub);
|
||||||
if (Sub->Next)
|
if (Sub->Next)
|
||||||
|
@ -1373,8 +1363,8 @@ do { \
|
||||||
if (Cmd->For.Switches & FOR_RECURSIVE) STRING(_T(" /R"));
|
if (Cmd->For.Switches & FOR_RECURSIVE) STRING(_T(" /R"));
|
||||||
if (Cmd->For.Params)
|
if (Cmd->For.Params)
|
||||||
PRINTF(_T(" %s"), Cmd->For.Params);
|
PRINTF(_T(" %s"), Cmd->For.Params);
|
||||||
if (Cmd->For.List && SubstituteForVars(Cmd->For.List, Buf))
|
if (Cmd->For.List && SubstituteForVars(Cmd->For.List, TempBuf))
|
||||||
PRINTF(_T(" %%%c in (%s) do "), Cmd->For.Variable, Buf);
|
PRINTF(_T(" %%%c in (%s) do "), Cmd->For.Variable, TempBuf);
|
||||||
else
|
else
|
||||||
PRINTF(_T(" %%%c in (%s) do "), Cmd->For.Variable, Cmd->For.List);
|
PRINTF(_T(" %%%c in (%s) do "), Cmd->For.Variable, Cmd->For.List);
|
||||||
RECURSE(Cmd->Subcommands);
|
RECURSE(Cmd->Subcommands);
|
||||||
|
@ -1387,10 +1377,10 @@ do { \
|
||||||
|
|
||||||
for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next)
|
for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next)
|
||||||
{
|
{
|
||||||
if (!SubstituteForVars(Redir->Filename, Buf))
|
if (!SubstituteForVars(Redir->Filename, TempBuf))
|
||||||
return NULL;
|
return NULL;
|
||||||
PRINTF(_T(" %c%s%s"), _T('0') + Redir->Number,
|
PRINTF(_T(" %c%s%s"), _T('0') + Redir->Number,
|
||||||
RedirString[Redir->Mode], Buf);
|
RedirString[Redir->Mode], TempBuf);
|
||||||
}
|
}
|
||||||
return Out;
|
return Out;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue