https://git.reactos.org/?p=reactos.git;a=commitdiff;h=d78e8029b8b499d00776c…
commit d78e8029b8b499d00776c54dd30a95b0afbd285a
Author:     Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Thu Jul 30 01:44:43 2020 +0200
Commit:     Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Wed Aug 19 20:36:03 2020 +0200
    [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 commit 26ff2c8e, and reverts commit 7bd33ac4.
      See also commit 8cf11060 (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.
---
 base/shell/cmd/batch.c    | 12 +++----
 base/shell/cmd/call.c     |  7 +++-
 base/shell/cmd/cmd.c      | 82 +++++++++++++++++++++++++++++------------------
 base/shell/cmd/internal.c |  7 ++--
 4 files changed, 68 insertions(+), 40 deletions(-)
diff --git a/base/shell/cmd/batch.c b/base/shell/cmd/batch.c
index 184911c60a6..a7dfa2fd11a 100644
--- a/base/shell/cmd/batch.c
+++ b/base/shell/cmd/batch.c
@@ -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;
 }
diff --git a/base/shell/cmd/call.c b/base/shell/cmd/call.c
index 2cf2772c3c4..55f39d086f1 100644
--- a/base/shell/cmd/call.c
+++ b/base/shell/cmd/call.c
@@ -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;
     }
diff --git a/base/shell/cmd/cmd.c b/base/shell/cmd/cmd.c
index 31910e9e2ef..4bbffa9faf1 100644
--- a/base/shell/cmd/cmd.c
+++ b/base/shell/cmd/cmd.c
@@ -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 */
diff --git a/base/shell/cmd/internal.c b/base/shell/cmd/internal.c
index 9febc003cdc..175f4b452a7 100644
--- a/base/shell/cmd/internal.c
+++ b/base/shell/cmd/internal.c
@@ -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