mirror of
https://github.com/reactos/reactos.git
synced 2025-07-31 10:21:50 +00:00
- Begin writing a real parser for cmd. &, &&, ||, and () are implemented. The parenthesized blocks aren't too useful yet as the parser can't read additional lines; doing this will require some restructuring in cmd.c.
- Remove ^-removing hacks in echo and set. svn path=/trunk/; revision=35514
This commit is contained in:
parent
07912f2b23
commit
4cdc27c1a2
7 changed files with 550 additions and 229 deletions
|
@ -323,7 +323,7 @@ static BOOL RunFile(LPTSTR filename)
|
||||||
* Rest - rest of command line
|
* Rest - rest of command line
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static VOID
|
static BOOL
|
||||||
Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
|
Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
|
||||||
{
|
{
|
||||||
TCHAR *szFullName=NULL;
|
TCHAR *szFullName=NULL;
|
||||||
|
@ -345,7 +345,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
|
||||||
{
|
{
|
||||||
error_out_of_memory();
|
error_out_of_memory();
|
||||||
nErrorLevel = 1;
|
nErrorLevel = 1;
|
||||||
return ;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
rest = cmd_alloc ( (_tcslen(Rest) + 512) * sizeof(TCHAR));
|
rest = cmd_alloc ( (_tcslen(Rest) + 512) * sizeof(TCHAR));
|
||||||
|
@ -354,7 +354,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
|
||||||
cmd_free (first);
|
cmd_free (first);
|
||||||
error_out_of_memory();
|
error_out_of_memory();
|
||||||
nErrorLevel = 1;
|
nErrorLevel = 1;
|
||||||
return ;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
full = cmd_alloc ( (_tcslen(Full) + 512) * sizeof(TCHAR));
|
full = cmd_alloc ( (_tcslen(Full) + 512) * sizeof(TCHAR));
|
||||||
|
@ -364,7 +364,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
|
||||||
cmd_free (rest);
|
cmd_free (rest);
|
||||||
error_out_of_memory();
|
error_out_of_memory();
|
||||||
nErrorLevel = 1;
|
nErrorLevel = 1;
|
||||||
return ;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
szFullName = cmd_alloc ( (_tcslen(Full) + 512) * sizeof(TCHAR));
|
szFullName = cmd_alloc ( (_tcslen(Full) + 512) * sizeof(TCHAR));
|
||||||
|
@ -375,7 +375,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
|
||||||
cmd_free (full);
|
cmd_free (full);
|
||||||
error_out_of_memory();
|
error_out_of_memory();
|
||||||
nErrorLevel = 1;
|
nErrorLevel = 1;
|
||||||
return ;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -446,7 +446,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
|
||||||
cmd_free (full);
|
cmd_free (full);
|
||||||
cmd_free (szFullName);
|
cmd_free (szFullName);
|
||||||
nErrorLevel = 1;
|
nErrorLevel = 1;
|
||||||
return;
|
return working;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get the PATH environment variable and parse it */
|
/* get the PATH environment variable and parse it */
|
||||||
|
@ -459,7 +459,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
|
||||||
cmd_free (full);
|
cmd_free (full);
|
||||||
cmd_free (szFullName);
|
cmd_free (szFullName);
|
||||||
nErrorLevel = 1;
|
nErrorLevel = 1;
|
||||||
return;
|
return FALSE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,6 +554,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
|
||||||
cmd_free(rest);
|
cmd_free(rest);
|
||||||
cmd_free(full);
|
cmd_free(full);
|
||||||
cmd_free (szFullName);
|
cmd_free (szFullName);
|
||||||
|
return nErrorLevel == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -566,7 +567,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
VOID
|
BOOL
|
||||||
DoCommand (LPTSTR line)
|
DoCommand (LPTSTR line)
|
||||||
{
|
{
|
||||||
TCHAR *com = NULL; /* the first word in the command */
|
TCHAR *com = NULL; /* the first word in the command */
|
||||||
|
@ -575,6 +576,7 @@ DoCommand (LPTSTR line)
|
||||||
LPTSTR rest; /* pointer to the rest of the command line */
|
LPTSTR rest; /* pointer to the rest of the command line */
|
||||||
INT cl;
|
INT cl;
|
||||||
LPCOMMAND cmdptr;
|
LPCOMMAND cmdptr;
|
||||||
|
BOOL ret = TRUE;
|
||||||
|
|
||||||
TRACE ("DoCommand: (\'%s\')\n", debugstr_aw(line));
|
TRACE ("DoCommand: (\'%s\')\n", debugstr_aw(line));
|
||||||
|
|
||||||
|
@ -582,7 +584,7 @@ DoCommand (LPTSTR line)
|
||||||
if (com == NULL)
|
if (com == NULL)
|
||||||
{
|
{
|
||||||
error_out_of_memory();
|
error_out_of_memory();
|
||||||
return;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
cp = com;
|
cp = com;
|
||||||
|
@ -640,7 +642,7 @@ DoCommand (LPTSTR line)
|
||||||
/* If end of table execute ext cmd */
|
/* If end of table execute ext cmd */
|
||||||
if (cmdptr->name == NULL)
|
if (cmdptr->name == NULL)
|
||||||
{
|
{
|
||||||
Execute (line, com, rest);
|
ret = Execute (line, com, rest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,6 +679,7 @@ DoCommand (LPTSTR line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmd_free(com);
|
cmd_free(com);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -687,25 +690,28 @@ DoCommand (LPTSTR line)
|
||||||
|
|
||||||
VOID ParseCommandLine (LPTSTR cmd)
|
VOID ParseCommandLine (LPTSTR cmd)
|
||||||
{
|
{
|
||||||
TCHAR cmdline[CMDLINE_LENGTH];
|
PARSED_COMMAND *Cmd = ParseCommand(cmd);
|
||||||
LPTSTR s;
|
if (Cmd)
|
||||||
|
{
|
||||||
|
ExecuteCommand(Cmd);
|
||||||
|
FreeCommand(Cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID
|
||||||
|
ExecutePipeline(PARSED_COMMAND *Cmd)
|
||||||
|
{
|
||||||
#ifdef FEATURE_REDIRECTION
|
#ifdef FEATURE_REDIRECTION
|
||||||
REDIRECTION *RedirList = NULL;
|
|
||||||
TCHAR szTempPath[MAX_PATH] = _T(".\\");
|
TCHAR szTempPath[MAX_PATH] = _T(".\\");
|
||||||
TCHAR szFileName[2][MAX_PATH] = {_T(""), _T("")};
|
TCHAR szFileName[2][MAX_PATH] = {_T(""), _T("")};
|
||||||
HANDLE hFile[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
|
HANDLE hFile[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
|
||||||
INT num = 0;
|
|
||||||
INT Length;
|
INT Length;
|
||||||
UINT Attributes;
|
UINT Attributes;
|
||||||
BOOL bNewBatch = TRUE;
|
|
||||||
HANDLE hOldConIn;
|
HANDLE hOldConIn;
|
||||||
HANDLE hOldConOut;
|
HANDLE hOldConOut;
|
||||||
#endif /* FEATURE_REDIRECTION */
|
#endif /* FEATURE_REDIRECTION */
|
||||||
|
|
||||||
_tcscpy (cmdline, cmd);
|
//TRACE ("ParseCommandLine: (\'%s\')\n", debugstr_aw(s));
|
||||||
s = &cmdline[0];
|
|
||||||
|
|
||||||
TRACE ("ParseCommandLine: (\'%s\')\n", debugstr_aw(s));
|
|
||||||
|
|
||||||
#ifdef FEATURE_REDIRECTION
|
#ifdef FEATURE_REDIRECTION
|
||||||
/* find the temp path to store temporary files */
|
/* find the temp path to store temporary files */
|
||||||
|
@ -726,15 +732,6 @@ VOID ParseCommandLine (LPTSTR cmd)
|
||||||
if (szTempPath[_tcslen (szTempPath) - 1] != _T('\\'))
|
if (szTempPath[_tcslen (szTempPath) - 1] != _T('\\'))
|
||||||
_tcscat (szTempPath, _T("\\"));
|
_tcscat (szTempPath, _T("\\"));
|
||||||
|
|
||||||
/* get the redirections from the command line */
|
|
||||||
num = GetRedirection (s, &RedirList);
|
|
||||||
|
|
||||||
if (!PerformRedirection(RedirList))
|
|
||||||
{
|
|
||||||
FreeRedirection(RedirList);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up the initial conditions ... */
|
/* Set up the initial conditions ... */
|
||||||
/* preserve STDIN and STDOUT handles */
|
/* preserve STDIN and STDOUT handles */
|
||||||
hOldConIn = GetStdHandle (STD_INPUT_HANDLE);
|
hOldConIn = GetStdHandle (STD_INPUT_HANDLE);
|
||||||
|
@ -744,7 +741,7 @@ VOID ParseCommandLine (LPTSTR cmd)
|
||||||
*szFileName[0] = _T('\0');
|
*szFileName[0] = _T('\0');
|
||||||
hFile[0] = INVALID_HANDLE_VALUE;
|
hFile[0] = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
while (num-- > 1)
|
while (Cmd->Type == C_PIPE)
|
||||||
{
|
{
|
||||||
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
|
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
|
||||||
|
|
||||||
|
@ -766,7 +763,7 @@ VOID ParseCommandLine (LPTSTR cmd)
|
||||||
|
|
||||||
SetStdHandle (STD_OUTPUT_HANDLE, hFile[1]);
|
SetStdHandle (STD_OUTPUT_HANDLE, hFile[1]);
|
||||||
|
|
||||||
DoCommand (s);
|
ExecuteCommand(Cmd->Subcommands);
|
||||||
|
|
||||||
/* close stdout file */
|
/* close stdout file */
|
||||||
SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut);
|
SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut);
|
||||||
|
@ -799,22 +796,18 @@ VOID ParseCommandLine (LPTSTR cmd)
|
||||||
OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
|
OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
|
||||||
SetStdHandle (STD_INPUT_HANDLE, hFile[0]);
|
SetStdHandle (STD_INPUT_HANDLE, hFile[0]);
|
||||||
|
|
||||||
s = s + _tcslen (s) + 1;
|
Cmd = Cmd->Subcommands->Next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now set up the end conditions... */
|
/* Now set up the end conditions... */
|
||||||
SetStdHandle(STD_OUTPUT_HANDLE, hOldConOut);
|
SetStdHandle(STD_OUTPUT_HANDLE, hOldConOut);
|
||||||
|
|
||||||
if(bc)
|
|
||||||
bNewBatch = FALSE;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* process final command */
|
/* process final command */
|
||||||
DoCommand (s);
|
ExecuteCommand(Cmd);
|
||||||
|
|
||||||
#ifdef FEATURE_REDIRECTION
|
#ifdef FEATURE_REDIRECTION
|
||||||
if(bNewBatch && bc)
|
|
||||||
AddBatchRedirection(&RedirList);
|
|
||||||
/* close old stdin file */
|
/* close old stdin file */
|
||||||
#if 0 /* buggy implementation */
|
#if 0 /* buggy implementation */
|
||||||
SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
|
SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
|
||||||
|
@ -870,12 +863,55 @@ VOID ParseCommandLine (LPTSTR cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UndoRedirection(RedirList, NULL);
|
|
||||||
FreeRedirection(RedirList);
|
|
||||||
#endif /* FEATURE_REDIRECTION */
|
#endif /* FEATURE_REDIRECTION */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
ExecuteCommand(PARSED_COMMAND *Cmd)
|
||||||
|
{
|
||||||
|
BOOL bNewBatch = TRUE;
|
||||||
|
PARSED_COMMAND *Sub;
|
||||||
|
BOOL Success = TRUE;
|
||||||
|
|
||||||
|
if (!PerformRedirection(Cmd->Redirections))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
switch (Cmd->Type)
|
||||||
|
{
|
||||||
|
case C_COMMAND:
|
||||||
|
if(bc)
|
||||||
|
bNewBatch = FALSE;
|
||||||
|
|
||||||
|
Success = DoCommand(Cmd->CommandLine);
|
||||||
|
|
||||||
|
if(bNewBatch && bc)
|
||||||
|
AddBatchRedirection(&Cmd->Redirections);
|
||||||
|
break;
|
||||||
|
case C_QUIET:
|
||||||
|
case C_BLOCK:
|
||||||
|
case C_MULTI:
|
||||||
|
for (Sub = Cmd->Subcommands; Sub; Sub = Sub->Next)
|
||||||
|
Success = ExecuteCommand(Sub);
|
||||||
|
break;
|
||||||
|
case C_IFFAILURE:
|
||||||
|
case C_IFSUCCESS:
|
||||||
|
Sub = Cmd->Subcommands;
|
||||||
|
Success = ExecuteCommand(Sub);
|
||||||
|
if (Success == (Cmd->Type - C_IFFAILURE))
|
||||||
|
{
|
||||||
|
Sub = Sub->Next;
|
||||||
|
Success = ExecuteCommand(Sub);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case C_PIPE:
|
||||||
|
ExecutePipeline(Cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
UndoRedirection(Cmd->Redirections, NULL);
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
GrowIfNecessary_dbg ( UINT needed, LPTSTR* ret, UINT* retlen, const char *file, int line )
|
GrowIfNecessary_dbg ( UINT needed, LPTSTR* ret, UINT* retlen, const char *file, int line )
|
||||||
{
|
{
|
||||||
|
|
|
@ -97,10 +97,12 @@ INT cmd_cls (LPTSTR, LPTSTR);
|
||||||
/* Prototypes for CMD.C */
|
/* Prototypes for CMD.C */
|
||||||
INT ConvertULargeInteger (ULARGE_INTEGER num, LPTSTR des, INT len, BOOL bPutSeperator);
|
INT ConvertULargeInteger (ULARGE_INTEGER num, LPTSTR des, INT len, BOOL bPutSeperator);
|
||||||
VOID ParseCommandLine (LPTSTR);
|
VOID ParseCommandLine (LPTSTR);
|
||||||
|
struct _PARSED_COMMAND;
|
||||||
|
BOOL ExecuteCommand(struct _PARSED_COMMAND *Cmd);
|
||||||
LPCTSTR GetEnvVarOrSpecial ( LPCTSTR varName );
|
LPCTSTR GetEnvVarOrSpecial ( LPCTSTR varName );
|
||||||
VOID AddBreakHandler (VOID);
|
VOID AddBreakHandler (VOID);
|
||||||
VOID RemoveBreakHandler (VOID);
|
VOID RemoveBreakHandler (VOID);
|
||||||
VOID DoCommand (LPTSTR line);
|
BOOL DoCommand (LPTSTR line);
|
||||||
int cmd_main (int argc, const TCHAR *argv[]);
|
int cmd_main (int argc, const TCHAR *argv[]);
|
||||||
|
|
||||||
extern HANDLE CMD_ModuleHandle;
|
extern HANDLE CMD_ModuleHandle;
|
||||||
|
@ -326,6 +328,21 @@ INT cmd_move (LPTSTR, LPTSTR);
|
||||||
INT CommandMsgbox (LPTSTR, LPTSTR);
|
INT CommandMsgbox (LPTSTR, LPTSTR);
|
||||||
|
|
||||||
|
|
||||||
|
/* Prototypes from PARSER.C */
|
||||||
|
enum { C_COMMAND, C_QUIET, C_BLOCK, C_MULTI, C_IFFAILURE, C_IFSUCCESS, C_PIPE };
|
||||||
|
typedef struct _PARSED_COMMAND
|
||||||
|
{
|
||||||
|
struct _PARSED_COMMAND *Subcommands;
|
||||||
|
struct _PARSED_COMMAND *Next;
|
||||||
|
struct _REDIRECTION *Redirections;
|
||||||
|
TCHAR *Tail;
|
||||||
|
BYTE Type;
|
||||||
|
TCHAR CommandLine[];
|
||||||
|
} PARSED_COMMAND;
|
||||||
|
PARSED_COMMAND *ParseCommand(LPTSTR Line);
|
||||||
|
VOID FreeCommand(PARSED_COMMAND *Cmd);
|
||||||
|
|
||||||
|
|
||||||
/* Prototypes from PATH.C */
|
/* Prototypes from PATH.C */
|
||||||
INT cmd_path (LPTSTR, LPTSTR);
|
INT cmd_path (LPTSTR, LPTSTR);
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
<file>misc.c</file>
|
<file>misc.c</file>
|
||||||
<file>move.c</file>
|
<file>move.c</file>
|
||||||
<file>msgbox.c</file>
|
<file>msgbox.c</file>
|
||||||
|
<file>parser.c</file>
|
||||||
<file>path.c</file>
|
<file>path.c</file>
|
||||||
<file>pause.c</file>
|
<file>pause.c</file>
|
||||||
<file>prompt.c</file>
|
<file>prompt.c</file>
|
||||||
|
|
|
@ -83,16 +83,6 @@ INT CommandEcho (LPTSTR cmd, LPTSTR param)
|
||||||
}
|
}
|
||||||
if (*p1 != _T('\0'))
|
if (*p1 != _T('\0'))
|
||||||
{
|
{
|
||||||
p1 = param;
|
|
||||||
while (NULL != (p1 = _tcschr(p1, _T('^'))))
|
|
||||||
{
|
|
||||||
memmove(p1, p1 + 1, (_tcslen(p1 + 1) + 1) * sizeof(TCHAR));
|
|
||||||
if (*p1)
|
|
||||||
{
|
|
||||||
//skip past the char being escaped
|
|
||||||
p1++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ConOutPuts (param);
|
ConOutPuts (param);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
456
reactos/base/shell/cmd/parser.c
Normal file
456
reactos/base/shell/cmd/parser.c
Normal file
|
@ -0,0 +1,456 @@
|
||||||
|
#include <precomp.h>
|
||||||
|
|
||||||
|
#define C_OP_LOWEST C_MULTI
|
||||||
|
#define C_OP_HIGHEST C_PIPE
|
||||||
|
static const TCHAR OpString[][3] = { _T("&"), _T("||"), _T("&&"), _T("|") };
|
||||||
|
|
||||||
|
static const TCHAR RedirString[][3] = { _T("<"), _T(">"), _T(">>") };
|
||||||
|
|
||||||
|
static BOOL IsSeparator(TCHAR Char)
|
||||||
|
{
|
||||||
|
/* These three characters act like spaces to the parser */
|
||||||
|
return _istspace(Char) || (Char && _tcschr(_T(",;="), Char));
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { TOK_END, TOK_NORMAL, TOK_OPERATOR, TOK_REDIRECTION,
|
||||||
|
TOK_BEGIN_BLOCK, TOK_END_BLOCK };
|
||||||
|
|
||||||
|
static BOOL bParseError;
|
||||||
|
static BOOL bLineContinuations;
|
||||||
|
static TCHAR ParseLine[CMDLINE_LENGTH];
|
||||||
|
static TCHAR *ParsePos;
|
||||||
|
static TCHAR CurChar;
|
||||||
|
|
||||||
|
static TCHAR CurrentToken[CMDLINE_LENGTH];
|
||||||
|
static int CurrentTokenType;
|
||||||
|
static int InsideBlock;
|
||||||
|
|
||||||
|
static TCHAR ParseChar()
|
||||||
|
{
|
||||||
|
TCHAR Char;
|
||||||
|
|
||||||
|
//restart:
|
||||||
|
/* Although CRs can be injected into a line via an environment
|
||||||
|
* variable substitution, the parser ignores them - they won't
|
||||||
|
* even separate tokens. */
|
||||||
|
do
|
||||||
|
Char = *ParsePos++;
|
||||||
|
while (Char == _T('\r'));
|
||||||
|
|
||||||
|
if (!Char)
|
||||||
|
{
|
||||||
|
/*if (bLineContinuations)
|
||||||
|
if (ReadLine(ParseLine, TRUE) && *(ParsePos = ParseLine))
|
||||||
|
goto restart;*/
|
||||||
|
}
|
||||||
|
return CurChar = Char;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ParseError()
|
||||||
|
{
|
||||||
|
if (CurrentTokenType == TOK_END)
|
||||||
|
ConOutResPuts(STRING_SYNTAX_COMMAND_INCORRECT);
|
||||||
|
else
|
||||||
|
ConOutPrintf(_T("%s was unexpected at this time.\n"), CurrentToken);
|
||||||
|
bParseError = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Yes, cmd has a Lexical Analyzer. Whenever the parser gives an "xxx was
|
||||||
|
* unexpected at this time." message, it shows what the last token read was */
|
||||||
|
static int ParseToken(TCHAR ExtraEnd, BOOL PreserveSpace)
|
||||||
|
{
|
||||||
|
TCHAR *Out = CurrentToken;
|
||||||
|
TCHAR Char = CurChar;
|
||||||
|
int Type;
|
||||||
|
BOOL bInQuote = FALSE;
|
||||||
|
|
||||||
|
if (!PreserveSpace)
|
||||||
|
{
|
||||||
|
while (Char != _T('\n') && IsSeparator(Char))
|
||||||
|
Char = ParseChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Char && Char != _T('\n'))
|
||||||
|
{
|
||||||
|
bInQuote ^= (Char == _T('"'));
|
||||||
|
if (!bInQuote)
|
||||||
|
{
|
||||||
|
/* Check for all the myriad ways in which this token
|
||||||
|
* may be brought to an untimely end. */
|
||||||
|
if ((Char >= _T('0') && Char <= _T('9') &&
|
||||||
|
(ParsePos == &ParseLine[1] || IsSeparator(ParsePos[-2]))
|
||||||
|
&& (*ParsePos == _T('<') || *ParsePos == _T('>')))
|
||||||
|
|| _tcschr(_T(")&|<>") + (InsideBlock ? 0 : 1), Char)
|
||||||
|
|| (!PreserveSpace && IsSeparator(Char))
|
||||||
|
|| (Char == ExtraEnd))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Char == _T('^'))
|
||||||
|
{
|
||||||
|
Char = ParseChar();
|
||||||
|
/* Eat up a \n, allowing line continuation */
|
||||||
|
if (Char == _T('\n'))
|
||||||
|
Char = ParseChar();
|
||||||
|
/* Next character is a forced literal */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* FIXME: potential buffer overflow here */
|
||||||
|
*Out++ = Char;
|
||||||
|
Char = ParseChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we got at least one character before reaching a special one.
|
||||||
|
* If so, return them and leave the special for the next call. */
|
||||||
|
if (Out != CurrentToken)
|
||||||
|
{
|
||||||
|
Type = TOK_NORMAL;
|
||||||
|
}
|
||||||
|
else if (Char == _T('('))
|
||||||
|
{
|
||||||
|
Type = TOK_BEGIN_BLOCK;
|
||||||
|
*Out++ = Char;
|
||||||
|
ParseChar();
|
||||||
|
}
|
||||||
|
else if (Char == _T(')'))
|
||||||
|
{
|
||||||
|
Type = TOK_END_BLOCK;
|
||||||
|
*Out++ = Char;
|
||||||
|
ParseChar();
|
||||||
|
}
|
||||||
|
else if (Char == _T('&') || Char == _T('|'))
|
||||||
|
{
|
||||||
|
Type = TOK_OPERATOR;
|
||||||
|
*Out++ = Char;
|
||||||
|
Char = ParseChar();
|
||||||
|
/* check for && or || */
|
||||||
|
if (Char == Out[-1])
|
||||||
|
{
|
||||||
|
*Out++ = Char;
|
||||||
|
ParseChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((Char >= _T('0') && Char <= _T('9'))
|
||||||
|
|| (Char == _T('<') || Char == _T('>')))
|
||||||
|
{
|
||||||
|
Type = TOK_REDIRECTION;
|
||||||
|
if (Char >= _T('0') && Char <= _T('9'))
|
||||||
|
{
|
||||||
|
*Out++ = Char;
|
||||||
|
Char = ParseChar();
|
||||||
|
}
|
||||||
|
*Out++ = Char;
|
||||||
|
Char = ParseChar();
|
||||||
|
if (Char == Out[-1])
|
||||||
|
{
|
||||||
|
/* Strangely, the tokenizer allows << as well as >>... (it
|
||||||
|
* will cause an error when trying to parse it though) */
|
||||||
|
*Out++ = Char;
|
||||||
|
Char = ParseChar();
|
||||||
|
}
|
||||||
|
if (Char == _T('&'))
|
||||||
|
{
|
||||||
|
*Out++ = Char;
|
||||||
|
while (IsSeparator(Char = ParseChar()))
|
||||||
|
;
|
||||||
|
if (Char >= _T('0') && Char <= _T('9'))
|
||||||
|
{
|
||||||
|
*Out++ = Char;
|
||||||
|
ParseChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Type = TOK_END;
|
||||||
|
}
|
||||||
|
*Out = _T('\0');
|
||||||
|
return CurrentTokenType = Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL ParseRedirection(REDIRECTION **List)
|
||||||
|
{
|
||||||
|
TCHAR *Tok = CurrentToken;
|
||||||
|
BYTE Number;
|
||||||
|
BYTE RedirType;
|
||||||
|
REDIRECTION *Redir;
|
||||||
|
|
||||||
|
if (*Tok >= _T('0') && *Tok <= _T('9'))
|
||||||
|
Number = *Tok++ - _T('0');
|
||||||
|
else
|
||||||
|
Number = *Tok == _T('<') ? 0 : 1;
|
||||||
|
|
||||||
|
if (*Tok++ == _T('<'))
|
||||||
|
{
|
||||||
|
RedirType = REDIR_READ;
|
||||||
|
if (*Tok == _T('<'))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RedirType = REDIR_WRITE;
|
||||||
|
if (*Tok == _T('>'))
|
||||||
|
{
|
||||||
|
RedirType = REDIR_APPEND;
|
||||||
|
Tok++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*Tok)
|
||||||
|
{
|
||||||
|
/* The file name was not part of this token, so it'll be the next one */
|
||||||
|
if (ParseToken(0, FALSE) != TOK_NORMAL)
|
||||||
|
goto fail;
|
||||||
|
Tok = CurrentToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If a redirection for this handle number already exists, delete it */
|
||||||
|
while ((Redir = *List))
|
||||||
|
{
|
||||||
|
if (Redir->Number == Number)
|
||||||
|
{
|
||||||
|
*List = Redir->Next;
|
||||||
|
cmd_free(Redir);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List = &Redir->Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Redir = cmd_alloc(FIELD_OFFSET(REDIRECTION, Filename[_tcslen(Tok) + 1]));
|
||||||
|
Redir->Next = NULL;
|
||||||
|
Redir->OldHandle = INVALID_HANDLE_VALUE;
|
||||||
|
Redir->Number = Number;
|
||||||
|
Redir->Type = RedirType;
|
||||||
|
_tcscpy(Redir->Filename, Tok);
|
||||||
|
*List = Redir;
|
||||||
|
return TRUE;
|
||||||
|
fail:
|
||||||
|
ParseError();
|
||||||
|
FreeRedirection(*List);
|
||||||
|
*List = NULL;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PARSED_COMMAND *ParseCommandOp(int OpType);
|
||||||
|
|
||||||
|
/* Parse a parenthesized block */
|
||||||
|
static PARSED_COMMAND *ParseBlock(REDIRECTION *RedirList)
|
||||||
|
{
|
||||||
|
PARSED_COMMAND *Cmd, *Sub, **NextPtr;
|
||||||
|
Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
|
||||||
|
Cmd->Type = C_BLOCK;
|
||||||
|
Cmd->Next = NULL;
|
||||||
|
Cmd->Subcommands = NULL;
|
||||||
|
Cmd->Redirections = RedirList;
|
||||||
|
|
||||||
|
/* Read the block contents */
|
||||||
|
NextPtr = &Cmd->Subcommands;
|
||||||
|
InsideBlock++;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Sub = ParseCommandOp(C_OP_LOWEST);
|
||||||
|
if (Sub)
|
||||||
|
{
|
||||||
|
*NextPtr = Sub;
|
||||||
|
NextPtr = &Sub->Next;
|
||||||
|
}
|
||||||
|
else if (bParseError)
|
||||||
|
{
|
||||||
|
InsideBlock--;
|
||||||
|
FreeCommand(Cmd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} while (CurrentTokenType != TOK_END_BLOCK);
|
||||||
|
InsideBlock--;
|
||||||
|
|
||||||
|
/* Process any trailing redirections */
|
||||||
|
while (ParseToken(0, FALSE) == TOK_REDIRECTION)
|
||||||
|
{
|
||||||
|
if (!ParseRedirection(&Cmd->Redirections))
|
||||||
|
{
|
||||||
|
FreeCommand(Cmd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PARSED_COMMAND *ParseCommandPart(void)
|
||||||
|
{
|
||||||
|
TCHAR ParsedLine[CMDLINE_LENGTH];
|
||||||
|
TCHAR *Pos;
|
||||||
|
DWORD TailOffset;
|
||||||
|
PARSED_COMMAND *Cmd;
|
||||||
|
REDIRECTION *RedirList = NULL;
|
||||||
|
int Type;
|
||||||
|
|
||||||
|
while (IsSeparator(CurChar))
|
||||||
|
{
|
||||||
|
if (CurChar == _T('\n'))
|
||||||
|
return NULL;
|
||||||
|
ParseChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CurChar)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (CurChar == _T(':'))
|
||||||
|
{
|
||||||
|
/* "Ignore" the rest of the line.
|
||||||
|
* (Line continuations will still be parsed, though.) */
|
||||||
|
while (ParseToken(0, TRUE) != TOK_END)
|
||||||
|
;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CurChar == _T('@'))
|
||||||
|
{
|
||||||
|
ParseChar();
|
||||||
|
Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
|
||||||
|
Cmd->Type = C_QUIET;
|
||||||
|
Cmd->Next = NULL;
|
||||||
|
/* @ acts like a unary operator with low precedence,
|
||||||
|
* so call the top-level parser */
|
||||||
|
Cmd->Subcommands = ParseCommandOp(C_OP_LOWEST);
|
||||||
|
Cmd->Redirections = NULL;
|
||||||
|
return Cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the head of the command */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
Type = ParseToken(_T('('), FALSE);
|
||||||
|
if (Type == TOK_NORMAL)
|
||||||
|
{
|
||||||
|
Pos = _stpcpy(ParsedLine, CurrentToken);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (Type == TOK_REDIRECTION)
|
||||||
|
{
|
||||||
|
if (!ParseRedirection(&RedirList))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else if (Type == TOK_BEGIN_BLOCK)
|
||||||
|
{
|
||||||
|
return ParseBlock(RedirList);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ParseError();
|
||||||
|
FreeRedirection(RedirList);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TailOffset = Pos - ParsedLine;
|
||||||
|
|
||||||
|
/* FIXME: FOR, IF, and REM need special processing by the parser. */
|
||||||
|
|
||||||
|
/* Now get the tail */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
Type = ParseToken(0, TRUE);
|
||||||
|
if (Type == TOK_NORMAL)
|
||||||
|
{
|
||||||
|
/* FIXME: potential buffer overflow here */
|
||||||
|
Pos = _stpcpy(Pos, CurrentToken);
|
||||||
|
}
|
||||||
|
else if (Type == TOK_REDIRECTION)
|
||||||
|
{
|
||||||
|
if (!ParseRedirection(&RedirList))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd = cmd_alloc(FIELD_OFFSET(PARSED_COMMAND, CommandLine[Pos + 1 - ParsedLine]));
|
||||||
|
Cmd->Type = C_COMMAND;
|
||||||
|
Cmd->Next = NULL;
|
||||||
|
Cmd->Subcommands = NULL;
|
||||||
|
Cmd->Redirections = RedirList;
|
||||||
|
_tcscpy(Cmd->CommandLine, ParsedLine);
|
||||||
|
Cmd->Tail = Cmd->CommandLine + TailOffset;
|
||||||
|
return Cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PARSED_COMMAND *ParseCommandOp(int OpType)
|
||||||
|
{
|
||||||
|
PARSED_COMMAND *Cmd, *Left, *Right;
|
||||||
|
|
||||||
|
if (OpType == C_OP_HIGHEST)
|
||||||
|
Cmd = ParseCommandPart();
|
||||||
|
else
|
||||||
|
Cmd = ParseCommandOp(OpType + 1);
|
||||||
|
|
||||||
|
if (Cmd && !_tcscmp(CurrentToken, OpString[OpType - C_OP_LOWEST]))
|
||||||
|
{
|
||||||
|
Left = Cmd;
|
||||||
|
Right = ParseCommandOp(OpType);
|
||||||
|
if (!Right)
|
||||||
|
{
|
||||||
|
if (!bParseError)
|
||||||
|
{
|
||||||
|
/* & is allowed to have an empty RHS */
|
||||||
|
if (OpType == C_MULTI)
|
||||||
|
return Left;
|
||||||
|
ParseError();
|
||||||
|
}
|
||||||
|
FreeCommand(Left);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
|
||||||
|
Cmd->Type = OpType;
|
||||||
|
Cmd->Next = NULL;
|
||||||
|
Cmd->Redirections = NULL;
|
||||||
|
Cmd->Subcommands = Left;
|
||||||
|
Left->Next = Right;
|
||||||
|
Right->Next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
PARSED_COMMAND *
|
||||||
|
ParseCommand(LPTSTR Line)
|
||||||
|
{
|
||||||
|
PARSED_COMMAND *Cmd;
|
||||||
|
|
||||||
|
if (Line)
|
||||||
|
{
|
||||||
|
_tcscpy(ParseLine, Line);
|
||||||
|
bLineContinuations = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*if (!ReadLine(ParseLine, FALSE))*/
|
||||||
|
return NULL;
|
||||||
|
bLineContinuations = TRUE;
|
||||||
|
}
|
||||||
|
bParseError = FALSE;
|
||||||
|
ParsePos = ParseLine;
|
||||||
|
CurChar = _T(' ');
|
||||||
|
|
||||||
|
Cmd = ParseCommandOp(C_OP_LOWEST);
|
||||||
|
if (Cmd && CurrentTokenType != TOK_END)
|
||||||
|
{
|
||||||
|
ParseError();
|
||||||
|
FreeCommand(Cmd);
|
||||||
|
Cmd = NULL;
|
||||||
|
}
|
||||||
|
return Cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
FreeCommand(PARSED_COMMAND *Cmd)
|
||||||
|
{
|
||||||
|
if (Cmd->Subcommands)
|
||||||
|
FreeCommand(Cmd->Subcommands);
|
||||||
|
if (Cmd->Next)
|
||||||
|
FreeCommand(Cmd->Next);
|
||||||
|
FreeRedirection(Cmd->Redirections);
|
||||||
|
cmd_free(Cmd);
|
||||||
|
}
|
|
@ -30,175 +30,6 @@
|
||||||
#ifdef FEATURE_REDIRECTION
|
#ifdef FEATURE_REDIRECTION
|
||||||
|
|
||||||
|
|
||||||
static BOOL
|
|
||||||
IsRedirection (TCHAR c)
|
|
||||||
{
|
|
||||||
return (c == _T('<')) || (c == _T('>')) || (c == _T('|'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Gets the redirection info from the command line and copies the
|
|
||||||
* file names into ifn, ofn and efn removing them from the command
|
|
||||||
* line.
|
|
||||||
*
|
|
||||||
* Converts remaining command line into a series of null terminated
|
|
||||||
* strings defined by the pipe char '|'. Each string corresponds
|
|
||||||
* to a single executable command. A double null terminates the
|
|
||||||
* command strings.
|
|
||||||
*
|
|
||||||
* Return number of command strings found.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
INT GetRedirection (LPTSTR s, REDIRECTION **RedirList)
|
|
||||||
{
|
|
||||||
INT num = 1;
|
|
||||||
LPTSTR dp = s;
|
|
||||||
LPTSTR sp = s;
|
|
||||||
TCHAR Filename[MAX_PATH];
|
|
||||||
|
|
||||||
#ifdef INCLUDE_CMD_REM
|
|
||||||
|
|
||||||
TCHAR * line = s;
|
|
||||||
|
|
||||||
|
|
||||||
while (_istspace (*line))
|
|
||||||
line++;
|
|
||||||
|
|
||||||
/*first thing first. check to see if this is "rem" and hope out*/
|
|
||||||
if(!_tcsncmp (line, _T("rem "), 4))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* find and remove all the redirections first */
|
|
||||||
while (*sp)
|
|
||||||
{
|
|
||||||
if (*sp == _T('^'))
|
|
||||||
{
|
|
||||||
*dp++ = *sp++;
|
|
||||||
*dp++ = *sp++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((*sp == _T('"')) || (*sp == _T('\'')))
|
|
||||||
{
|
|
||||||
/* No redirects inside quotes */
|
|
||||||
TCHAR qc = *sp;
|
|
||||||
|
|
||||||
do
|
|
||||||
*dp++ = *sp++;
|
|
||||||
while (*sp && *sp != qc);
|
|
||||||
|
|
||||||
*dp++ = *sp++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int NumberGiven = (*sp >= _T('0') && *sp <= _T('9')) ? 1 : 0;
|
|
||||||
if (sp[NumberGiven] == _T('<') || sp[NumberGiven] == _T('>'))
|
|
||||||
{
|
|
||||||
BYTE HandleNumber;
|
|
||||||
BYTE Type;
|
|
||||||
BOOL bInQuote = FALSE;
|
|
||||||
TCHAR *fn = Filename;
|
|
||||||
REDIRECTION *Redir, **ListPtr;
|
|
||||||
|
|
||||||
if (NumberGiven)
|
|
||||||
HandleNumber = *sp++ - _T('0');
|
|
||||||
else
|
|
||||||
HandleNumber = *sp == _T('<') ? 0 : 1;
|
|
||||||
|
|
||||||
if (*sp == _T('<'))
|
|
||||||
{
|
|
||||||
/* input redirection */
|
|
||||||
Type = REDIR_READ;
|
|
||||||
sp++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* output redirection */
|
|
||||||
Type = REDIR_WRITE;
|
|
||||||
sp++;
|
|
||||||
|
|
||||||
/* append request ? */
|
|
||||||
if (*sp == _T('>'))
|
|
||||||
{
|
|
||||||
Type = REDIR_APPEND;
|
|
||||||
sp++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (_istspace(*sp))
|
|
||||||
sp++;
|
|
||||||
|
|
||||||
/* copy file name */
|
|
||||||
while (*sp && (bInQuote || (!IsRedirection (*sp) && !_istspace (*sp))))
|
|
||||||
{
|
|
||||||
bInQuote ^= (*sp == _T('"'));
|
|
||||||
*fn++ = *sp++;
|
|
||||||
}
|
|
||||||
*fn++ = _T('\0');
|
|
||||||
|
|
||||||
/* Delete any existing redirection for the same handle number */
|
|
||||||
ListPtr = RedirList;
|
|
||||||
while ((Redir = *ListPtr))
|
|
||||||
{
|
|
||||||
if (Redir->Number == HandleNumber)
|
|
||||||
{
|
|
||||||
*ListPtr = Redir->Next;
|
|
||||||
cmd_free(Redir);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ListPtr = &Redir->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
Redir = cmd_alloc(FIELD_OFFSET(REDIRECTION, Filename[fn - Filename]));
|
|
||||||
Redir->Next = NULL;
|
|
||||||
Redir->OldHandle = INVALID_HANDLE_VALUE;
|
|
||||||
Redir->Number = HandleNumber;
|
|
||||||
Redir->Type = Type;
|
|
||||||
_tcscpy(Redir->Filename, Filename);
|
|
||||||
*ListPtr = Redir;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*dp++ = *sp++;
|
|
||||||
}
|
|
||||||
|
|
||||||
*dp++ = _T('\0');
|
|
||||||
*dp = _T('\0');
|
|
||||||
|
|
||||||
/* now go for the pipes */
|
|
||||||
sp = s;
|
|
||||||
while (*sp)
|
|
||||||
{
|
|
||||||
if (*sp == _T('^'))
|
|
||||||
{
|
|
||||||
sp++;
|
|
||||||
sp++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if ((*sp == _T('"')) || (*sp == _T('\'')))
|
|
||||||
{
|
|
||||||
TCHAR qc = *sp;
|
|
||||||
|
|
||||||
do
|
|
||||||
sp++;
|
|
||||||
while (*sp && *sp != qc);
|
|
||||||
|
|
||||||
sp++;
|
|
||||||
}
|
|
||||||
else if (*sp == _T('|'))
|
|
||||||
{
|
|
||||||
*sp++ = _T('\0');
|
|
||||||
num++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
sp++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* cmd allows redirection of handles numbered 3-9 even though these don't
|
/* cmd allows redirection of handles numbered 3-9 even though these don't
|
||||||
* correspond to any STD_ constant. */
|
* correspond to any STD_ constant. */
|
||||||
static HANDLE ExtraHandles[10 - 3];
|
static HANDLE ExtraHandles[10 - 3];
|
||||||
|
|
|
@ -53,7 +53,6 @@ skip_ws ( LPCTSTR p )
|
||||||
|
|
||||||
INT cmd_set (LPTSTR cmd, LPTSTR param)
|
INT cmd_set (LPTSTR cmd, LPTSTR param)
|
||||||
{
|
{
|
||||||
INT i;
|
|
||||||
LPTSTR p;
|
LPTSTR p;
|
||||||
|
|
||||||
if ( !_tcsncmp (param, _T("/?"), 2) )
|
if ( !_tcsncmp (param, _T("/?"), 2) )
|
||||||
|
@ -62,15 +61,6 @@ INT cmd_set (LPTSTR cmd, LPTSTR param)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove escapes */
|
|
||||||
if ( param[0] ) for ( i = 0; param[i+1]; i++ )
|
|
||||||
{
|
|
||||||
if ( param[i] == _T('^') )
|
|
||||||
{
|
|
||||||
memmove ( ¶m[i], ¶m[i+1], _tcslen(¶m[i]) * sizeof(TCHAR) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if no parameters, show the environment */
|
/* if no parameters, show the environment */
|
||||||
if (param[0] == _T('\0'))
|
if (param[0] == _T('\0'))
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue