- 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.

svn path=/trunk/; revision=35530
This commit is contained in:
Jeffrey Morlan 2008-08-22 14:37:11 +00:00
parent 16ab5c9a07
commit 8b52a8e50a
6 changed files with 160 additions and 86 deletions

View file

@ -332,10 +332,9 @@ VOID AddBatchRedirection(REDIRECTION **RedirList)
* 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 @@ LPTSTR ReadBatchLine (LPBOOL bLocalEcho)
*dp = _T('\0');
*bLocalEcho = bEcho;
return textline;
}
@ -446,14 +443,7 @@ LPTSTR ReadBatchLine (LPBOOL bLocalEcho)
}
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 @@ LPTSTR ReadBatchLine (LPBOOL bLocalEcho)
}
}
/* 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;
}

View file

@ -44,7 +44,7 @@ LPTSTR FindArg (INT);
LPTSTR BatchParams (LPTSTR, LPTSTR);
VOID ExitBatch (LPTSTR);
BOOL Batch (LPTSTR, LPTSTR, LPTSTR);
LPTSTR ReadBatchLine (LPBOOL);
LPTSTR ReadBatchLine();
VOID AddBatchRedirection(REDIRECTION **);
#endif /* _BATCH_H_INCLUDED_ */

View file

@ -1239,60 +1239,86 @@ too_long:
*
*/
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);
EchoCommand(Cmd);
ConOutChar(_T('\n'));
}
/* 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;
}
ExecuteCommand(Cmd);
if (bEcho && !bIgnoreEcho && (!bIsBatch || Cmd->Type != C_QUIET))
ConOutChar ('\n');
FreeCommand(Cmd);
bIgnoreEcho = FALSE;
}
while (!bCanExit || !bExit);

View file

@ -103,6 +103,7 @@ LPCTSTR GetEnvVarOrSpecial ( LPCTSTR varName );
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 @@ typedef struct _PARSED_COMMAND
TCHAR CommandLine[];
} PARSED_COMMAND;
PARSED_COMMAND *ParseCommand(LPTSTR Line);
VOID EchoCommand(PARSED_COMMAND *Cmd);
VOID FreeCommand(PARSED_COMMAND *Cmd);

View file

@ -152,10 +152,6 @@ VOID ReadCommand (LPTSTR str, INT maxlen)
/* 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 @@ VOID ReadCommand (LPTSTR str, INT maxlen)
if (str[0])
History (0, str);
#endif
str[charcount++] = _T('\n');
str[charcount] = _T('\0');
ConInDummy ();
ConOutChar (_T('\n'));
bReturn = TRUE;

View file

@ -29,7 +29,10 @@ static TCHAR ParseChar()
{
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 @@ static TCHAR ParseChar()
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 @@ static int ParseToken(TCHAR ExtraEnd, BOOL PreserveSpace)
/* 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 @@ static PARSED_COMMAND *ParseBlock(REDIRECTION *RedirList)
/* Read the block contents */
NextPtr = &Cmd->Subcommands;
InsideBlock++;
do
while (1)
{
Sub = ParseCommandOp(C_OP_LOWEST);
if (Sub)
@ -261,7 +275,12 @@ static PARSED_COMMAND *ParseBlock(REDIRECTION *RedirList)
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 @@ static PARSED_COMMAND *ParseCommandPart(void)
{
return ParseBlock(RedirList);
}
else if (Type == TOK_END_BLOCK && !RedirList)
{
return NULL;
}
else
{
ParseError();
@ -352,7 +375,12 @@ static PARSED_COMMAND *ParseCommandPart(void)
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 @@ ParseCommand(LPTSTR Line)
}
else
{
/*if (!ReadLine(ParseLine, FALSE))*/
if (!ReadLine(ParseLine, FALSE))
return NULL;
bLineContinuations = TRUE;
}
@ -435,15 +463,61 @@ ParseCommand(LPTSTR Line)
CurChar = _T(' ');
Cmd = ParseCommandOp(C_OP_LOWEST);
if (Cmd && CurrentTokenType != TOK_END)
if (Cmd)
{
ParseError();
FreeCommand(Cmd);
Cmd = NULL;
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
FreeCommand(PARSED_COMMAND *Cmd)
{