mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 16:26:02 +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" */
|
||||
if (*firstword == _T(':'))
|
||||
cmd_goto(firstword);
|
||||
ret = cmd_goto(firstword);
|
||||
|
||||
/* If we are calling from inside a FOR, hide the FOR variables */
|
||||
saved_fc = fc;
|
||||
|
@ -376,6 +376,7 @@ INT Batch(LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd)
|
|||
}
|
||||
/* Stop all execution */
|
||||
ExitAllBatches();
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -386,12 +387,11 @@ INT Batch(LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd)
|
|||
FreeCommand(Cmd);
|
||||
}
|
||||
|
||||
/* Always return the current errorlevel */
|
||||
ret = nErrorLevel;
|
||||
|
||||
TRACE("Batch: returns TRUE\n");
|
||||
|
||||
/* Restore the FOR variables */
|
||||
fc = saved_fc;
|
||||
|
||||
/* Always return the last command's return code */
|
||||
TRACE("Batch: returns %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,10 +69,15 @@ INT cmd_call(LPTSTR param)
|
|||
|
||||
if (*first == _T(':') && bc)
|
||||
{
|
||||
INT ret;
|
||||
|
||||
/* CALL :label - call a subroutine of the current batch file */
|
||||
while (*param == _T(' '))
|
||||
param++;
|
||||
nErrorLevel = Batch(bc->BatchFilePath, first, param, NULL);
|
||||
|
||||
ret = Batch(bc->BatchFilePath, first, param, NULL);
|
||||
nErrorLevel = (ret != 0 ? ret : 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 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 bAlwaysStrip = FALSE;
|
||||
INT nErrorLevel = 0; /* Errorlevel of last launched external program */
|
||||
CRITICAL_SECTION ChildProcessRunningLock;
|
||||
BOOL bDisableBatchEcho = FALSE;
|
||||
|
@ -631,12 +632,17 @@ DoCommand(LPTSTR first, LPTSTR rest, PARSED_COMMAND *Cmd)
|
|||
INT ParseCommandLine(LPTSTR cmd)
|
||||
{
|
||||
INT Ret = 0;
|
||||
PARSED_COMMAND *Cmd = ParseCommand(cmd);
|
||||
if (Cmd)
|
||||
PARSED_COMMAND *Cmd;
|
||||
|
||||
Cmd = ParseCommand(cmd);
|
||||
if (!Cmd)
|
||||
{
|
||||
Ret = ExecuteCommand(Cmd);
|
||||
FreeCommand(Cmd);
|
||||
/* Return an adequate error code */
|
||||
return (!bParseError ? 0 : 1);
|
||||
}
|
||||
|
||||
Ret = ExecuteCommand(Cmd);
|
||||
FreeCommand(Cmd);
|
||||
return Ret;
|
||||
}
|
||||
|
||||
|
@ -1524,9 +1530,10 @@ ReadLine(TCHAR *commandline, BOOL bMore)
|
|||
return SubstituteVars(ip, commandline, _T('%'));
|
||||
}
|
||||
|
||||
static VOID
|
||||
static INT
|
||||
ProcessInput(VOID)
|
||||
{
|
||||
INT Ret = 0;
|
||||
PARSED_COMMAND *Cmd;
|
||||
|
||||
while (!bCanExit || !bExit)
|
||||
|
@ -1538,9 +1545,11 @@ ProcessInput(VOID)
|
|||
if (!Cmd)
|
||||
continue;
|
||||
|
||||
ExecuteCommand(Cmd);
|
||||
Ret = ExecuteCommand(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)
|
||||
{
|
||||
HMODULE NtDllModule;
|
||||
// INT nExitCode;
|
||||
HANDLE hIn, hOut;
|
||||
LPTSTR ptr, cmdLine;
|
||||
TCHAR option = 0;
|
||||
BOOL AlwaysStrip = FALSE;
|
||||
BOOL AutoRun = TRUE;
|
||||
TCHAR ModuleName[MAX_PATH + 1];
|
||||
TCHAR commandline[CMDLINE_LENGTH];
|
||||
|
||||
/* Get version information */
|
||||
InitOSVersion();
|
||||
|
@ -1957,7 +1964,7 @@ Initialize(VOID)
|
|||
ConOutResPaging(TRUE, STRING_CMD_HELP8);
|
||||
nErrorLevel = 1;
|
||||
bExit = TRUE;
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
else if (option == _T('P'))
|
||||
{
|
||||
|
@ -1996,7 +2003,7 @@ Initialize(VOID)
|
|||
}
|
||||
else if (option == _T('S'))
|
||||
{
|
||||
AlwaysStrip = TRUE;
|
||||
bAlwaysStrip = TRUE;
|
||||
}
|
||||
#ifdef INCLUDE_CMD_COLOR
|
||||
else if (!_tcsnicmp(ptr, _T("/T:"), 3))
|
||||
|
@ -2067,18 +2074,8 @@ Initialize(VOID)
|
|||
ExecuteAutoRunFile(HKEY_CURRENT_USER);
|
||||
}
|
||||
|
||||
if (*ptr)
|
||||
{
|
||||
/* Do the /C or /K command */
|
||||
GetCmdLineCommand(commandline, &ptr[2], AlwaysStrip);
|
||||
/* nExitCode = */ ParseCommandLine(commandline);
|
||||
if (fSingleCommand == 1)
|
||||
{
|
||||
// nErrorLevel = nExitCode;
|
||||
bExit = TRUE;
|
||||
}
|
||||
fSingleCommand = 0;
|
||||
}
|
||||
/* Returns the rest of the command line */
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2125,6 +2122,8 @@ static VOID Cleanup(VOID)
|
|||
*/
|
||||
int _tmain(int argc, const TCHAR *argv[])
|
||||
{
|
||||
INT nExitCode;
|
||||
LPCTSTR pCmdLine;
|
||||
TCHAR startPath[MAX_PATH];
|
||||
|
||||
InitializeCriticalSection(&ChildProcessRunningLock);
|
||||
|
@ -2144,18 +2143,39 @@ int _tmain(int argc, const TCHAR *argv[])
|
|||
|
||||
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 */
|
||||
ProcessInput();
|
||||
if (pCmdLine && *pCmdLine)
|
||||
{
|
||||
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 */
|
||||
Cleanup();
|
||||
cmd_free(lpOriginalEnvironment);
|
||||
|
||||
cmd_exit(nErrorLevel);
|
||||
return nErrorLevel;
|
||||
cmd_exit(nExitCode);
|
||||
return nExitCode;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -548,13 +548,16 @@ INT CommandExit(LPTSTR param)
|
|||
|
||||
/* Search for an optional exit code */
|
||||
while (_istspace(*param))
|
||||
param++;
|
||||
++param;
|
||||
|
||||
/* Set the errorlevel to the exit code */
|
||||
if (_istdigit(*param))
|
||||
{
|
||||
nErrorLevel = _ttoi(param);
|
||||
// if (fSingleCommand == 1) return nErrorLevel;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return (bExit ? nErrorLevel : 0);
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_CMD_REM
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue