mirror of
https://github.com/reactos/reactos.git
synced 2025-01-07 14:51:00 +00:00
- 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:
parent
16ab5c9a07
commit
8b52a8e50a
6 changed files with 160 additions and 86 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue