mirror of
https://github.com/reactos/reactos.git
synced 2025-07-31 11:51:58 +00:00
[CMD] Additional fixes for ERRORLEVEL and last returned exit code from EXIT, CALL commands and CMD.
CORE-10495 CORE-13672 - Fix how the ERRORLEVEL and the last returned exit code are set by EXIT and CALL commands, when batch contexts terminate, and when CMD runs in single-command mode (with /C). Addendum to commit26ff2c8e
, and reverts commit7bd33ac4
. See also commit8cf11060
(r40474). More information can be found at: https://ss64.com/nt/exit.html https://stackoverflow.com/a/34987886/13530036 https://stackoverflow.com/a/34937706/13530036 - Move the actual execution of the CMD command-line (in /C or /K single-command mode) from Initialize() to _tmain(), to put it on par with the ProcessInput() interactive mode. - Make ProcessInput() also return the last command's exit code.
This commit is contained in:
parent
4c9d322c68
commit
d78e8029b8
4 changed files with 68 additions and 40 deletions
|
@ -349,7 +349,7 @@ INT Batch(LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd)
|
||||||
|
|
||||||
/* Check if this is a "CALL :label" */
|
/* Check if this is a "CALL :label" */
|
||||||
if (*firstword == _T(':'))
|
if (*firstword == _T(':'))
|
||||||
cmd_goto(firstword);
|
ret = cmd_goto(firstword);
|
||||||
|
|
||||||
/* If we are calling from inside a FOR, hide the FOR variables */
|
/* If we are calling from inside a FOR, hide the FOR variables */
|
||||||
saved_fc = fc;
|
saved_fc = fc;
|
||||||
|
@ -376,6 +376,7 @@ INT Batch(LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd)
|
||||||
}
|
}
|
||||||
/* Stop all execution */
|
/* Stop all execution */
|
||||||
ExitAllBatches();
|
ExitAllBatches();
|
||||||
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,12 +387,11 @@ INT Batch(LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd)
|
||||||
FreeCommand(Cmd);
|
FreeCommand(Cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Always return the current errorlevel */
|
/* Restore the FOR variables */
|
||||||
ret = nErrorLevel;
|
|
||||||
|
|
||||||
TRACE("Batch: returns TRUE\n");
|
|
||||||
|
|
||||||
fc = saved_fc;
|
fc = saved_fc;
|
||||||
|
|
||||||
|
/* Always return the last command's return code */
|
||||||
|
TRACE("Batch: returns %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,10 +69,15 @@ INT cmd_call(LPTSTR param)
|
||||||
|
|
||||||
if (*first == _T(':') && bc)
|
if (*first == _T(':') && bc)
|
||||||
{
|
{
|
||||||
|
INT ret;
|
||||||
|
|
||||||
/* CALL :label - call a subroutine of the current batch file */
|
/* CALL :label - call a subroutine of the current batch file */
|
||||||
while (*param == _T(' '))
|
while (*param == _T(' '))
|
||||||
param++;
|
param++;
|
||||||
nErrorLevel = Batch(bc->BatchFilePath, first, param, NULL);
|
|
||||||
|
ret = Batch(bc->BatchFilePath, first, param, NULL);
|
||||||
|
nErrorLevel = (ret != 0 ? ret : nErrorLevel);
|
||||||
|
|
||||||
return nErrorLevel;
|
return nErrorLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,7 @@ BOOL bCanExit = TRUE; /* Indicates if this shell is exitable */
|
||||||
BOOL bCtrlBreak = FALSE; /* Ctrl-Break or Ctrl-C hit */
|
BOOL bCtrlBreak = FALSE; /* Ctrl-Break or Ctrl-C hit */
|
||||||
BOOL bIgnoreEcho = FALSE; /* Set this to TRUE to prevent a newline, when executing a command */
|
BOOL bIgnoreEcho = FALSE; /* Set this to TRUE to prevent a newline, when executing a command */
|
||||||
static BOOL fSingleCommand = 0; /* When we are executing something passed on the command line after /C or /K */
|
static BOOL fSingleCommand = 0; /* When we are executing something passed on the command line after /C or /K */
|
||||||
|
static BOOL bAlwaysStrip = FALSE;
|
||||||
INT nErrorLevel = 0; /* Errorlevel of last launched external program */
|
INT nErrorLevel = 0; /* Errorlevel of last launched external program */
|
||||||
CRITICAL_SECTION ChildProcessRunningLock;
|
CRITICAL_SECTION ChildProcessRunningLock;
|
||||||
BOOL bDisableBatchEcho = FALSE;
|
BOOL bDisableBatchEcho = FALSE;
|
||||||
|
@ -631,12 +632,17 @@ DoCommand(LPTSTR first, LPTSTR rest, PARSED_COMMAND *Cmd)
|
||||||
INT ParseCommandLine(LPTSTR cmd)
|
INT ParseCommandLine(LPTSTR cmd)
|
||||||
{
|
{
|
||||||
INT Ret = 0;
|
INT Ret = 0;
|
||||||
PARSED_COMMAND *Cmd = ParseCommand(cmd);
|
PARSED_COMMAND *Cmd;
|
||||||
if (Cmd)
|
|
||||||
|
Cmd = ParseCommand(cmd);
|
||||||
|
if (!Cmd)
|
||||||
{
|
{
|
||||||
Ret = ExecuteCommand(Cmd);
|
/* Return an adequate error code */
|
||||||
FreeCommand(Cmd);
|
return (!bParseError ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ret = ExecuteCommand(Cmd);
|
||||||
|
FreeCommand(Cmd);
|
||||||
return Ret;
|
return Ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1524,9 +1530,10 @@ ReadLine(TCHAR *commandline, BOOL bMore)
|
||||||
return SubstituteVars(ip, commandline, _T('%'));
|
return SubstituteVars(ip, commandline, _T('%'));
|
||||||
}
|
}
|
||||||
|
|
||||||
static VOID
|
static INT
|
||||||
ProcessInput(VOID)
|
ProcessInput(VOID)
|
||||||
{
|
{
|
||||||
|
INT Ret = 0;
|
||||||
PARSED_COMMAND *Cmd;
|
PARSED_COMMAND *Cmd;
|
||||||
|
|
||||||
while (!bCanExit || !bExit)
|
while (!bCanExit || !bExit)
|
||||||
|
@ -1538,9 +1545,11 @@ ProcessInput(VOID)
|
||||||
if (!Cmd)
|
if (!Cmd)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ExecuteCommand(Cmd);
|
Ret = ExecuteCommand(Cmd);
|
||||||
FreeCommand(Cmd);
|
FreeCommand(Cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1879,20 +1888,18 @@ GetCmdLineCommand(
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up global initializations and process parameters
|
* Set up global initializations and process parameters.
|
||||||
|
* Return a pointer to the command line if present.
|
||||||
*/
|
*/
|
||||||
static VOID
|
static LPCTSTR
|
||||||
Initialize(VOID)
|
Initialize(VOID)
|
||||||
{
|
{
|
||||||
HMODULE NtDllModule;
|
HMODULE NtDllModule;
|
||||||
// INT nExitCode;
|
|
||||||
HANDLE hIn, hOut;
|
HANDLE hIn, hOut;
|
||||||
LPTSTR ptr, cmdLine;
|
LPTSTR ptr, cmdLine;
|
||||||
TCHAR option = 0;
|
TCHAR option = 0;
|
||||||
BOOL AlwaysStrip = FALSE;
|
|
||||||
BOOL AutoRun = TRUE;
|
BOOL AutoRun = TRUE;
|
||||||
TCHAR ModuleName[MAX_PATH + 1];
|
TCHAR ModuleName[MAX_PATH + 1];
|
||||||
TCHAR commandline[CMDLINE_LENGTH];
|
|
||||||
|
|
||||||
/* Get version information */
|
/* Get version information */
|
||||||
InitOSVersion();
|
InitOSVersion();
|
||||||
|
@ -1957,7 +1964,7 @@ Initialize(VOID)
|
||||||
ConOutResPaging(TRUE, STRING_CMD_HELP8);
|
ConOutResPaging(TRUE, STRING_CMD_HELP8);
|
||||||
nErrorLevel = 1;
|
nErrorLevel = 1;
|
||||||
bExit = TRUE;
|
bExit = TRUE;
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (option == _T('P'))
|
else if (option == _T('P'))
|
||||||
{
|
{
|
||||||
|
@ -1996,7 +2003,7 @@ Initialize(VOID)
|
||||||
}
|
}
|
||||||
else if (option == _T('S'))
|
else if (option == _T('S'))
|
||||||
{
|
{
|
||||||
AlwaysStrip = TRUE;
|
bAlwaysStrip = TRUE;
|
||||||
}
|
}
|
||||||
#ifdef INCLUDE_CMD_COLOR
|
#ifdef INCLUDE_CMD_COLOR
|
||||||
else if (!_tcsnicmp(ptr, _T("/T:"), 3))
|
else if (!_tcsnicmp(ptr, _T("/T:"), 3))
|
||||||
|
@ -2067,18 +2074,8 @@ Initialize(VOID)
|
||||||
ExecuteAutoRunFile(HKEY_CURRENT_USER);
|
ExecuteAutoRunFile(HKEY_CURRENT_USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*ptr)
|
/* Returns the rest of the command line */
|
||||||
{
|
return ptr;
|
||||||
/* Do the /C or /K command */
|
|
||||||
GetCmdLineCommand(commandline, &ptr[2], AlwaysStrip);
|
|
||||||
/* nExitCode = */ ParseCommandLine(commandline);
|
|
||||||
if (fSingleCommand == 1)
|
|
||||||
{
|
|
||||||
// nErrorLevel = nExitCode;
|
|
||||||
bExit = TRUE;
|
|
||||||
}
|
|
||||||
fSingleCommand = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2125,6 +2122,8 @@ static VOID Cleanup(VOID)
|
||||||
*/
|
*/
|
||||||
int _tmain(int argc, const TCHAR *argv[])
|
int _tmain(int argc, const TCHAR *argv[])
|
||||||
{
|
{
|
||||||
|
INT nExitCode;
|
||||||
|
LPCTSTR pCmdLine;
|
||||||
TCHAR startPath[MAX_PATH];
|
TCHAR startPath[MAX_PATH];
|
||||||
|
|
||||||
InitializeCriticalSection(&ChildProcessRunningLock);
|
InitializeCriticalSection(&ChildProcessRunningLock);
|
||||||
|
@ -2144,18 +2143,39 @@ int _tmain(int argc, const TCHAR *argv[])
|
||||||
|
|
||||||
CMD_ModuleHandle = GetModuleHandle(NULL);
|
CMD_ModuleHandle = GetModuleHandle(NULL);
|
||||||
|
|
||||||
/* Perform general initialization, parse switches on command-line */
|
/*
|
||||||
Initialize();
|
* Perform general initialization, parse switches on command-line.
|
||||||
|
* Initialize the exit code with the errorlevel as Initialize() can set it.
|
||||||
|
*/
|
||||||
|
pCmdLine = Initialize();
|
||||||
|
nExitCode = nErrorLevel;
|
||||||
|
|
||||||
/* Call prompt routine */
|
if (pCmdLine && *pCmdLine)
|
||||||
ProcessInput();
|
{
|
||||||
|
TCHAR commandline[CMDLINE_LENGTH];
|
||||||
|
|
||||||
|
/* Do the /C or /K command */
|
||||||
|
GetCmdLineCommand(commandline, &pCmdLine[2], bAlwaysStrip);
|
||||||
|
nExitCode = ParseCommandLine(commandline);
|
||||||
|
if (fSingleCommand == 1)
|
||||||
|
{
|
||||||
|
// nErrorLevel = nExitCode;
|
||||||
|
bExit = TRUE;
|
||||||
|
}
|
||||||
|
fSingleCommand = 0;
|
||||||
|
}
|
||||||
|
if (!bExit)
|
||||||
|
{
|
||||||
|
/* Call prompt routine */
|
||||||
|
nExitCode = ProcessInput();
|
||||||
|
}
|
||||||
|
|
||||||
/* Do the cleanup */
|
/* Do the cleanup */
|
||||||
Cleanup();
|
Cleanup();
|
||||||
cmd_free(lpOriginalEnvironment);
|
cmd_free(lpOriginalEnvironment);
|
||||||
|
|
||||||
cmd_exit(nErrorLevel);
|
cmd_exit(nExitCode);
|
||||||
return nErrorLevel;
|
return nExitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -548,13 +548,16 @@ INT CommandExit(LPTSTR param)
|
||||||
|
|
||||||
/* Search for an optional exit code */
|
/* Search for an optional exit code */
|
||||||
while (_istspace(*param))
|
while (_istspace(*param))
|
||||||
param++;
|
++param;
|
||||||
|
|
||||||
/* Set the errorlevel to the exit code */
|
/* Set the errorlevel to the exit code */
|
||||||
if (_istdigit(*param))
|
if (_istdigit(*param))
|
||||||
|
{
|
||||||
nErrorLevel = _ttoi(param);
|
nErrorLevel = _ttoi(param);
|
||||||
|
// if (fSingleCommand == 1) return nErrorLevel;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return (bExit ? nErrorLevel : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef INCLUDE_CMD_REM
|
#ifdef INCLUDE_CMD_REM
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue