Author: jmorlan
Date: Mon Dec 22 16:34:51 2008
New Revision: 38280
URL:
http://svn.reactos.org/svn/reactos?rev=38280&view=rev
Log:
- Make IF command a special form; necessary to make nested multi-line IF blocks work
properly
- Implement IF /I option, IF CMDEXTVERSION, and generic comparisons (EQU etc)
- Make IF ERRORLEVEL return true if the errorlevel is greater than the number
- Remove hacked support for multi-line IF blocks from batch.c
Modified:
trunk/reactos/base/shell/cmd/batch.c
trunk/reactos/base/shell/cmd/batch.h
trunk/reactos/base/shell/cmd/cmd.c
trunk/reactos/base/shell/cmd/cmd.h
trunk/reactos/base/shell/cmd/cmdtable.c
trunk/reactos/base/shell/cmd/if.c
trunk/reactos/base/shell/cmd/parser.c
Modified: trunk/reactos/base/shell/cmd/batch.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/batch.c?rev…
==============================================================================
--- trunk/reactos/base/shell/cmd/batch.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/batch.c [iso-8859-1] Mon Dec 22 16:34:51 2008
@@ -269,7 +269,6 @@
SetFilePointer (bc->hBatchFile, 0, NULL, FILE_BEGIN);
bc->bEcho = bEcho; /* Preserve echo across batch calls */
bc->shiftlevel = 0;
- bc->bCmdBlock = -1;
bc->ffind = NULL;
bc->forvar = _T('\0');
@@ -445,39 +444,6 @@
first = textline;
- /* cmd block over multiple lines (..) */
- if (bc->bCmdBlock >= 0)
- {
- if (*first == _T(')'))
- {
- first++;
- /* Strip leading spaces and trailing space/control chars */
- while(_istspace (*first))
- first++;
- if ((_tcsncicmp (first, _T("else"), 4) == 0) && (_tcschr(first,
_T('('))))
- {
- bc->bExecuteBlock[bc->bCmdBlock] = !bc->bExecuteBlock[bc->bCmdBlock];
- }
- else
- {
- bc->bCmdBlock--;
- }
- continue;
- }
- if (bc->bCmdBlock < MAX_PATH)
- if (!bc->bExecuteBlock[bc->bCmdBlock])
- {
- /* increase the bCmdBlock count when there is another conditon which opens a new
bracket */
- if ((_tcsncicmp (first, _T("if"), 2) == 0) && _tcschr(first,
_T('(')))
- {
- bc->bCmdBlock++;
- if ((bc->bCmdBlock > 0) && (bc->bCmdBlock < MAX_PATH))
- bc->bExecuteBlock[bc->bCmdBlock] = bc->bExecuteBlock[bc->bCmdBlock -
1];
- }
- continue;
- }
- }
-
break;
}
Modified: trunk/reactos/base/shell/cmd/batch.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/batch.h?rev…
==============================================================================
--- trunk/reactos/base/shell/cmd/batch.h [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/batch.h [iso-8859-1] Mon Dec 22 16:34:51 2008
@@ -21,8 +21,6 @@
HANDLE hFind; /* Preserve find handle when doing a for */
REDIRECTION *RedirList;
TCHAR forvar;
- INT bCmdBlock;
- BOOL bExecuteBlock[MAX_PATH];
} BATCH_CONTEXT, *LPBATCH_CONTEXT;
Modified: trunk/reactos/base/shell/cmd/cmd.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/cmd.c?rev=3…
==============================================================================
--- trunk/reactos/base/shell/cmd/cmd.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/cmd.c [iso-8859-1] Mon Dec 22 16:34:51 2008
@@ -879,7 +879,7 @@
if(bc)
bNewBatch = FALSE;
- Success = DoCommand(Cmd->CommandLine);
+ Success = DoCommand(Cmd->Command.CommandLine);
if(bNewBatch && bc)
AddBatchRedirection(&Cmd->Redirections);
@@ -902,6 +902,9 @@
break;
case C_PIPE:
ExecutePipeline(Cmd);
+ break;
+ case C_IF:
+ Success = ExecuteIf(Cmd);
break;
}
Modified: trunk/reactos/base/shell/cmd/cmd.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/cmd.h?rev=3…
==============================================================================
--- trunk/reactos/base/shell/cmd/cmd.h [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/cmd.h [iso-8859-1] Mon Dec 22 16:34:51 2008
@@ -256,6 +256,15 @@
VOID History_del_current_entry(LPTSTR str);/*CTRL-D*/
INT CommandHistory (LPTSTR param);
#endif
+
+
+/* Prototypes for IF.C */
+#define IFFLAG_NEGATE 1 /* NOT */
+#define IFFLAG_IGNORECASE 2 /* /I */
+enum { IF_CMDEXTVERSION, IF_DEFINED, IF_ERRORLEVEL, IF_EXIST,
+ IF_STRINGEQ, /* == */
+ IF_EQU, IF_GTR, IF_GEQ, IF_LSS, IF_LEQ, IF_NEQ };
+BOOL ExecuteIf(struct _PARSED_COMMAND *Cmd);
/* Prototypes for INTERNAL.C */
@@ -330,15 +339,28 @@
/* Prototypes from PARSER.C */
-enum { C_COMMAND, C_QUIET, C_BLOCK, C_MULTI, C_IFFAILURE, C_IFSUCCESS, C_PIPE };
+enum { C_COMMAND, C_QUIET, C_BLOCK, C_MULTI, C_IFFAILURE, C_IFSUCCESS, C_PIPE, C_IF };
typedef struct _PARSED_COMMAND
{
struct _PARSED_COMMAND *Subcommands;
struct _PARSED_COMMAND *Next;
struct _REDIRECTION *Redirections;
- TCHAR *Tail;
BYTE Type;
- TCHAR CommandLine[];
+ union
+ {
+ struct
+ {
+ TCHAR *Tail;
+ TCHAR CommandLine[];
+ } Command;
+ struct
+ {
+ BYTE Flags;
+ BYTE Operator;
+ TCHAR *LeftArg;
+ TCHAR *RightArg;
+ } If;
+ };
} PARSED_COMMAND;
PARSED_COMMAND *ParseCommand(LPTSTR Line);
VOID EchoCommand(PARSED_COMMAND *Cmd);
Modified: trunk/reactos/base/shell/cmd/cmdtable.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/cmdtable.c?…
==============================================================================
--- trunk/reactos/base/shell/cmd/cmdtable.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/cmdtable.c [iso-8859-1] Mon Dec 22 16:34:51 2008
@@ -120,7 +120,7 @@
{_T("history"), 0, CommandHistory},
#endif
- {_T("if"), 0, cmd_if},
+// {_T("if"), 0, cmd_if},
#ifdef INCLUDE_CMD_LABEL
{_T("label"), 0, cmd_label},
Modified: trunk/reactos/base/shell/cmd/if.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/if.c?rev=38…
==============================================================================
--- trunk/reactos/base/shell/cmd/if.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/if.c [iso-8859-1] Mon Dec 22 16:34:51 2008
@@ -32,15 +32,30 @@
#include <precomp.h>
+static INT GenericCmp(INT (*StringCmp)(LPCTSTR, LPCTSTR),
+ LPCTSTR Left, LPCTSTR Right)
+{
+ TCHAR *end;
+ INT nLeft = _tcstol(Left, &end, 0);
+ if (*end == _T('\0'))
+ {
+ INT nRight = _tcstol(Right, &end, 0);
+ if (*end == _T('\0'))
+ {
+ /* both arguments are numeric */
+ return (nLeft < nRight) ? -1 : (nLeft > nRight);
+ }
+ }
+ return StringCmp(Left, Right);
+}
-#define X_EXEC 1
-#define X_EMPTY 0x80
+BOOL ExecuteIf(PARSED_COMMAND *Cmd)
+{
+ INT result = FALSE; /* when set cause 'then' clause to be executed */
+ LPTSTR param;
-INT cmd_if (LPTSTR param)
-{
- INT x_flag = 0; /* when set cause 'then' clause to be executed */
- LPTSTR pp;
-
+#if 0
+ /* FIXME: need to handle IF /?; will require special parsing */
TRACE ("cmd_if: (\'%s\')\n", debugstr_aw(param));
if (!_tcsncmp (param, _T("/?"), 2))
@@ -48,178 +63,89 @@
ConOutResPaging(TRUE,STRING_IF_HELP1);
return 0;
}
+#endif
- /* First check if param string begins with 'not' */
- if (!_tcsnicmp (param, _T("not"), 3) && _istspace (*(param + 3)))
+ if (Cmd->If.Operator == IF_CMDEXTVERSION)
{
- x_flag = X_EXEC; /* Remember 'NOT' */
- param += 3; /* Step over 'NOT' */
- while (_istspace (*param)) /* And subsequent spaces */
- param++;
+ /* IF CMDEXTVERSION n: check if Command Extensions version
+ * is greater or equal to n */
+ DWORD n = _tcstoul(Cmd->If.RightArg, ¶m, 10);
+ if (*param != _T('\0'))
+ {
+ error_syntax(Cmd->If.RightArg);
+ return FALSE;
+ }
+ result = (2 >= n);
}
+ else if (Cmd->If.Operator == IF_DEFINED)
+ {
+ /* IF DEFINED var: check if environment variable exists */
+ result = (GetEnvVarOrSpecial(Cmd->If.RightArg) != NULL);
+ }
+ else if (Cmd->If.Operator == IF_ERRORLEVEL)
+ {
+ /* IF ERRORLEVEL n: check if last exit code is greater or equal to n */
+ INT n = _tcstol(Cmd->If.RightArg, ¶m, 10);
+ if (*param != _T('\0'))
+ {
+ error_syntax(Cmd->If.RightArg);
+ return FALSE;
+ }
+ result = (nErrorLevel >= n);
+ }
+ else if (Cmd->If.Operator == IF_EXIST)
+ {
+ /* IF EXIST filename: check if file exists (wildcards allowed) */
+ WIN32_FIND_DATA f;
+ HANDLE hFind;
- /* Check for 'exist' form */
- if (!_tcsnicmp (param, _T("exist"), 5) && _istspace (*(param + 5)))
- {
- UINT i;
- BOOL bInside = FALSE;
+ StripQuotes(Cmd->If.RightArg);
- param += 5;
- while (_istspace (*param))
- param++;
-
- pp = param;
-
- /* find the whole path to the file */
- for(i = 0; i < _tcslen(param); i++)
+ hFind = FindFirstFile(Cmd->If.RightArg, &f);
+ if (hFind != INVALID_HANDLE_VALUE)
{
- if(param[i] == _T('\"'))
- bInside = !bInside;
- if((param[i] == _T(' ')) && !bInside)
- {
- break;
- }
- pp++;
+ result = TRUE;
+ FindClose(hFind);
}
- *pp++ = _T('\0');
- i = 0;
- /* remove quotes */
- while(i < _tcslen(param))
- {
- if(param[i] == _T('\"'))
- memmove(¶m[i],¶m[i + 1], _tcslen(¶m[i]) * sizeof(TCHAR));
- else
- i++;
- }
-
- if (*pp)
- {
- WIN32_FIND_DATA f;
- HANDLE hFind;
-
- hFind = FindFirstFile (param, &f);
- x_flag ^= (hFind == INVALID_HANDLE_VALUE) ? 0 : X_EXEC;
- if (hFind != INVALID_HANDLE_VALUE)
- {
- FindClose (hFind);
- }
- }
- else
- return 0;
- }
- else if (!_tcsnicmp (param, _T("defined"), 7) && _istspace (*(param +
7)))
- {
- /* Check for 'defined' form */
- TCHAR Value [1];
- INT ValueSize = 0;
-
- param += 7;
- /* IF [NOT] DEFINED var COMMAND */
- /* ^ */
- while (_istspace (*param))
- param++;
- /* IF [NOT] DEFINED var COMMAND */
- /* ^ */
- pp = param;
- while (*pp && !_istspace (*pp))
- pp++;
- /* IF [NOT] DEFINED var COMMAND */
- /* ^ */
- if (*pp)
- {
- *pp++ = _T('\0');
- ValueSize = GetEnvironmentVariable(param, Value, sizeof(Value) / sizeof(Value[0]));
- x_flag ^= (0 == ValueSize)
- ? 0
- : X_EXEC;
- x_flag |= X_EMPTY;
- }
- else
- return 0;
- }
- else if (!_tcsnicmp (param, _T("errorlevel"), 10) && _istspace
(*(param + 10)))
- {
- /* Check for 'errorlevel' form */
- INT n = 0;
-
- pp = param + 10;
- while (_istspace (*pp))
- pp++;
-
- while (_istdigit (*pp))
- n = n * 10 + (*pp++ - _T('0'));
-
- x_flag ^= (nErrorLevel != n) ? 0 : X_EXEC;
-
- x_flag |= X_EMPTY; /* Syntax error if comd empty */
}
else
{
- BOOL bInQuote = FALSE;
- INT p1len;
- pp = param;
- while ( *pp && ( bInQuote || *pp != _T('=') ) )
+ /* Do case-insensitive string comparisons if /I specified */
+ INT (*StringCmp)(LPCTSTR, LPCTSTR) =
+ (Cmd->If.Flags & IFFLAG_IGNORECASE) ? _tcsicmp : _tcscmp;
+
+ if (Cmd->If.Operator == IF_STRINGEQ)
{
- if ( *pp == _T('\"') )
- bInQuote = !bInQuote;
- ++pp;
+ /* IF str1 == str2 */
+ result = StringCmp(Cmd->If.LeftArg, Cmd->If.RightArg) == 0;
}
- p1len = pp-param;
- /* check for "==" */
- if ( *pp++ != _T('=') || *pp++ != _T('=') )
+ else
{
- error_syntax ( NULL );
- return 1;
- }
- while (_istspace (*pp)) /* Skip subsequent spaces */
- pp++;
-
- /* are the two sides equal*/
- if ( !_tcsncmp(param,pp,p1len))
- x_flag ^= X_EXEC;
- pp += p1len;
-
- if ( x_flag )
- {
- x_flag |= X_EMPTY;
+ result = GenericCmp(StringCmp, Cmd->If.LeftArg, Cmd->If.RightArg);
+ switch (Cmd->If.Operator)
+ {
+ case IF_EQU: result = (result == 0); break;
+ case IF_NEQ: result = (result != 0); break;
+ case IF_LSS: result = (result < 0); break;
+ case IF_LEQ: result = (result <= 0); break;
+ case IF_GTR: result = (result > 0); break;
+ case IF_GEQ: result = (result >= 0); break;
+ }
}
}
- while (_istspace (*pp)) /* skip spaces */
- pp++;
-
- if (*pp == _T('('))
+ if (result ^ ((Cmd->If.Flags & IFFLAG_NEGATE) != 0))
{
- if (bc)
- {
- pp++;
- bc->bCmdBlock++;
- if ((bc->bCmdBlock >= 0) && (bc->bCmdBlock < MAX_PATH))
- bc->bExecuteBlock[bc->bCmdBlock] = x_flag & X_EXEC;
- /* commands are in the next lines */
- if (*pp == _T('\0'))
- return 0;
- }
+ /* full condition was true, do the command */
+ return ExecuteCommand(Cmd->Subcommands);
}
-
- if (x_flag & X_EMPTY)
+ else
{
- while (_istspace (*pp)) /* Then skip spaces */
- pp++;
-
- if (*pp == _T('\0')) /* If nothing left then syntax err */
- {
- error_syntax (NULL);
- return 1;
- }
+ /* full condition was false, do the "else" command if there is one */
+ if (Cmd->Subcommands->Next)
+ return ExecuteCommand(Cmd->Subcommands->Next);
+ return TRUE;
}
-
- if (x_flag & X_EXEC)
- {
- ParseCommandLine (pp);
- }
-
- return 0;
}
/* EOF */
Modified: trunk/reactos/base/shell/cmd/parser.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/parser.c?re…
==============================================================================
--- trunk/reactos/base/shell/cmd/parser.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/parser.c [iso-8859-1] Mon Dec 22 16:34:51 2008
@@ -1,3 +1,8 @@
+/*
+ * PARSER.C - command parsing.
+ *
+ */
+
#include <precomp.h>
#define C_OP_LOWEST C_MULTI
@@ -6,10 +11,28 @@
static const TCHAR RedirString[][3] = { _T("<"), _T(">"),
_T(">>") };
+static const TCHAR *const IfOperatorString[] = {
+ _T("cmdextversion"),
+ _T("defined"),
+ _T("errorlevel"),
+ _T("exist"),
+#define IF_MAX_UNARY IF_EXIST
+ _T("=="),
+ _T("equ"),
+ _T("gtr"),
+ _T("geq"),
+ _T("lss"),
+ _T("leq"),
+ _T("neq"),
+#define IF_MAX_COMPARISON IF_NEQ
+};
+
+/* These three characters act like spaces to the parser in most contexts */
+#define STANDARD_SEPS _T(",;=")
+
static BOOL IsSeparator(TCHAR Char)
{
- /* These three characters act like spaces to the parser */
- return _istspace(Char) || (Char && _tcschr(_T(",;="), Char));
+ return _istspace(Char) || (Char && _tcschr(STANDARD_SEPS, Char));
}
enum { TOK_END, TOK_NORMAL, TOK_OPERATOR, TOK_REDIRECTION,
@@ -70,35 +93,43 @@
/* 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)
+static int ParseToken(TCHAR ExtraEnd, TCHAR *Separators)
{
TCHAR *Out = CurrentToken;
- TCHAR Char = CurChar;
+ TCHAR Char;
int Type;
BOOL bInQuote = FALSE;
- if (!PreserveSpace)
- {
- while (Char != _T('\n') && IsSeparator(Char))
- Char = ParseChar();
- }
-
- while (Char && Char != _T('\n'))
+ for (Char = CurChar; Char && Char != _T('\n'); Char = ParseChar())
{
bInQuote ^= (Char == _T('"'));
if (!bInQuote)
{
- /* Check for all the myriad ways in which this token
- * may be brought to an untimely end. */
+ if (Separators != NULL)
+ {
+ if (_istspace(Char) || _tcschr(Separators, Char))
+ {
+ /* Skip leading separators */
+ if (Out == CurrentToken)
+ continue;
+ break;
+ }
+ }
+
+ /* Check for numbered redirection */
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))
+ && (*ParsePos == _T('<') || *ParsePos ==
_T('>'))))
{
break;
}
+
+ if (Char == ExtraEnd)
+ break;
+ if (InsideBlock && Char == _T(')'))
+ break;
+ if (_tcschr(_T("&|<>"), Char))
+ break;
if (Char == _T('^'))
{
@@ -112,7 +143,6 @@
if (Out == &CurrentToken[CMDLINE_LENGTH - 1])
break;
*Out++ = Char;
- Char = ParseChar();
}
/* Check if we got at least one character before reaching a special one.
@@ -214,7 +244,7 @@
if (!*Tok)
{
/* The file name was not part of this token, so it'll be the next one */
- if (ParseToken(0, FALSE) != TOK_NORMAL)
+ if (ParseToken(0, STANDARD_SEPS) != TOK_NORMAL)
goto fail;
Tok = CurrentToken;
}
@@ -284,7 +314,7 @@
InsideBlock--;
/* Process any trailing redirections */
- while (ParseToken(0, FALSE) == TOK_REDIRECTION)
+ while (ParseToken(0, STANDARD_SEPS) == TOK_REDIRECTION)
{
if (!ParseRedirection(&Cmd->Redirections))
{
@@ -292,6 +322,94 @@
return NULL;
}
}
+ return Cmd;
+}
+
+/* Parse an IF statement */
+static PARSED_COMMAND *ParseIf(void)
+{
+ PARSED_COMMAND *Cmd = cmd_alloc(sizeof(PARSED_COMMAND));
+ memset(Cmd, 0, sizeof(PARSED_COMMAND));
+ Cmd->Type = C_IF;
+
+ int Type = ParseToken(0, STANDARD_SEPS);
+ if (_tcsicmp(CurrentToken, _T("/I")) == 0)
+ {
+ Cmd->If.Flags |= IFFLAG_IGNORECASE;
+ Type = ParseToken(0, STANDARD_SEPS);
+ }
+ if (_tcsicmp(CurrentToken, _T("not")) == 0)
+ {
+ Cmd->If.Flags |= IFFLAG_NEGATE;
+ Type = ParseToken(0, STANDARD_SEPS);
+ }
+
+ if (Type != TOK_NORMAL)
+ {
+ FreeCommand(Cmd);
+ ParseError();
+ return NULL;
+ }
+
+ /* Check for unary operators */
+ for (; Cmd->If.Operator <= IF_MAX_UNARY; Cmd->If.Operator++)
+ {
+ if (_tcsicmp(CurrentToken, IfOperatorString[Cmd->If.Operator]) == 0)
+ {
+ if (ParseToken(0, STANDARD_SEPS) != TOK_NORMAL)
+ {
+ FreeCommand(Cmd);
+ ParseError();
+ return NULL;
+ }
+ Cmd->If.RightArg = cmd_dup(CurrentToken);
+ goto condition_done;
+ }
+ }
+
+ /* It must be a two-argument (comparison) operator. It could be ==, so
+ * the equals sign can't be treated as whitespace here. */
+ Cmd->If.LeftArg = cmd_dup(CurrentToken);
+ ParseToken(0, _T(",;"));
+
+ /* The right argument can come immediately after == */
+ if (_tcsnicmp(CurrentToken, _T("=="), 2) == 0 && CurrentToken[2])
+ {
+ Cmd->If.RightArg = cmd_dup(&CurrentToken[2]);
+ goto condition_done;
+ }
+
+ for (; Cmd->If.Operator <= IF_MAX_COMPARISON; Cmd->If.Operator++)
+ {
+ if (_tcsicmp(CurrentToken, IfOperatorString[Cmd->If.Operator]) == 0)
+ {
+ if (ParseToken(0, STANDARD_SEPS) != TOK_NORMAL)
+ break;
+ Cmd->If.RightArg = cmd_dup(CurrentToken);
+ goto condition_done;
+ }
+ }
+ FreeCommand(Cmd);
+ ParseError();
+ return NULL;
+
+condition_done:
+ Cmd->Subcommands = ParseCommandOp(C_OP_LOWEST);
+ if (Cmd->Subcommands == NULL)
+ {
+ FreeCommand(Cmd);
+ return NULL;
+ }
+ if (_tcsicmp(CurrentToken, _T("else")) == 0)
+ {
+ Cmd->Subcommands->Next = ParseCommandOp(C_OP_LOWEST);
+ if (Cmd->Subcommands->Next == NULL)
+ {
+ FreeCommand(Cmd);
+ return NULL;
+ }
+ }
+
return Cmd;
}
@@ -318,7 +436,7 @@
{
/* "Ignore" the rest of the line.
* (Line continuations will still be parsed, though.) */
- while (ParseToken(0, TRUE) != TOK_END)
+ while (ParseToken(0, NULL) != TOK_END)
;
return NULL;
}
@@ -339,7 +457,7 @@
/* Get the head of the command */
while (1)
{
- Type = ParseToken(_T('('), FALSE);
+ Type = ParseToken(_T('('), STANDARD_SEPS);
if (Type == TOK_NORMAL)
{
Pos = _stpcpy(ParsedLine, CurrentToken);
@@ -367,12 +485,22 @@
}
TailOffset = Pos - ParsedLine;
- /* FIXME: FOR, IF, and REM need special processing by the parser. */
+ /* Check for special forms */
+ if (_tcsicmp(ParsedLine, _T("if")) == 0)
+ {
+ if (RedirList)
+ {
+ ParseError();
+ FreeRedirection(RedirList);
+ return NULL;
+ }
+ return ParseIf();
+ }
/* Now get the tail */
while (1)
{
- Type = ParseToken(0, TRUE);
+ Type = ParseToken(0, NULL);
if (Type == TOK_NORMAL)
{
if (Pos + _tcslen(CurrentToken) >= &ParsedLine[CMDLINE_LENGTH])
@@ -394,13 +522,13 @@
}
}
- Cmd = cmd_alloc(FIELD_OFFSET(PARSED_COMMAND, CommandLine[Pos + 1 - ParsedLine]));
+ Cmd = cmd_alloc(FIELD_OFFSET(PARSED_COMMAND, 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;
+ _tcscpy(Cmd->Command.CommandLine, ParsedLine);
+ Cmd->Command.Tail = Cmd->Command.CommandLine + TailOffset;
return Cmd;
}
@@ -487,7 +615,7 @@
switch (Cmd->Type)
{
case C_COMMAND:
- ConOutPrintf(_T("%s"), Cmd->CommandLine);
+ ConOutPrintf(_T("%s"), Cmd->Command.CommandLine);
break;
case C_QUIET:
return;
@@ -509,6 +637,23 @@
ConOutPrintf(_T(" %s "), OpString[Cmd->Type - C_OP_LOWEST]);
EchoCommand(Sub->Next);
break;
+ case C_IF:
+ ConOutPrintf(_T("if"));
+ if (Cmd->If.Flags & IFFLAG_IGNORECASE)
+ 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);
+ Sub = Cmd->Subcommands;
+ EchoCommand(Sub);
+ if (Sub->Next)
+ {
+ ConOutPrintf(_T(" else "));
+ EchoCommand(Sub->Next);
+ }
+ break;
}
for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next)
@@ -526,5 +671,10 @@
if (Cmd->Next)
FreeCommand(Cmd->Next);
FreeRedirection(Cmd->Redirections);
+ if (Cmd->Type == C_IF)
+ {
+ cmd_free(Cmd->If.LeftArg);
+ cmd_free(Cmd->If.RightArg);
+ }
cmd_free(Cmd);
}