[ros-diffs] [jmorlan] 35514: - 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.

jmorlan at svn.reactos.org jmorlan at svn.reactos.org
Thu Aug 21 22:18:35 CEST 2008


Author: jmorlan
Date: Thu Aug 21 15:18:35 2008
New Revision: 35514

URL: http://svn.reactos.org/svn/reactos?rev=35514&view=rev
Log:
- 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.

Added:
    trunk/reactos/base/shell/cmd/parser.c   (with props)
Modified:
    trunk/reactos/base/shell/cmd/cmd.c
    trunk/reactos/base/shell/cmd/cmd.h
    trunk/reactos/base/shell/cmd/cmd.rbuild
    trunk/reactos/base/shell/cmd/echo.c
    trunk/reactos/base/shell/cmd/redir.c
    trunk/reactos/base/shell/cmd/set.c

Modified: trunk/reactos/base/shell/cmd/cmd.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/cmd.c?rev=35514&r1=35513&r2=35514&view=diff
==============================================================================
--- trunk/reactos/base/shell/cmd/cmd.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/cmd.c [iso-8859-1] Thu Aug 21 15:18:35 2008
@@ -323,7 +323,7 @@
  * Rest  - rest of command line
  */
 
-static VOID
+static BOOL
 Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
 {
 	TCHAR *szFullName=NULL;
@@ -345,7 +345,7 @@
 	{
 		error_out_of_memory();
                 nErrorLevel = 1;
-		return ;
+		return FALSE;
 	}
 
 	rest = cmd_alloc ( (_tcslen(Rest) + 512) * sizeof(TCHAR));
@@ -354,7 +354,7 @@
 		cmd_free (first);
 		error_out_of_memory();
                 nErrorLevel = 1;
-		return ;
+		return FALSE;
 	}
 
 	full = cmd_alloc ( (_tcslen(Full) + 512) * sizeof(TCHAR));
@@ -364,7 +364,7 @@
 		cmd_free (rest);
 		error_out_of_memory();
                 nErrorLevel = 1;
-		return ;
+		return FALSE;
 	}
 
 	szFullName = cmd_alloc ( (_tcslen(Full) + 512) * sizeof(TCHAR));
@@ -375,7 +375,7 @@
 		cmd_free (full);
 		error_out_of_memory();
                 nErrorLevel = 1;
-		return ;
+		return FALSE;
 	}
 
 
@@ -446,7 +446,7 @@
 		cmd_free (full);
 		cmd_free (szFullName);
                 nErrorLevel = 1;
-		return;
+		return working;
 	}
 
 	/* get the PATH environment variable and parse it */
@@ -459,7 +459,7 @@
 			cmd_free (full);
 			cmd_free (szFullName);
                         nErrorLevel = 1;
-			return;
+			return FALSE;
 
 	}
 
@@ -554,6 +554,7 @@
 	cmd_free(rest);
 	cmd_free(full);
 	cmd_free (szFullName);
+	return nErrorLevel == 0;
 }
 
 
@@ -566,7 +567,7 @@
  *
  */
 
-VOID
+BOOL
 DoCommand (LPTSTR line)
 {
 	TCHAR *com = NULL;  /* the first word in the command */
@@ -575,6 +576,7 @@
 	LPTSTR rest;   /* pointer to the rest of the command line */
 	INT cl;
 	LPCOMMAND cmdptr;
+	BOOL ret = TRUE;
 
 	TRACE ("DoCommand: (\'%s\')\n", debugstr_aw(line));
 
@@ -582,7 +584,7 @@
 	if (com == NULL)
 	{
 		error_out_of_memory();
-		return;
+		return FALSE;
 	}
 
 	cp = com;
@@ -640,7 +642,7 @@
 			/* If end of table execute ext cmd */
 			if (cmdptr->name == NULL)
 			{
-				Execute (line, com, rest);
+				ret = Execute (line, com, rest);
 				break;
 			}
 
@@ -677,6 +679,7 @@
 		}
 	}
 	cmd_free(com);
+	return ret;
 }
 
 
@@ -687,25 +690,28 @@
 
 VOID ParseCommandLine (LPTSTR cmd)
 {
-	TCHAR cmdline[CMDLINE_LENGTH];
-	LPTSTR s;
+	PARSED_COMMAND *Cmd = ParseCommand(cmd);
+	if (Cmd)
+	{
+		ExecuteCommand(Cmd);
+		FreeCommand(Cmd);
+	}
+}
+
+static VOID
+ExecutePipeline(PARSED_COMMAND *Cmd)
+{
 #ifdef FEATURE_REDIRECTION
-	REDIRECTION *RedirList = NULL;
 	TCHAR szTempPath[MAX_PATH] = _T(".\\");
 	TCHAR szFileName[2][MAX_PATH] = {_T(""), _T("")};
 	HANDLE hFile[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
-	INT  num = 0;
 	INT  Length;
 	UINT Attributes;
-	BOOL bNewBatch = TRUE;
 	HANDLE hOldConIn;
 	HANDLE hOldConOut;
 #endif /* FEATURE_REDIRECTION */
 
-	_tcscpy (cmdline, cmd);
-	s = &cmdline[0];
-
-	TRACE ("ParseCommandLine: (\'%s\')\n", debugstr_aw(s));
+	//TRACE ("ParseCommandLine: (\'%s\')\n", debugstr_aw(s));
 
 #ifdef FEATURE_REDIRECTION
 	/* find the temp path to store temporary files */
@@ -726,15 +732,6 @@
 	if (szTempPath[_tcslen (szTempPath) - 1] != _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 ... */
 	/* preserve STDIN and STDOUT handles */
 	hOldConIn  = GetStdHandle (STD_INPUT_HANDLE);
@@ -744,7 +741,7 @@
 	*szFileName[0] = _T('\0');
 	hFile[0] = INVALID_HANDLE_VALUE;
 
-	while (num-- > 1)
+	while (Cmd->Type == C_PIPE)
 	{
 		SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
 
@@ -766,7 +763,7 @@
 
 		SetStdHandle (STD_OUTPUT_HANDLE, hFile[1]);
 
-		DoCommand (s);
+		ExecuteCommand(Cmd->Subcommands);
 
 		/* close stdout file */
 		SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut);
@@ -799,22 +796,18 @@
 		                       OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
 		SetStdHandle (STD_INPUT_HANDLE, hFile[0]);
 
-		s = s + _tcslen (s) + 1;
+		Cmd = Cmd->Subcommands->Next;
 	}
 
 	/* Now set up the end conditions... */
 	SetStdHandle(STD_OUTPUT_HANDLE, hOldConOut);
 
-	if(bc)
-		bNewBatch = FALSE;
 #endif
 
 	/* process final command */
-	DoCommand (s);
+	ExecuteCommand(Cmd);
 
 #ifdef FEATURE_REDIRECTION
-	if(bNewBatch && bc)
-		AddBatchRedirection(&RedirList);
 	/* close old stdin file */
 #if 0  /* buggy implementation */
 	SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
@@ -870,10 +863,53 @@
 			}
 		}
 	}
-
-	UndoRedirection(RedirList, NULL);
-	FreeRedirection(RedirList);
 #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

Modified: trunk/reactos/base/shell/cmd/cmd.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/cmd.h?rev=35514&r1=35513&r2=35514&view=diff
==============================================================================
--- trunk/reactos/base/shell/cmd/cmd.h [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/cmd.h [iso-8859-1] Thu Aug 21 15:18:35 2008
@@ -97,10 +97,12 @@
 /* Prototypes for CMD.C */
 INT ConvertULargeInteger (ULARGE_INTEGER num, LPTSTR des, INT len, BOOL bPutSeperator);
 VOID ParseCommandLine (LPTSTR);
+struct _PARSED_COMMAND;
+BOOL ExecuteCommand(struct _PARSED_COMMAND *Cmd);
 LPCTSTR GetEnvVarOrSpecial ( LPCTSTR varName );
 VOID AddBreakHandler (VOID);
 VOID RemoveBreakHandler (VOID);
-VOID DoCommand (LPTSTR line);
+BOOL DoCommand (LPTSTR line);
 int cmd_main (int argc, const TCHAR *argv[]);
 
 extern HANDLE CMD_ModuleHandle;
@@ -326,6 +328,21 @@
 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 */
 INT cmd_path (LPTSTR, LPTSTR);
 

Modified: trunk/reactos/base/shell/cmd/cmd.rbuild
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/cmd.rbuild?rev=35514&r1=35513&r2=35514&view=diff
==============================================================================
--- trunk/reactos/base/shell/cmd/cmd.rbuild [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/cmd.rbuild [iso-8859-1] Thu Aug 21 15:18:35 2008
@@ -44,6 +44,7 @@
 			<file>misc.c</file>
 			<file>move.c</file>
 			<file>msgbox.c</file>
+			<file>parser.c</file>
 			<file>path.c</file>
 			<file>pause.c</file>
 			<file>prompt.c</file>

Modified: trunk/reactos/base/shell/cmd/echo.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/echo.c?rev=35514&r1=35513&r2=35514&view=diff
==============================================================================
--- trunk/reactos/base/shell/cmd/echo.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/echo.c [iso-8859-1] Thu Aug 21 15:18:35 2008
@@ -83,16 +83,6 @@
                 }
 		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);
 		}
 		else

Added: trunk/reactos/base/shell/cmd/parser.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/parser.c?rev=35514&view=auto
==============================================================================
--- trunk/reactos/base/shell/cmd/parser.c (added)
+++ trunk/reactos/base/shell/cmd/parser.c [iso-8859-1] Thu Aug 21 15:18:35 2008
@@ -1,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);
+}

Propchange: trunk/reactos/base/shell/cmd/parser.c
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: trunk/reactos/base/shell/cmd/redir.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/redir.c?rev=35514&r1=35513&r2=35514&view=diff
==============================================================================
--- trunk/reactos/base/shell/cmd/redir.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/redir.c [iso-8859-1] Thu Aug 21 15:18:35 2008
@@ -29,175 +29,6 @@
 
 #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
  * correspond to any STD_ constant. */

Modified: trunk/reactos/base/shell/cmd/set.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/set.c?rev=35514&r1=35513&r2=35514&view=diff
==============================================================================
--- trunk/reactos/base/shell/cmd/set.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/set.c [iso-8859-1] Thu Aug 21 15:18:35 2008
@@ -53,22 +53,12 @@
 
 INT cmd_set (LPTSTR cmd, LPTSTR param)
 {
-	INT i;
 	LPTSTR p;
 
 	if ( !_tcsncmp (param, _T("/?"), 2) )
 	{
 		ConOutResPaging(TRUE,STRING_SET_HELP);
 		return 0;
-	}
-
-	/* remove escapes */
-	if ( param[0] ) for ( i = 0; param[i+1]; i++ )
-	{
-		if ( param[i] == _T('^') )
-		{
-			memmove ( &param[i], &param[i+1], _tcslen(&param[i]) * sizeof(TCHAR) );
-		}
 	}
 
 	/* if no parameters, show the environment */



More information about the Ros-diffs mailing list