diff --git a/reactos/base/shell/cmd/batch.c b/reactos/base/shell/cmd/batch.c index aab0b67d8c8..bb0c8b6859b 100644 --- a/reactos/base/shell/cmd/batch.c +++ b/reactos/base/shell/cmd/batch.c @@ -203,11 +203,12 @@ VOID ExitBatch() * */ -BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd) +INT Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd) { BATCH_CONTEXT new; LPFOR_CONTEXT saved_fc; INT i; + INT ret = 0; HANDLE hFile; SetLastError(0); @@ -221,7 +222,7 @@ BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd if (hFile == INVALID_HANDLE_VALUE) { ConErrResPuts(STRING_BATCH_ERROR); - return FALSE; + return 1; } if (bc != NULL && Cmd == bc->current) @@ -238,10 +239,19 @@ BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd else { struct _SETLOCAL *setlocal = NULL; - /* If a batch file runs another batch file as part of a compound command - * (e.g. "x.bat & somethingelse") then the first file gets terminated. */ - if (bc && Cmd != NULL) + + if (Cmd == NULL) { + /* This is a CALL. CALL will set errorlevel to our return value, so + * in order to keep the value of errorlevel unchanged in the case + * of calling an empty batch file, we must return that same value. */ + ret = nErrorLevel; + } + else if (bc) + { + /* If a batch file runs another batch file as part of a compound command + * (e.g. "x.bat & somethingelse") then the first file gets terminated. */ + /* Get its SETLOCAL stack so it can be migrated to the new context */ setlocal = bc->setlocal; bc->setlocal = NULL; @@ -272,7 +282,7 @@ BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd if (bc->raw_params == NULL) { error_out_of_memory(); - return FALSE; + return 1; } /* Check if this is a "CALL :label" */ @@ -303,14 +313,14 @@ BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd } bc->current = Cmd; - ExecuteCommand(Cmd); + ret = ExecuteCommand(Cmd); FreeCommand(Cmd); } TRACE ("Batch: returns TRUE\n"); fc = saved_fc; - return TRUE; + return ret; } VOID AddBatchRedirection(REDIRECTION **RedirList) diff --git a/reactos/base/shell/cmd/batch.h b/reactos/base/shell/cmd/batch.h index 9c89518b648..c3a8a0bf4b5 100644 --- a/reactos/base/shell/cmd/batch.h +++ b/reactos/base/shell/cmd/batch.h @@ -47,7 +47,7 @@ extern TCHAR textline[BATCH_BUFFSIZE]; /* Buffer for reading Batch file lines */ LPTSTR FindArg (TCHAR, BOOL *); LPTSTR BatchParams (LPTSTR, LPTSTR); VOID ExitBatch (); -BOOL Batch (LPTSTR, LPTSTR, LPTSTR, PARSED_COMMAND *); +INT Batch (LPTSTR, LPTSTR, LPTSTR, PARSED_COMMAND *); LPTSTR ReadBatchLine(); VOID AddBatchRedirection(REDIRECTION **); diff --git a/reactos/base/shell/cmd/call.c b/reactos/base/shell/cmd/call.c index b945e88beb5..9f71b94cd04 100644 --- a/reactos/base/shell/cmd/call.c +++ b/reactos/base/shell/cmd/call.c @@ -73,10 +73,12 @@ INT cmd_call (LPTSTR param) /* CALL :label - call a subroutine of the current batch file */ while (*param == _T(' ')) param++; - return !Batch(bc->BatchFilePath, first, param, NULL); + nErrorLevel = Batch(bc->BatchFilePath, first, param, NULL); + return nErrorLevel; } - return !DoCommand(first, param, NULL); + nErrorLevel = DoCommand(first, param, NULL); + return nErrorLevel; } /* EOF */ diff --git a/reactos/base/shell/cmd/cmd.c b/reactos/base/shell/cmd/cmd.c index 11a30d3822d..0ec4d674e0b 100644 --- a/reactos/base/shell/cmd/cmd.c +++ b/reactos/base/shell/cmd/cmd.c @@ -308,7 +308,7 @@ HANDLE RunFile(DWORD flags, LPTSTR filename, LPTSTR params, * Rest - rest of command line */ -static BOOL +static INT Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd) { TCHAR szFullName[MAX_PATH]; @@ -363,7 +363,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd) } if (!working) ConErrResPuts (STRING_FREE_ERROR1); - return working; + return !working; } /* get the PATH environment variable and parse it */ @@ -372,7 +372,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd) if (!SearchForExecutable(First, szFullName)) { error_bad_command(first); - return FALSE; + return 1; } GetConsoleTitle (szWindowTitle, MAX_PATH); @@ -384,7 +384,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd) while (*rest == _T(' ')) rest++; TRACE ("[BATCH: %s %s]\n", debugstr_aw(szFullName), debugstr_aw(rest)); - Batch (szFullName, first, rest, Cmd); + dwExitCode = Batch(szFullName, first, rest, Cmd); } else { @@ -448,17 +448,13 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd) GetExitCodeProcess (prci.hProcess, &dwExitCode); nErrorLevel = (INT)dwExitCode; } - else - { - nErrorLevel = 0; - } CloseHandle (prci.hProcess); } else { TRACE ("[ShellExecute failed!: %s]\n", debugstr_aw(Full)); error_bad_command (first); - nErrorLevel = 1; + dwExitCode = 1; } // restore console mode @@ -472,7 +468,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd) OutputCodePage = GetConsoleOutputCP(); SetConsoleTitle (szWindowTitle); - return nErrorLevel == 0; + return dwExitCode; } @@ -485,7 +481,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd) * rest - rest of command line */ -BOOL +INT DoCommand(LPTSTR first, LPTSTR rest, PARSED_COMMAND *Cmd) { TCHAR com[_tcslen(first) + _tcslen(rest) + 2]; /* full command line */ @@ -530,7 +526,7 @@ DoCommand(LPTSTR first, LPTSTR rest, PARSED_COMMAND *Cmd) if (_tcsicmp(cmdptr->name, _T("echo")) != 0) while (_istspace(*param)) param++; - return !cmdptr->func(param); + return cmdptr->func(param); } } @@ -543,14 +539,16 @@ DoCommand(LPTSTR first, LPTSTR rest, PARSED_COMMAND *Cmd) * full input/output redirection and piping are supported */ -VOID ParseCommandLine (LPTSTR cmd) +INT ParseCommandLine (LPTSTR cmd) { + INT Ret = 0; PARSED_COMMAND *Cmd = ParseCommand(cmd); if (Cmd) { - ExecuteCommand(Cmd); + Ret = ExecuteCommand(Cmd); FreeCommand(Cmd); } + return Ret; } /* Execute a command without waiting for it to finish. If it's an internal @@ -679,27 +677,27 @@ failed: #endif } -BOOL +INT ExecuteCommand(PARSED_COMMAND *Cmd) { PARSED_COMMAND *Sub; LPTSTR First, Rest; - BOOL Success = TRUE; + INT Ret = 0; if (!PerformRedirection(Cmd->Redirections)) - return FALSE; + return 1; switch (Cmd->Type) { case C_COMMAND: - Success = FALSE; + Ret = 1; First = DoDelayedExpansion(Cmd->Command.First); if (First) { Rest = DoDelayedExpansion(Cmd->Command.Rest); if (Rest) { - Success = DoCommand(First, Rest, Cmd); + Ret = DoCommand(First, Rest, Cmd); cmd_free(Rest); } cmd_free(First); @@ -709,31 +707,36 @@ ExecuteCommand(PARSED_COMMAND *Cmd) case C_BLOCK: case C_MULTI: for (Sub = Cmd->Subcommands; Sub; Sub = Sub->Next) - Success = ExecuteCommand(Sub); + Ret = ExecuteCommand(Sub); break; case C_IFFAILURE: + Sub = Cmd->Subcommands; + Ret = ExecuteCommand(Sub); + if (Ret != 0) + { + nErrorLevel = Ret; + Ret = ExecuteCommand(Sub->Next); + } + break; case C_IFSUCCESS: Sub = Cmd->Subcommands; - Success = ExecuteCommand(Sub); - if (Success == (Cmd->Type - C_IFFAILURE)) - { - Sub = Sub->Next; - Success = ExecuteCommand(Sub); - } + Ret = ExecuteCommand(Sub); + if (Ret == 0) + Ret = ExecuteCommand(Sub->Next); break; case C_PIPE: ExecutePipeline(Cmd); break; case C_IF: - Success = ExecuteIf(Cmd); + Ret = ExecuteIf(Cmd); break; case C_FOR: - Success = ExecuteFor(Cmd); + Ret = ExecuteFor(Cmd); break; } UndoRedirection(Cmd->Redirections, NULL); - return Success; + return Ret; } BOOL @@ -1402,7 +1405,7 @@ ReadLine (TCHAR *commandline, BOOL bMore) return SubstituteVars(ip, commandline, _T('%')); } -static INT +static VOID ProcessInput() { PARSED_COMMAND *Cmd; @@ -1416,8 +1419,6 @@ ProcessInput() ExecuteCommand(Cmd); FreeCommand(Cmd); } - - return nErrorLevel; } @@ -1614,6 +1615,7 @@ Initialize() TCHAR commandline[CMDLINE_LENGTH]; TCHAR ModuleName[_MAX_PATH + 1]; TCHAR lpBuffer[2]; + INT nExitCode; //INT len; TCHAR *ptr, *cmdLine, option = 0; @@ -1760,9 +1762,12 @@ Initialize() { /* Do the /C or /K command */ GetCmdLineCommand(commandline, &ptr[2], AlwaysStrip); - ParseCommandLine(commandline); + nExitCode = ParseCommandLine(commandline); if (option != _T('K')) + { + nErrorLevel = nExitCode; bExit = TRUE; + } } } @@ -1806,7 +1811,6 @@ int cmd_main (int argc, const TCHAR *argv[]) HANDLE hConsole; TCHAR startPath[MAX_PATH]; CONSOLE_SCREEN_BUFFER_INFO Info; - INT nExitCode; lpOriginalEnvironment = DuplicateEnvironment(); @@ -1839,15 +1843,15 @@ int cmd_main (int argc, const TCHAR *argv[]) Initialize(); /* call prompt routine */ - nExitCode = ProcessInput(); + ProcessInput(); /* do the cleanup */ Cleanup(); cmd_free(lpOriginalEnvironment); - cmd_exit(nExitCode); - return(nExitCode); + cmd_exit(nErrorLevel); + return(nErrorLevel); } /* EOF */ diff --git a/reactos/base/shell/cmd/cmd.h b/reactos/base/shell/cmd/cmd.h index 9d5738480d2..5900e40ad5b 100644 --- a/reactos/base/shell/cmd/cmd.h +++ b/reactos/base/shell/cmd/cmd.h @@ -102,16 +102,16 @@ INT cmd_cls (LPTSTR); /* Prototypes for CMD.C */ INT ConvertULargeInteger(ULONGLONG num, LPTSTR des, INT len, BOOL bPutSeperator); HANDLE RunFile(DWORD, LPTSTR, LPTSTR, LPTSTR, INT); -VOID ParseCommandLine (LPTSTR); +INT ParseCommandLine(LPTSTR); struct _PARSED_COMMAND; -BOOL ExecuteCommand(struct _PARSED_COMMAND *Cmd); +INT ExecuteCommand(struct _PARSED_COMMAND *Cmd); LPCTSTR GetEnvVarOrSpecial ( LPCTSTR varName ); VOID AddBreakHandler (VOID); VOID RemoveBreakHandler (VOID); BOOL SubstituteVars(TCHAR *Src, TCHAR *Dest, TCHAR Delim); BOOL SubstituteForVars(TCHAR *Src, TCHAR *Dest); LPTSTR DoDelayedExpansion(LPTSTR Line); -BOOL DoCommand(LPTSTR first, LPTSTR rest, struct _PARSED_COMMAND *Cmd); +INT DoCommand(LPTSTR first, LPTSTR rest, struct _PARSED_COMMAND *Cmd); BOOL ReadLine(TCHAR *commandline, BOOL bMore); int cmd_main (int argc, const TCHAR *argv[]); @@ -254,7 +254,7 @@ VOID CompleteFilename (LPTSTR, BOOL, LPTSTR, UINT); #define FOR_LOOP 4 /* /L */ #define FOR_RECURSIVE 8 /* /R */ INT cmd_for (LPTSTR); -BOOL ExecuteFor(struct _PARSED_COMMAND *Cmd); +INT ExecuteFor(struct _PARSED_COMMAND *Cmd); /* Prototypes for FREE.C */ @@ -283,7 +283,7 @@ INT CommandHistory (LPTSTR param); enum { IF_CMDEXTVERSION, IF_DEFINED, IF_ERRORLEVEL, IF_EXIST, IF_STRINGEQ, /* == */ IF_EQU, IF_GTR, IF_GEQ, IF_LSS, IF_LEQ, IF_NEQ }; -BOOL ExecuteIf(struct _PARSED_COMMAND *Cmd); +INT ExecuteIf(struct _PARSED_COMMAND *Cmd); /* Prototypes for INTERNAL.C */ diff --git a/reactos/base/shell/cmd/for.c b/reactos/base/shell/cmd/for.c index 4488d6aacaf..a73f180e563 100644 --- a/reactos/base/shell/cmd/for.c +++ b/reactos/base/shell/cmd/for.c @@ -69,7 +69,7 @@ static BOOL GetNextElement(TCHAR **pStart, TCHAR **pEnd) } /* Execute a single instance of a FOR command */ -static void RunInstance(PARSED_COMMAND *Cmd) +static INT RunInstance(PARSED_COMMAND *Cmd) { if (bEcho && !bDisableBatchEcho && Cmd->Subcommands->Type != C_QUIET) { @@ -80,7 +80,7 @@ static void RunInstance(PARSED_COMMAND *Cmd) ConOutChar(_T('\n')); } /* Just run the command (variable expansion is done in DoDelayedExpansion) */ - ExecuteCommand(Cmd->Subcommands); + return ExecuteCommand(Cmd->Subcommands); } /* Check if this FOR should be terminated early */ @@ -117,7 +117,7 @@ static LPTSTR ReadFileContents(FILE *InputFile, TCHAR *Buffer) return Contents; } -static BOOL ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer) +static INT ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer) { LPTSTR Delims = _T(" \t"); TCHAR Eol = _T(';'); @@ -129,6 +129,7 @@ static BOOL ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer) LPTSTR Variables[32]; TCHAR *Start, *End; INT i; + INT Ret = 0; if (Cmd->For.Params) { @@ -228,7 +229,7 @@ static BOOL ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer) { error: error_syntax(Param); - return FALSE; + return 1; } } } @@ -270,7 +271,7 @@ static BOOL ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer) if (!InputFile) { error_bad_command(Start + 1); - return FALSE; + return 1; } FullInput = ReadFileContents(InputFile, Buffer); _pclose(InputFile); @@ -286,7 +287,7 @@ static BOOL ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer) if (!InputFile) { error_sfile_not_found(Start); - return FALSE; + return 1; } FullInput = ReadFileContents(InputFile, Buffer); fclose(InputFile); @@ -295,7 +296,7 @@ static BOOL ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer) if (!FullInput) { error_out_of_memory(); - return FALSE; + return 1; } /* Loop over the input line by line */ @@ -337,20 +338,21 @@ static BOOL ForF(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer) /* Don't run unless the line had enough tokens to fill at least one variable */ if (*Variables[0]) - RunInstance(Cmd); + Ret = RunInstance(Cmd); } while (!Exiting(Cmd) && (In = NextLine) != NULL); cmd_free(FullInput); } - return TRUE; + return Ret; } /* FOR /L: Do a numeric loop */ -static void ForLoop(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer) +static INT ForLoop(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer) { enum { START, STEP, END }; INT params[3] = { 0, 0, 0 }; INT i; + INT Ret = 0; TCHAR *Start, *End = List; for (i = 0; i < 3 && GetNextElement(&Start, &End); i++) @@ -361,17 +363,19 @@ static void ForLoop(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer) (params[STEP] >= 0 ? (i <= params[END]) : (i >= params[END]))) { _itot(i, Buffer, 10); - RunInstance(Cmd); + Ret = RunInstance(Cmd); i += params[STEP]; } + return Ret; } /* Process a FOR in one directory. Stored in Buffer (up to BufPos) is a * string which is prefixed to each element of the list. In a normal FOR * it will be empty, but in FOR /R it will be the directory name. */ -static void ForDir(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer, TCHAR *BufPos) +static INT ForDir(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer, TCHAR *BufPos) { TCHAR *Start, *End = List; + INT Ret = 0; while (!Exiting(Cmd) && GetNextElement(&Start, &End)) { if (BufPos + (End - Start) > &Buffer[CMDLINE_LENGTH]) @@ -402,22 +406,24 @@ static void ForDir(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer, TCHAR *BufPo _tcscmp(w32fd.cFileName, _T("..")) == 0) continue; _tcscpy(FilePart, w32fd.cFileName); - RunInstance(Cmd); + Ret = RunInstance(Cmd); } while (!Exiting(Cmd) && FindNextFile(hFind, &w32fd)); FindClose(hFind); } else { - RunInstance(Cmd); + Ret = RunInstance(Cmd); } } + return Ret; } /* FOR /R: Process a FOR in each directory of a tree, recursively. */ -static void ForRecursive(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer, TCHAR *BufPos) +static INT ForRecursive(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer, TCHAR *BufPos) { HANDLE hFind; WIN32_FIND_DATA w32fd; + INT Ret = 0; if (BufPos[-1] != _T('\\')) { @@ -425,12 +431,12 @@ static void ForRecursive(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer, TCHAR *BufPos = _T('\0'); } - ForDir(Cmd, List, Buffer, BufPos); + Ret = ForDir(Cmd, List, Buffer, BufPos); _tcscpy(BufPos, _T("*")); hFind = FindFirstFile(Buffer, &w32fd); if (hFind == INVALID_HANDLE_VALUE) - return; + return Ret; do { if (!(w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) @@ -438,9 +444,10 @@ static void ForRecursive(PARSED_COMMAND *Cmd, LPTSTR List, TCHAR *Buffer, TCHAR if (_tcscmp(w32fd.cFileName, _T(".")) == 0 || _tcscmp(w32fd.cFileName, _T("..")) == 0) continue; - ForRecursive(Cmd, List, Buffer, _stpcpy(BufPos, w32fd.cFileName)); + Ret = ForRecursive(Cmd, List, Buffer, _stpcpy(BufPos, w32fd.cFileName)); } while (!Exiting(Cmd) && FindNextFile(hFind, &w32fd)); FindClose(hFind); + return Ret; } BOOL @@ -449,18 +456,18 @@ ExecuteFor(PARSED_COMMAND *Cmd) TCHAR Buffer[CMDLINE_LENGTH]; /* Buffer to hold the variable value */ LPTSTR BufferPtr = Buffer; LPFOR_CONTEXT lpNew; - BOOL Success = TRUE; + INT Ret; LPTSTR List = DoDelayedExpansion(Cmd->For.List); if (!List) - return FALSE; + return 1; /* Create our FOR context */ lpNew = cmd_alloc(sizeof(FOR_CONTEXT)); if (!lpNew) { cmd_free(List); - return FALSE; + return 1; } lpNew->prev = fc; lpNew->firstvar = Cmd->For.Variable; @@ -472,21 +479,21 @@ ExecuteFor(PARSED_COMMAND *Cmd) if (Cmd->For.Switches & FOR_F) { - Success = ForF(Cmd, List, Buffer); + Ret = ForF(Cmd, List, Buffer); } else if (Cmd->For.Switches & FOR_LOOP) { - ForLoop(Cmd, List, Buffer); + Ret = ForLoop(Cmd, List, Buffer); } else if (Cmd->For.Switches & FOR_RECURSIVE) { DWORD Len = GetFullPathName(Cmd->For.Params ? Cmd->For.Params : _T("."), MAX_PATH, Buffer, NULL); - ForRecursive(Cmd, List, Buffer, &Buffer[Len]); + Ret = ForRecursive(Cmd, List, Buffer, &Buffer[Len]); } else { - ForDir(Cmd, List, Buffer, Buffer); + Ret = ForDir(Cmd, List, Buffer, Buffer); } /* Remove our context, unless someone already did that */ @@ -495,7 +502,7 @@ ExecuteFor(PARSED_COMMAND *Cmd) cmd_free(lpNew); cmd_free(List); - return Success; + return Ret; } /* EOF */ diff --git a/reactos/base/shell/cmd/if.c b/reactos/base/shell/cmd/if.c index 913a1a8e19f..2f2ae79e7e8 100644 --- a/reactos/base/shell/cmd/if.c +++ b/reactos/base/shell/cmd/if.c @@ -63,7 +63,7 @@ INT cmd_if (LPTSTR param) return 1; } -BOOL ExecuteIf(PARSED_COMMAND *Cmd) +INT ExecuteIf(PARSED_COMMAND *Cmd) { INT result = FALSE; /* when set cause 'then' clause to be executed */ LPTSTR param; @@ -73,13 +73,13 @@ BOOL ExecuteIf(PARSED_COMMAND *Cmd) { Left = DoDelayedExpansion(Cmd->If.LeftArg); if (!Left) - return FALSE; + return 1; } Right = DoDelayedExpansion(Cmd->If.RightArg); if (!Right) { cmd_free(Left); - return FALSE; + return 1; } if (Cmd->If.Operator == IF_CMDEXTVERSION) @@ -91,7 +91,7 @@ BOOL ExecuteIf(PARSED_COMMAND *Cmd) { error_syntax(Right); cmd_free(Right); - return FALSE; + return 1; } result = (2 >= n); } @@ -108,7 +108,7 @@ BOOL ExecuteIf(PARSED_COMMAND *Cmd) { error_syntax(Right); cmd_free(Right); - return FALSE; + return 1; } result = (nErrorLevel >= n); } @@ -166,7 +166,7 @@ BOOL ExecuteIf(PARSED_COMMAND *Cmd) /* full condition was false, do the "else" command if there is one */ if (Cmd->Subcommands->Next) return ExecuteCommand(Cmd->Subcommands->Next); - return TRUE; + return 0; } }