From: Mikhail Bystryantsev Subject: [3/3] cmd: implemented && and || functionality (try 2) Message-Id: <1422112005.634974347@f346.i.mail.ru> Date: Sat, 24 Jan 2015 18:06:45 +0300 Implemented expected behavior of && and || delimeters, https://bugs.winehq.org/show_bug.cgi?id=32679 Try 2 (removed leading spaces from tests) From 0fcf30876215762b92d8a5dfd2fe8d9d99ce9771 Mon Sep 17 00:00:00 2001 From: Mikhail Bystryantsev Date: Thu, 8 Jan 2015 01:41:48 +0200 Subject: cmd: implemented && and || functionality --- programs/cmd/builtins.c | 17 +++++++++++++---- programs/cmd/tests/test_builtins.cmd | 13 +++++++++++++ programs/cmd/tests/test_builtins.cmd.exp | 11 +++++++++++ programs/cmd/tests/test_cmdline.cmd | 20 ++++++++++++++++++++ programs/cmd/tests/test_cmdline.cmd.exp | 22 ++++++++++++++++++++++ programs/cmd/wcmdmain.c | 10 +++++++++- 6 files changed, 88 insertions(+), 5 deletions(-) diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index 992ca5c..17b4867 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -1503,6 +1503,7 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd, { CMD_LIST *curPosition = *cmdList; int myDepth = (*cmdList)->bracketDepth; + BOOL skipAppended = FALSE; WINE_TRACE("cmdList(%p), firstCmd(%s), doIt(%d)\n", cmdList, wine_dbgstr_w(firstcmd), executecmds); @@ -1537,10 +1538,17 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd, (*cmdList)->bracketDepth, myDepth); /* Execute any statements appended to the line */ - /* FIXME: Only if previous call worked for && or failed for || */ if ((*cmdList)->prevDelim == CMD_ONFAILURE || (*cmdList)->prevDelim == CMD_ONSUCCESS) { - if (processThese && (*cmdList)->command) { + + if (!skipAppended && + (((*cmdList)->prevDelim == CMD_ONFAILURE && errorlevel == 0) || + ((*cmdList)->prevDelim == CMD_ONSUCCESS && errorlevel != 0))) { + WINE_TRACE("Prev delim %d and errorlevel %d, skipping appended statements\n", (*cmdList)->prevDelim, errorlevel); + skipAppended = TRUE; + } + + if (!skipAppended && processThese && (*cmdList)->command) { WCMD_execute ((*cmdList)->command, (*cmdList)->redirects, cmdList, FALSE); } @@ -1548,7 +1556,7 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd, /* Execute any appended to the statement with (...) */ } else if ((*cmdList)->bracketDepth > myDepth) { - if (processThese) { + if (!skipAppended && processThese) { *cmdList = WCMD_process_commands(*cmdList, TRUE, FALSE); WINE_TRACE("Back from processing commands, (next = %p)\n", *cmdList); } @@ -1562,9 +1570,10 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd, /* Swap between if and else processing */ processThese = !processThese; + skipAppended = FALSE; /* Process the ELSE part */ - if (processThese) { + if (!skipAppended && processThese) { const int keyw_len = sizeof(ifElse)/sizeof(ifElse[0]) + 1; WCHAR *cmd = ((*cmdList)->command) + keyw_len; diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd index 16fdd43..4ee9708 100644 --- a/programs/cmd/tests/test_builtins.cmd +++ b/programs/cmd/tests/test_builtins.cmd @@ -194,6 +194,19 @@ type C (if 1==0 (echo A > B) else echo C) cd .. & rd /s/q foobar +echo --------- Testing ONSUCCESS and ONFAILURE delimeters -------------- +if 1 == 1 (echo 1) || echo 2 +echo -- +if 1 == 1 (echo 1) && echo 2 +echo -- +if 1 == 1 (cmd /c exit 0) && echo 1 +echo -- +if 1 == 1 (cmd /c exit 1) && echo 1 +echo -- +if 1 == 1 (cmd /c exit 0) || echo 1 +echo -- +if 1 == 1 (cmd /c exit 1) || echo 1 + echo ------------ Testing circumflex escape character ------------ rem Using something like "echo foo^" asks for an additional char after a "More?" prompt on the following line; it's not possible to currently test that non-interactively echo ^hell^o, world diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp index 828a651..5cf7adc 100644 --- a/programs/cmd/tests/test_builtins.cmd.exp +++ b/programs/cmd/tests/test_builtins.cmd.exp @@ -199,6 +199,17 @@ foo A B C +--------- Testing ONSUCCESS and ONFAILURE delimeters -------------- +1 +-- +1 +2 +-- +1 +-- +-- +-- +1 ------------ Testing circumflex escape character ------------ hello, world hello, world diff --git a/programs/cmd/tests/test_cmdline.cmd b/programs/cmd/tests/test_cmdline.cmd index 32a1ef2..a7e74e2 100644 --- a/programs/cmd/tests/test_cmdline.cmd +++ b/programs/cmd/tests/test_cmdline.cmd @@ -266,6 +266,26 @@ call tell 1 2 call tell(1234) call tell(12(34) call tell(12;34) +echo --------- Testing ONSUCCESS and ONFAILURE delimeters -------------- +echo 1 && echo 2 +echo -- +echo 1 || echo 2 +echo -- +echo 1 || echo 2 && echo 3 +echo -- +echo 1 && echo 2 || echo 3 +echo -- +echo 1 && echo 2 && echo 3 +echo -- +echo 1 || echo 2 || echo 3 +echo -- +cmd /c exit 0 && echo 1 +echo -- +cmd /c exit 1 && echo 1 +echo -- +cmd /c exit 0 || echo 1 +echo -- +cmd /c exit 1 || echo 1 echo --------- Finished -------------- del tell.bat say*.* bazbaz*.bat exit diff --git a/programs/cmd/tests/test_cmdline.cmd.exp b/programs/cmd/tests/test_cmdline.cmd.exp index 980f674..90dd32e 100644 --- a/programs/cmd/tests/test_cmdline.cmd.exp +++ b/programs/cmd/tests/test_cmdline.cmd.exp @@ -130,4 +130,26 @@ THIS FAILS: cmd ignoreme/c say one 0:tell,1:(1234),2:,All:'(1234)' 0:tell,1:(12(34),2:,All:'(12(34)' 0:tell,1:(12,2:34),All:'(12;34)' +--------- Testing ONSUCCESS and ONFAILURE delimeters -------------- +1 +2 +-- +1 +-- +1 +-- +1 +2 +-- +1 +2 +3 +-- +1 +-- +1 +-- +-- +-- +1 --------- Finished -------------- diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index e5865e6..b593776 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -2269,6 +2269,7 @@ CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket, BOOL retrycall) { int bdepth = -1; + BOOL skipAppended = FALSE; if (thisCmd && oneBracket) bdepth = thisCmd->bracketDepth; @@ -2286,10 +2287,17 @@ CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket, return thisCmd->nextcommand; } + if (!skipAppended && + ((thisCmd->prevDelim == CMD_ONFAILURE && errorlevel == 0) || + (thisCmd->prevDelim == CMD_ONSUCCESS && errorlevel != 0))) { + WINE_TRACE("Prev delim %d and errorlevel %d, skip following commands\n", thisCmd->prevDelim, errorlevel); + skipAppended = TRUE; + } + /* Ignore the NULL entries a ')' inserts (Only 'if' cares about them and it will be handled in there) Also, skip over any batch labels (eg. :fred) */ - if (thisCmd->command && thisCmd->command[0] != ':') { + if (!skipAppended && thisCmd->command && thisCmd->command[0] != ':') { WINE_TRACE("Executing command: '%s'\n", wine_dbgstr_w(thisCmd->command)); WCMD_execute (thisCmd->command, thisCmd->redirects, &thisCmd, retrycall); } -- 1.8.5.2.msysgit.0