From: Dmitry Sokolov mr.dmitry.sokolov@gmail.com
--- programs/cmd/builtins.c | 25 +++++++++++++++++++++++-- programs/cmd/wcmd.h | 7 +++++++ programs/cmd/wcmdmain.c | 37 ++++++++++++++++++++++++++++++++++--- 3 files changed, 64 insertions(+), 5 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index a0cb7025d83..d6f23ae020c 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -1485,6 +1485,8 @@ void WCMD_echo (const WCHAR *args) const WCHAR *origcommand = args; WCHAR *trimmed;
+ WCMD_set_lastCmdStatus(TRUE); + if ( args[0]==' ' || args[0]=='\t' || args[0]=='.' || args[0]==':' || args[0]==';' || args[0]=='/') args++; @@ -2723,6 +2725,8 @@ void WCMD_pushd (const WCHAR *args) void WCMD_popd (void) { struct env_stack *temp = pushd_directories;
+ WCMD_set_lastCmdStatus(FALSE); + if (!pushd_directories) return;
@@ -2731,6 +2735,7 @@ void WCMD_popd (void) { SetCurrentDirectoryW(temp->strings); LocalFree (temp->strings); LocalFree (temp); + WCMD_set_lastCmdStatus(TRUE); }
/******************************************************************* @@ -3084,6 +3089,8 @@ void WCMD_pause (void) WCMD_ReadFile(hIn, &key, 1, &count); if (have_console) SetConsoleMode(hIn, oldmode); + + WCMD_set_lastCmdStatus(TRUE); }
/**************************************************************************** @@ -3098,6 +3105,8 @@ void WCMD_remove_dir (WCHAR *args) { int argsProcessed = 0; WCHAR *argN = args;
+ WCMD_set_lastCmdStatus(TRUE); + /* Loop through all args */ while (argN) { WCHAR *thisArg = WCMD_parameter (args, argno++, &argN, FALSE, FALSE); @@ -3109,7 +3118,10 @@ void WCMD_remove_dir (WCHAR *args) { /* If subdirectory search not supplied, just try to remove and report error if it fails (eg if it contains a file) */ if (wcsstr(quals, L"/S") == NULL) { - if (!RemoveDirectoryW(thisArg)) WCMD_print_error (); + if (!RemoveDirectoryW(thisArg)) { + WCMD_set_lastCmdStatus(FALSE); + WCMD_print_error(); + }
/* Otherwise use ShFileOp to recursively remove a directory */ } else { @@ -3139,7 +3151,10 @@ void WCMD_remove_dir (WCHAR *args) { /* SHFileOperationW needs file list with a double null termination */ thisArg[lstrlenW(thisArg) + 1] = 0x00;
- if (SHFileOperationW(&lpDir)) WCMD_print_error (); + if (SHFileOperationW(&lpDir)) { + WCMD_set_lastCmdStatus(FALSE); + WCMD_print_error (); + } } } } @@ -3350,6 +3365,8 @@ void WCMD_endlocal (void) { struct env_stack *temp; int len, n;
+ WCMD_set_lastCmdStatus(TRUE); + /* setlocal does nothing outside of batch programs */ if (!context) return;
@@ -4346,6 +4363,8 @@ void WCMD_setshow_time (void) { void WCMD_shift (const WCHAR *args) { int start;
+ WCMD_set_lastCmdStatus(TRUE); + if (context != NULL) { WCHAR *pos = wcschr(args, '/'); int i; @@ -4355,6 +4374,7 @@ void WCMD_shift (const WCHAR *args) { } else if (*(pos+1)>='0' && *(pos+1)<='8') { start = (*(pos+1) - '0'); } else { + WCMD_set_lastCmdStatus(FALSE); SetLastError(ERROR_INVALID_PARAMETER); WCMD_print_error(); return; @@ -4498,6 +4518,7 @@ void WCMD_start(WCHAR *args) */ void WCMD_title (const WCHAR *args) { SetConsoleTitleW(args); + WCMD_set_lastCmdStatus(TRUE); }
/**************************************************************************** diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index 0710a57c827..a996071309f 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -200,6 +200,7 @@ typedef struct _FOR_CONTEXT { */ extern WCHAR quals[MAXSTRING], param1[MAXSTRING], param2[MAXSTRING]; extern DWORD errorlevel; +extern BOOL lastCmdStatus; extern BATCH_CONTEXT *context; extern FOR_CONTEXT forloopcontext; extern BOOL delayedsubst; @@ -207,6 +208,12 @@ extern BOOL delayedsubst; static inline void WCMD_set_errorlevel(DWORD newValue) { errorlevel = newValue; + lastCmdStatus = (errorlevel == 0); +} + +static inline void WCMD_set_lastCmdStatus(BOOL isSucceeded) +{ + lastCmdStatus = isSucceeded; }
#endif /* !RC_INVOKED */ diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 513543f17d6..3ba1dba22b7 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -37,6 +37,7 @@ extern struct env_stack *pushd_directories;
BATCH_CONTEXT *context = NULL; DWORD errorlevel; +BOOL lastCmdStatus; WCHAR quals[MAXSTRING], param1[MAXSTRING], param2[MAXSTRING]; BOOL interactive; FOR_CONTEXT forloopcontext; /* The 'for' loop context */ @@ -2365,6 +2366,7 @@ CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket, BOOL retrycall) {
int bdepth = -1; + CMD_LIST *prevCmd = NULL;
if (thisCmd && oneBracket) bdepth = thisCmd->bracketDepth;
@@ -2386,12 +2388,41 @@ CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket, about them and it will be handled in there) Also, skip over any batch labels (eg. :fred) */ if (thisCmd->command && thisCmd->command[0] != ':') { - WINE_TRACE("Executing command: '%s'\n", wine_dbgstr_w(thisCmd->command)); - WCMD_execute (thisCmd->command, thisCmd->redirects, &thisCmd, retrycall); + /* Process the command chaining */ + if ( (thisCmd->prevDelim == CMD_ONSUCCESS && lastCmdStatus == FALSE) || + (thisCmd->prevDelim == CMD_ONFAILURE && lastCmdStatus == TRUE) ) { + if (prevCmd && prevCmd->bracketDepth < thisCmd->bracketDepth) { + /* Skipping the chain of commands in brackets */ + int bd = thisCmd->bracketDepth; + do { + WINE_TRACE("Skipping command '%s'\n", wine_dbgstr_w(thisCmd->command)); + prevCmd = thisCmd; + thisCmd = thisCmd->nextcommand; + } while (thisCmd && bd <= thisCmd->bracketDepth); + continue; + } else if (thisCmd->prevDelim == CMD_ONFAILURE && lastCmdStatus == TRUE) { + /* Skipping all chaining commands after '||', i.e. '|| cmd2 && cmd3 || cmd4'*/ + do { + WINE_TRACE("Skipping command '%s'\n", wine_dbgstr_w(thisCmd->command)); + prevCmd = thisCmd; + thisCmd = thisCmd->nextcommand; + } while (thisCmd && (thisCmd->prevDelim == CMD_ONSUCCESS || thisCmd->prevDelim == CMD_ONFAILURE)); + continue; + } else { + /* Skipping the next command */ + WINE_TRACE("Skipping command '%s'\n", wine_dbgstr_w(thisCmd->command)); + } + } else { + WINE_TRACE("Executing command: '%s'\n", wine_dbgstr_w(thisCmd->command)); + WCMD_execute (thisCmd->command, thisCmd->redirects, &thisCmd, retrycall); + } }
/* Step on unless the command itself already stepped on */ - if (thisCmd == origCmd) thisCmd = thisCmd->nextcommand; + if (thisCmd == origCmd) { + prevCmd = thisCmd; + thisCmd = thisCmd->nextcommand; + } } return NULL; }