From db8815a497d233cc2ed0b3ee061b3c58fdffbdd9 Mon Sep 17 00:00:00 2001 From: Jeffrey Morlan Date: Thu, 26 Mar 2009 01:14:25 +0000 Subject: [PATCH] - Implement CMD /D, /Q, and /R switches - Do %envvar% expansions in CMD /C or /K commands - Make SETLOCAL recognize ENABLEEXTENSIONS and DISABLEEXTENSIONS, although it doesn't do anything yet - Make VERIFY set the errorlevel (documented in SETLOCAL /?). Also make it recognize when ON/OFF is followed by space - Make ECHOSERR actually print to stderr, not stdout - Make echoed display of ( ... ) blocks look nicer (Bug 4022) - Fix some other minor display bugs svn path=/trunk/; revision=40244 --- reactos/base/shell/cmd/batch.c | 5 +- reactos/base/shell/cmd/cmd.c | 79 +++++++++++++++------------- reactos/base/shell/cmd/cmd.h | 2 + reactos/base/shell/cmd/echo.c | 85 +++++++++++++++---------------- reactos/base/shell/cmd/error.c | 2 +- reactos/base/shell/cmd/for.c | 5 +- reactos/base/shell/cmd/parser.c | 22 +++++++- reactos/base/shell/cmd/setlocal.c | 28 +++++++--- reactos/base/shell/cmd/verify.c | 17 ++----- 9 files changed, 139 insertions(+), 106 deletions(-) diff --git a/reactos/base/shell/cmd/batch.c b/reactos/base/shell/cmd/batch.c index e8c2b0768b5..aab0b67d8c8 100644 --- a/reactos/base/shell/cmd/batch.c +++ b/reactos/base/shell/cmd/batch.c @@ -293,9 +293,10 @@ BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd /* JPP 19980807 */ /* Echo batch file line */ - if (bEcho && Cmd->Type != C_QUIET) + if (bEcho && !bDisableBatchEcho && Cmd->Type != C_QUIET) { - ConOutChar(_T('\n')); + if (!bIgnoreEcho) + ConOutChar(_T('\n')); PrintPrompt(); EchoCommand(Cmd); ConOutChar(_T('\n')); diff --git a/reactos/base/shell/cmd/cmd.c b/reactos/base/shell/cmd/cmd.c index a7e0e53a772..5a4f3d4ebdd 100644 --- a/reactos/base/shell/cmd/cmd.c +++ b/reactos/base/shell/cmd/cmd.c @@ -157,6 +157,7 @@ BOOL bCtrlBreak = FALSE; /* Ctrl-Break or Ctrl-C hit */ BOOL bIgnoreEcho = FALSE; /* Set this to TRUE to prevent a newline, when executing a command */ INT nErrorLevel = 0; /* Errorlevel of last launched external program */ BOOL bChildProcessRunning = FALSE; +BOOL bDisableBatchEcho = FALSE; BOOL bDelayedExpansion = FALSE; DWORD dwChildProcessId = 0; OSVERSIONINFO osvi; @@ -1509,7 +1510,11 @@ ReadLine (TCHAR *commandline, BOOL bMore) { /* JPP 19980807 - if echo off, don't print prompt */ if (bEcho) + { + if (!bIgnoreEcho) + ConOutChar('\n'); PrintPrompt(); + } } ReadCommand (readline, CMDLINE_LENGTH - 1); @@ -1542,10 +1547,7 @@ ProcessInput() continue; ExecuteCommand(Cmd); - if (bEcho && !bIgnoreEcho) - ConOutChar ('\n'); FreeCommand(Cmd); - bIgnoreEcho = FALSE; } while (!bCanExit || !bExit); @@ -1676,7 +1678,8 @@ ExecuteAutoRunFile (VOID) (LPBYTE)autorun, &len) == ERROR_SUCCESS) { - ParseCommandLine (autorun); + if (*autorun) + ParseCommandLine(autorun); } } @@ -1748,9 +1751,9 @@ Initialize() TCHAR lpBuffer[2]; //INT len; - TCHAR *ptr, *cmdLine; + TCHAR *ptr, *cmdLine, option = 0; BOOL AlwaysStrip = FALSE; - BOOL ShowVersion = TRUE; + BOOL AutoRun = TRUE; /* get version information */ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); @@ -1793,12 +1796,13 @@ Initialize() { if (*ptr == _T('/')) { - if (ptr[1] == _T('?')) + option = _totupper(ptr[1]); + if (option == _T('?')) { ConOutResPaging(TRUE,STRING_CMD_HELP8); cmd_exit(0); } - else if (_totlower(ptr[1]) == _T('p')) + else if (option == _T('P')) { if (!IsExistingFile (_T("\\autoexec.bat"))) { @@ -1815,27 +1819,25 @@ Initialize() } bCanExit = FALSE; } - else if (_totlower(ptr[1]) == _T('c')) + else if (option == _T('C') || option == _T('K') || option == _T('R')) { - /* This just runs a program and exits */ - GetCmdLineCommand(commandline, &ptr[2], AlwaysStrip); - ParseCommandLine(commandline); - cmd_exit(nErrorLevel); - } - else if (_totlower(ptr[1]) == _T('k')) - { - /* This just runs a program and remains */ - GetCmdLineCommand(commandline, &ptr[2], AlwaysStrip); - ParseCommandLine(commandline); - ShowVersion = FALSE; + /* Remainder of command line is a command to be run */ break; } - else if (_totlower(ptr[1]) == _T('s')) + else if (option == _T('D')) + { + AutoRun = FALSE; + } + else if (option == _T('Q')) + { + bDisableBatchEcho = TRUE; + } + else if (option == _T('S')) { AlwaysStrip = TRUE; } #ifdef INCLUDE_CMD_COLOR - else if (!_tcsnicmp(ptr, _T("/t:"), 3)) + else if (!_tcsnicmp(ptr, _T("/T:"), 3)) { /* process /t (color) argument */ wDefColor = (WORD)_tcstoul(&ptr[3], &ptr, 16); @@ -1843,24 +1845,21 @@ Initialize() SetScreenColor (wColor, TRUE); } #endif - else if (_totlower(ptr[1]) == _T('v')) + else if (option == _T('V')) { - bDelayedExpansion = _tcsnicmp(&ptr[2], _T(":off"), 4); + bDelayedExpansion = _tcsnicmp(&ptr[2], _T(":OFF"), 4); } } } - if (ShowVersion) - { - /* Display a simple version string */ + if (!*ptr) + { + /* If neither /C or /K was given, display a simple version string */ ConOutResPrintf(STRING_REACTOS_VERSION, - _T(KERNEL_RELEASE_STR), - _T(KERNEL_VERSION_BUILD_STR)); - - ConOutPuts (_T("(C) Copyright 1998-") _T(COPYRIGHT_YEAR) _T(" ReactOS Team.\n")); - } - - ExecuteAutoRunFile (); + _T(KERNEL_RELEASE_STR), + _T(KERNEL_VERSION_BUILD_STR)); + ConOutPuts(_T("(C) Copyright 1998-") _T(COPYRIGHT_YEAR) _T(" ReactOS Team.")); + } #ifdef FEATURE_DIR_STACK /* initialize directory stack */ @@ -1882,6 +1881,18 @@ Initialize() /* add ctrl break handler */ AddBreakHandler (); + + if (AutoRun) + ExecuteAutoRunFile(); + + if (*ptr) + { + /* Do the /C or /K command */ + GetCmdLineCommand(commandline, &ptr[2], AlwaysStrip); + ParseCommandLine(commandline); + if (option != _T('K')) + cmd_exit(nErrorLevel); + } } diff --git a/reactos/base/shell/cmd/cmd.h b/reactos/base/shell/cmd/cmd.h index f0ae1a3b042..fc21bbbbb2b 100644 --- a/reactos/base/shell/cmd/cmd.h +++ b/reactos/base/shell/cmd/cmd.h @@ -60,6 +60,7 @@ extern WORD wDefColor; extern BOOL bCtrlBreak; extern BOOL bIgnoreEcho; extern BOOL bExit; +extern BOOL bDisableBatchEcho; extern BOOL bDelayedExpansion; extern INT nErrorLevel; extern SHORT maxx; @@ -211,6 +212,7 @@ INT CommandDirs (LPTSTR); /* Prototypes for ECHO.C */ +BOOL OnOffCommand(LPTSTR param, LPBOOL flag, INT message); INT CommandEcho (LPTSTR); INT CommandEchos (LPTSTR); INT CommandEchoerr (LPTSTR); diff --git a/reactos/base/shell/cmd/echo.c b/reactos/base/shell/cmd/echo.c index e6ea2d11cfa..324facdb75b 100644 --- a/reactos/base/shell/cmd/echo.c +++ b/reactos/base/shell/cmd/echo.c @@ -28,10 +28,43 @@ #include +BOOL +OnOffCommand(LPTSTR param, LPBOOL flag, INT message) +{ + TCHAR *p2; + if (_tcsnicmp(param, D_OFF, sizeof(D_OFF)/sizeof(TCHAR) - 1) == 0) + { + p2 = param + sizeof(D_OFF)/sizeof(TCHAR) - 1; + while (_istspace(*p2)) + p2++; + if (*p2 == _T('\0')) + { + *flag = FALSE; + return TRUE; + } + } + else if (_tcsnicmp(param, D_ON, sizeof(D_ON)/sizeof(TCHAR) - 1) == 0) + { + p2 = param + sizeof(D_ON)/sizeof(TCHAR) - 1; + while (_istspace(*p2)) + p2++; + if (*p2 == _T('\0')) + { + *flag = TRUE; + return TRUE; + } + } + else if (*param == _T('\0')) + { + ConOutResPrintf(message, *flag ? D_ON : D_OFF); + return TRUE; + } + return FALSE; +} INT CommandEcho (LPTSTR param) { - LPTSTR p1, p2; + LPTSTR p1; TRACE ("CommandEcho: '%s'\n", debugstr_aw(param)); @@ -46,45 +79,16 @@ INT CommandEcho (LPTSTR param) return 0; } - if (_tcsnicmp (p1, D_OFF, sizeof(D_OFF)/sizeof(TCHAR) - 1) == 0) - { - p2 = p1 + sizeof(D_OFF)/sizeof(TCHAR) - 1; - while (_istspace(*p2)) - p2++; - if (*p2 == _T('\0')) - { - bEcho = FALSE; - return 0; - } - } - else if (_tcsnicmp (p1, D_ON, sizeof(D_ON)/sizeof(TCHAR) - 1) == 0) - { - p2 = p1 + sizeof(D_ON)/sizeof(TCHAR) - 1; - while (_istspace(*p2)) - p2++; - if (*p2 == _T('\0')) - { - bEcho = TRUE; - return 0; - } - } - if (*p1 != _T('\0')) - { - /* skip the first character */ - ConOutPuts(param + 1); - } - else - { - ConOutResPrintf(STRING_ECHO_HELP5, bEcho ? D_ON : D_OFF); - } - + if (!OnOffCommand(p1, &bEcho, STRING_ECHO_HELP5)) + { + /* skip the first character */ + ConOutPuts(param + 1); + } return 0; } - INT CommandEchos (LPTSTR param) { - TRACE ("CommandEchos: '%s'\n", debugstr_aw(param)); if (!_tcsncmp (param, _T("/?"), 2)) @@ -93,16 +97,13 @@ INT CommandEchos (LPTSTR param) return 0; } - if (*param) - ConOutPrintf (_T("%s"), param); - + ConOutPrintf (_T("%s"), param); return 0; } INT CommandEchoerr (LPTSTR param) { - TRACE ("CommandEchoerr: '%s'\n", debugstr_aw(param)); if (!_tcsncmp (param, _T("/?"), 2)) @@ -112,14 +113,12 @@ INT CommandEchoerr (LPTSTR param) } ConErrPuts (param); - return 0; } INT CommandEchoserr (LPTSTR param) { - TRACE ("CommandEchoserr: '%s'\n", debugstr_aw(param)); if (!_tcsncmp (param, _T("/?"), 2)) @@ -128,9 +127,7 @@ INT CommandEchoserr (LPTSTR param) return 0; } - if (*param) - ConOutPrintf (_T("%s"), param); - + ConErrPrintf (_T("%s"), param); return 0; } diff --git a/reactos/base/shell/cmd/error.c b/reactos/base/shell/cmd/error.c index 35e4ec543d5..aa7eae4bf1a 100644 --- a/reactos/base/shell/cmd/error.c +++ b/reactos/base/shell/cmd/error.c @@ -141,7 +141,7 @@ VOID error_out_of_memory (VOID) VOID error_invalid_parameter_format (LPTSTR s) { - ConErrResPuts(STRING_ERROR_INVALID_PARAM_FORMAT); + ConErrResPrintf(STRING_ERROR_INVALID_PARAM_FORMAT, s); nErrorLevel = 1; } diff --git a/reactos/base/shell/cmd/for.c b/reactos/base/shell/cmd/for.c index 84cf68f1df4..4488d6aacaf 100644 --- a/reactos/base/shell/cmd/for.c +++ b/reactos/base/shell/cmd/for.c @@ -71,9 +71,10 @@ static BOOL GetNextElement(TCHAR **pStart, TCHAR **pEnd) /* Execute a single instance of a FOR command */ static void RunInstance(PARSED_COMMAND *Cmd) { - if (bEcho && Cmd->Subcommands->Type != C_QUIET) + if (bEcho && !bDisableBatchEcho && Cmd->Subcommands->Type != C_QUIET) { - ConOutChar(_T('\n')); + if (!bIgnoreEcho) + ConOutChar(_T('\n')); PrintPrompt(); EchoCommand(Cmd->Subcommands); ConOutChar(_T('\n')); diff --git a/reactos/base/shell/cmd/parser.c b/reactos/base/shell/cmd/parser.c index a0a09f8e170..c2f41bdeed4 100644 --- a/reactos/base/shell/cmd/parser.c +++ b/reactos/base/shell/cmd/parser.c @@ -701,7 +701,8 @@ ParseCommand(LPTSTR Line) if (Line) { - _tcscpy(ParseLine, Line); + if (!SubstituteVars(Line, ParseLine, _T('%'))) + return NULL; bLineContinuations = FALSE; } else @@ -724,6 +725,11 @@ ParseCommand(LPTSTR Line) FreeCommand(Cmd); Cmd = NULL; } + bIgnoreEcho = FALSE; + } + else + { + bIgnoreEcho = TRUE; } return Cmd; } @@ -748,10 +754,22 @@ EchoCommand(PARSED_COMMAND *Cmd) return; case C_BLOCK: ConOutChar(_T('(')); - for (Sub = Cmd->Subcommands; Sub; Sub = Sub->Next) + Sub = Cmd->Subcommands; + if (Sub && !Sub->Next) { + /* Single-command block: display all on one line */ EchoCommand(Sub); + } + else if (Sub) + { + /* Multi-command block: display parenthesis on separate lines */ ConOutChar(_T('\n')); + do + { + EchoCommand(Sub); + ConOutChar(_T('\n')); + Sub = Sub->Next; + } while (Sub); } ConOutChar(_T(')')); break; diff --git a/reactos/base/shell/cmd/setlocal.c b/reactos/base/shell/cmd/setlocal.c index ed6fb69d0f3..51284c9bdc0 100644 --- a/reactos/base/shell/cmd/setlocal.c +++ b/reactos/base/shell/cmd/setlocal.c @@ -35,6 +35,8 @@ DuplicateEnvironment(VOID) INT cmd_setlocal(LPTSTR param) { SETLOCAL *Saved; + LPTSTR *arg; + INT argc, i; /* SETLOCAL only works inside a batch file */ if (!bc) @@ -59,14 +61,24 @@ INT cmd_setlocal(LPTSTR param) nErrorLevel = 0; - if (*param == _T('\0')) - /* nothing */; - else if (!_tcsicmp(param, _T("enabledelayedexpansion"))) - bDelayedExpansion = TRUE; - else if (!_tcsicmp(param, _T("disabledelayedexpansion"))) - bDelayedExpansion = FALSE; - else - error_invalid_parameter_format(param); + arg = splitspace(param, &argc); + for (i = 0; i < argc; i++) + { + if (!_tcsicmp(arg[i], _T("enableextensions"))) + /* not implemented, ignore */; + else if (!_tcsicmp(arg[i], _T("disableextensions"))) + /* not implemented, ignore */; + else if (!_tcsicmp(arg[i], _T("enabledelayedexpansion"))) + bDelayedExpansion = TRUE; + else if (!_tcsicmp(arg[i], _T("disabledelayedexpansion"))) + bDelayedExpansion = FALSE; + else + { + error_invalid_parameter_format(arg[i]); + break; + } + } + freep(arg); return nErrorLevel; } diff --git a/reactos/base/shell/cmd/verify.c b/reactos/base/shell/cmd/verify.c index dba702ea6e1..e184891b64c 100644 --- a/reactos/base/shell/cmd/verify.c +++ b/reactos/base/shell/cmd/verify.c @@ -35,22 +35,13 @@ INT cmd_verify (LPTSTR param) return 0; } - nErrorLevel = 0; - - if (!*param) + if (!OnOffCommand(param, &bVerify, STRING_VERIFY_HELP2)) { - ConOutResPrintf(STRING_VERIFY_HELP2, bVerify ? D_ON : D_OFF); - } - else if (_tcsicmp (param, D_OFF) == 0) - bVerify = FALSE; - else if (_tcsicmp (param, D_ON) == 0) - bVerify = TRUE; - else - { - ConOutResPuts(STRING_VERIFY_HELP3); + ConErrResPuts(STRING_VERIFY_HELP3); + return nErrorLevel = 1; } - return 0; + return nErrorLevel = 0; } #endif