Author: jmorlan
Date: Fri Aug 22 09:37:11 2008
New Revision: 35530
URL:
http://svn.reactos.org/svn/reactos?rev=35530&view=rev
Log:
- Extract the line-reading code in ProcessInput to a separate function (ReadLine) that the
parser can call. Now line continuations (using ^ at the end of a line) and multi-line
parenthesized blocks work.
- ReadBatchLine: Don't strip the trailing \n, the parser needs it. Remove handling of
:labels and @quiet commands, now done by the parser.
- ReadCommand: Add a \n to the line. Move PrintPrompt call out, since the prompt
shouldn't be printed for additional lines read in a command beyond the first.
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/cmdinput.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] Fri Aug 22 09:37:11 2008
@@ -332,10 +332,9 @@
* Set eflag to 0 if line is not to be echoed else 1
*/
-LPTSTR ReadBatchLine (LPBOOL bLocalEcho)
+LPTSTR ReadBatchLine ()
{
LPTSTR first;
- LPTSTR ip;
/* No batch */
if (bc == NULL)
@@ -428,8 +427,6 @@
*dp = _T('\0');
- *bLocalEcho = bEcho;
-
return textline;
}
@@ -446,14 +443,7 @@
}
TRACE ("ReadBatchLine(): textline: \'%s\'\n",
debugstr_aw(textline));
- /* Strip leading spaces and trailing space/control chars */
- for (first = textline; _istspace (*first); first++)
- ;
-
- for (ip = first + _tcslen (first) - 1; _istspace (*ip) || _istcntrl (*ip); ip--)
- ;
-
- *++ip = _T('\0');
+ first = textline;
/* cmd block over multiple lines (..) */
if (bc->bCmdBlock >= 0)
@@ -488,22 +478,6 @@
}
}
- /* ignore labels and empty lines */
- if (*first == _T(':') || *first == 0)
- continue;
-
- if (*first == _T('@'))
- {
- /* don't echo this line */
- do
- first++;
- while (_istspace (*first));
-
- *bLocalEcho = 0;
- }
- else
- *bLocalEcho = bEcho;
-
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] Fri Aug 22 09:37:11 2008
@@ -44,7 +44,7 @@
LPTSTR BatchParams (LPTSTR, LPTSTR);
VOID ExitBatch (LPTSTR);
BOOL Batch (LPTSTR, LPTSTR, LPTSTR);
-LPTSTR ReadBatchLine (LPBOOL);
+LPTSTR ReadBatchLine();
VOID AddBatchRedirection(REDIRECTION **);
#endif /* _BATCH_H_INCLUDED_ */
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] Fri Aug 22 09:37:11 2008
@@ -1239,60 +1239,86 @@
*
*/
+BOOL bNoInteractive;
+BOOL bIsBatch;
+
+BOOL
+ReadLine (TCHAR *commandline, BOOL bMore)
+{
+ TCHAR readline[CMDLINE_LENGTH];
+ LPTSTR ip;
+
+ /* if no batch input then... */
+ if (!(ip = ReadBatchLine()))
+ {
+ if (bNoInteractive)
+ {
+ bExit = TRUE;
+ return FALSE;
+ }
+
+ if (bMore)
+ {
+ ConOutPrintf(_T("More? "));
+ }
+ else
+ {
+ /* JPP 19980807 - if echo off, don't print prompt */
+ if (bEcho)
+ PrintPrompt();
+ }
+
+ ReadCommand (readline, CMDLINE_LENGTH - 1);
+ if (CheckCtrlBreak(BREAK_INPUT))
+ {
+ ConOutPuts(_T("\n"));
+ return FALSE;
+ }
+ ip = readline;
+ bIsBatch = FALSE;
+ }
+ else
+ {
+ bIsBatch = TRUE;
+ }
+
+ if (!SubstituteVars(ip, commandline, _T('%'), bIsBatch))
+ return FALSE;
+
+ /* FIXME: !vars! should be substituted later, after parsing. */
+ if (!SubstituteVars(commandline, readline, _T('!'), bIsBatch))
+ return FALSE;
+ _tcscpy(commandline, readline);
+
+ return TRUE;
+}
+
static INT
ProcessInput (BOOL bFlag)
{
- TCHAR commandline[CMDLINE_LENGTH];
- TCHAR readline[CMDLINE_LENGTH];
- LPTSTR ip;
- BOOL bEchoThisLine;
- BOOL bIsBatch;
-
+ PARSED_COMMAND *Cmd;
+
+ bNoInteractive = bFlag;
do
{
- /* if no batch input then... */
- if (!(ip = ReadBatchLine (&bEchoThisLine)))
- {
- if (bFlag)
- return nErrorLevel;
-
- ReadCommand (readline, CMDLINE_LENGTH);
- ip = readline;
- bEchoThisLine = FALSE;
- bIsBatch = FALSE;
- }
- else
- {
- bIsBatch = TRUE;
- }
-
- /* skip leading blanks */
- while ( _istspace(*ip) )
- ++ip;
-
- if (!SubstituteVars(ip, commandline, _T('%'), bIsBatch))
+ Cmd = ParseCommand(NULL);
+ if (!Cmd)
continue;
/* JPP 19980807 */
/* Echo batch file line */
- if (bEchoThisLine)
+ if (bIsBatch && bEcho && Cmd->Type != C_QUIET)
{
PrintPrompt ();
- ConOutPuts (commandline);
- }
-
- /* FIXME: !vars! should be substituted later, after parsing. */
- if (!SubstituteVars(commandline, readline, _T('!'), bIsBatch))
- continue;
- _tcscpy(commandline, readline);
-
- if (!CheckCtrlBreak(BREAK_INPUT) && *commandline)
- {
- ParseCommandLine (commandline);
- if (bEcho && !bIgnoreEcho && (!bIsBatch || bEchoThisLine))
- ConOutChar ('\n');
- bIgnoreEcho = FALSE;
- }
+ EchoCommand(Cmd);
+ ConOutChar(_T('\n'));
+ }
+
+ ExecuteCommand(Cmd);
+ if (bEcho && !bIgnoreEcho && (!bIsBatch || Cmd->Type != C_QUIET))
+ ConOutChar ('\n');
+ FreeCommand(Cmd);
+ bIgnoreEcho = FALSE;
}
while (!bCanExit || !bExit);
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] Fri Aug 22 09:37:11 2008
@@ -103,6 +103,7 @@
VOID AddBreakHandler (VOID);
VOID RemoveBreakHandler (VOID);
BOOL DoCommand (LPTSTR line);
+BOOL ReadLine(TCHAR *commandline, BOOL bMore);
int cmd_main (int argc, const TCHAR *argv[]);
extern HANDLE CMD_ModuleHandle;
@@ -340,6 +341,7 @@
TCHAR CommandLine[];
} PARSED_COMMAND;
PARSED_COMMAND *ParseCommand(LPTSTR Line);
+VOID EchoCommand(PARSED_COMMAND *Cmd);
VOID FreeCommand(PARSED_COMMAND *Cmd);
Modified: trunk/reactos/base/shell/cmd/cmdinput.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/cmdinput.c?…
==============================================================================
--- trunk/reactos/base/shell/cmd/cmdinput.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/cmdinput.c [iso-8859-1] Fri Aug 22 09:37:11 2008
@@ -152,10 +152,6 @@
/* get screen size */
GetScreenSize (&maxx, &maxy);
- /* JPP 19980807 - if echo off, don't print prompt */
- if (bEcho)
- PrintPrompt();
-
GetCursorXY (&orgx, &orgy);
GetCursorXY (&curx, &cury);
@@ -431,6 +427,8 @@
if (str[0])
History (0, str);
#endif
+ str[charcount++] = _T('\n');
+ str[charcount] = _T('\0');
ConInDummy ();
ConOutChar (_T('\n'));
bReturn = TRUE;
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] Fri Aug 22 09:37:11 2008
@@ -29,7 +29,10 @@
{
TCHAR Char;
-//restart:
+ if (bParseError)
+ return CurChar = 0;
+
+restart:
/* Although CRs can be injected into a line via an environment
* variable substitution, the parser ignores them - they won't
* even separate tokens. */
@@ -39,9 +42,19 @@
if (!Char)
{
- /*if (bLineContinuations)
- if (ReadLine(ParseLine, TRUE) && *(ParsePos = ParseLine))
- goto restart;*/
+ ParsePos--;
+ if (bLineContinuations)
+ {
+ if (!ReadLine(ParseLine, TRUE))
+ {
+ /* ^C pressed, or line was too long */
+ bParseError = TRUE;
+ }
+ else if (*(ParsePos = ParseLine))
+ {
+ goto restart;
+ }
+ }
}
return CurChar = Char;
}
@@ -96,7 +109,8 @@
/* Next character is a forced literal */
}
}
- /* FIXME: potential buffer overflow here */
+ if (Out == &CurrentToken[CMDLINE_LENGTH - 1])
+ break;
*Out++ = Char;
Char = ParseChar();
}
@@ -247,7 +261,7 @@
/* Read the block contents */
NextPtr = &Cmd->Subcommands;
InsideBlock++;
- do
+ while (1)
{
Sub = ParseCommandOp(C_OP_LOWEST);
if (Sub)
@@ -261,7 +275,12 @@
FreeCommand(Cmd);
return NULL;
}
- } while (CurrentTokenType != TOK_END_BLOCK);
+
+ if (CurrentTokenType == TOK_END_BLOCK)
+ break;
+ /* Skip past the \n */
+ ParseChar();
+ }
InsideBlock--;
/* Process any trailing redirections */
@@ -335,6 +354,10 @@
{
return ParseBlock(RedirList);
}
+ else if (Type == TOK_END_BLOCK && !RedirList)
+ {
+ return NULL;
+ }
else
{
ParseError();
@@ -352,7 +375,12 @@
Type = ParseToken(0, TRUE);
if (Type == TOK_NORMAL)
{
- /* FIXME: potential buffer overflow here */
+ if (Pos + _tcslen(CurrentToken) >= &ParsedLine[CMDLINE_LENGTH])
+ {
+ ParseError();
+ FreeRedirection(RedirList);
+ return NULL;
+ }
Pos = _stpcpy(Pos, CurrentToken);
}
else if (Type == TOK_REDIRECTION)
@@ -426,7 +454,7 @@
}
else
{
- /*if (!ReadLine(ParseLine, FALSE))*/
+ if (!ReadLine(ParseLine, FALSE))
return NULL;
bLineContinuations = TRUE;
}
@@ -435,13 +463,59 @@
CurChar = _T(' ');
Cmd = ParseCommandOp(C_OP_LOWEST);
- if (Cmd && CurrentTokenType != TOK_END)
- {
- ParseError();
- FreeCommand(Cmd);
- Cmd = NULL;
+ if (Cmd)
+ {
+ if (CurrentTokenType != TOK_END)
+ ParseError();
+ if (bParseError)
+ {
+ FreeCommand(Cmd);
+ Cmd = NULL;
+ }
}
return Cmd;
+}
+
+/* Reconstruct a parse tree into text form;
+ * used for echoing batch file commands */
+VOID
+EchoCommand(PARSED_COMMAND *Cmd)
+{
+ PARSED_COMMAND *Sub;
+ REDIRECTION *Redir;
+
+ switch (Cmd->Type)
+ {
+ case C_COMMAND:
+ ConOutPrintf(_T("%s"), Cmd->CommandLine);
+ break;
+ case C_QUIET:
+ return;
+ case C_BLOCK:
+ ConOutChar(_T('('));
+ for (Sub = Cmd->Subcommands; Sub; Sub = Sub->Next)
+ {
+ EchoCommand(Sub);
+ ConOutChar(_T('\n'));
+ }
+ ConOutChar(_T(')'));
+ break;
+ case C_MULTI:
+ case C_IFFAILURE:
+ case C_IFSUCCESS:
+ case C_PIPE:
+ Sub = Cmd->Subcommands;
+ EchoCommand(Sub);
+ ConOutPrintf(_T(" %s "), OpString[Cmd->Type - C_OP_LOWEST]);
+ EchoCommand(Sub->Next);
+ break;
+ }
+
+ for (Redir = Cmd->Redirections; Redir; Redir = Redir->Next)
+ {
+ ConOutPrintf(_T(" %c%s%s"), _T('0') + Redir->Number,
+ RedirString[Redir->Type], Redir->Filename);
+ }
}
VOID