diff --git a/reactos/base/shell/cmd/batch.c b/reactos/base/shell/cmd/batch.c index 752eb1f9bc7..aae78e7f2e5 100644 --- a/reactos/base/shell/cmd/batch.c +++ b/reactos/base/shell/cmd/batch.c @@ -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; } diff --git a/reactos/base/shell/cmd/batch.h b/reactos/base/shell/cmd/batch.h index badf2b57e38..e93e3254cee 100644 --- a/reactos/base/shell/cmd/batch.h +++ b/reactos/base/shell/cmd/batch.h @@ -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_ */ diff --git a/reactos/base/shell/cmd/cmd.c b/reactos/base/shell/cmd/cmd.c index 572ffb0ca95..d3e6d03d920 100644 --- a/reactos/base/shell/cmd/cmd.c +++ b/reactos/base/shell/cmd/cmd.c @@ -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); diff --git a/reactos/base/shell/cmd/cmd.h b/reactos/base/shell/cmd/cmd.h index 87dce182016..9d709e6247a 100644 --- a/reactos/base/shell/cmd/cmd.h +++ b/reactos/base/shell/cmd/cmd.h @@ -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); diff --git a/reactos/base/shell/cmd/cmdinput.c b/reactos/base/shell/cmd/cmdinput.c index 573a21b62ac..fd3560a43b3 100644 --- a/reactos/base/shell/cmd/cmdinput.c +++ b/reactos/base/shell/cmd/cmdinput.c @@ -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; diff --git a/reactos/base/shell/cmd/parser.c b/reactos/base/shell/cmd/parser.c index a2cdb6c29ad..287110a2dfa 100644 --- a/reactos/base/shell/cmd/parser.c +++ b/reactos/base/shell/cmd/parser.c @@ -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) {