[PATCH] cmd: Fix 'CALL IF' and 'CALL FOR' handling with ()
Flávio J. Saraiva
flaviojs2005 at gmail.com
Sun Nov 6 14:45:10 CST 2016
'call if 1==1 (echo 1)' should produce a single error, instead it was
giving an error and executing 'echo 1'
'call for %i in (foo bar baz) do (echo %i)' should produce a single
error, instead it was giving 3 errors and executing 'echo %i'
Based on cmd.exe behavior in Windows XP
Signed-off-by: Flávio J. Saraiva <flaviojs2005 at gmail.com>
---
programs/cmd/tests/test_builtins.cmd | 8 ++++--
programs/cmd/tests/test_builtins.cmd.exp | 6 +++--
programs/cmd/wcmdmain.c | 42 ++++++++++++++++++++++----------
3 files changed, 39 insertions(+), 17 deletions(-)
diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd
index 38a7700..1ff55eb 100644
--- a/programs/cmd/tests/test_builtins.cmd
+++ b/programs/cmd/tests/test_builtins.cmd
@@ -2116,10 +2116,14 @@ dir /b
if exist batfile echo batfile shouldn't exist
rem ... but not for 'if' or 'for'
call if 1==1 echo bar 2> nul
-echo %ErrorLevel%
+echo ErrorLevel is %ErrorLevel% after call if
+call if 1==1 (echo bar2) 2> nul
+echo ErrorLevel is %ErrorLevel% after call if with ()
call :setError 0
call for %%i in (foo bar baz) do echo %%i 2> nul
-echo %ErrorLevel%
+echo ErrorLevel is %ErrorLevel% after call for
+call for %%i in (foo bar baz) do (echo %%i) 2> nul
+echo ErrorLevel is %ErrorLevel% after call for with ()
rem First look for programs in the path before trying a builtin
echo echo non-builtin dir> dir.cmd
call dir /b
diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp
index d01a23e..6a37323 100644
--- a/programs/cmd/tests/test_builtins.cmd.exp
+++ b/programs/cmd/tests/test_builtins.cmd.exp
@@ -1201,8 +1201,10 @@ foo created
Should expand foobaz
batfile
robinfile
-1
-1
+ErrorLevel is 1 after call if
+ErrorLevel is 1 after call if with ()
+ErrorLevel is 1 after call for
+ErrorLevel is 1 after call for with ()
non-builtin dir
Line one
Line two
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index 87f5387..bb7b568 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -1236,10 +1236,31 @@ void WCMD_run_program (WCHAR *command, BOOL called)
/* Parse the command string, without reading any more input */
WCMD_ReadAndParseLine(command, &toExecute, INVALID_HANDLE_VALUE);
- WCMD_process_commands(toExecute, FALSE, called);
- WCMD_free_commands(toExecute);
- toExecute = NULL;
- return;
+
+ /* Very oddly, probably because of all the special parsing required for
+ these two commands, neither 'for' nor 'if' is supported when called,
+ i.e. 'call if 1==1...' will fail. */
+ if (toExecute) {
+ int len = 0;
+ WCHAR *name;
+ BOOL canExecute = TRUE;
+
+ name = WCMD_skip_leading_spaces(toExecute->command);
+ while (IsCharAlphaNumericW(*(name+len))) len++;
+
+ if ((CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
+ name, len, inbuilt[WCMD_FOR], -1) == CSTR_EQUAL) ||
+ (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
+ name, len, inbuilt[WCMD_IF], -1) == CSTR_EQUAL)) {
+ canExecute = FALSE;
+ }
+
+ /* Execute commands or drop to error */
+ if (canExecute) WCMD_process_commands(toExecute, FALSE, called);
+ WCMD_free_commands(toExecute);
+ toExecute = NULL;
+ if (canExecute) return;
+ }
}
/* Not found anywhere - give up */
@@ -1601,16 +1622,11 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
WCMD_exit (cmdList);
break;
case WCMD_FOR:
+ WCMD_for(p, cmdList);
+ break;
case WCMD_IF:
- /* Very oddly, probably because of all the special parsing required for
- these two commands, neither 'for' nor 'if' is supported when called,
- i.e. 'call if 1==1...' will fail. */
- if (!retrycall) {
- if (i==WCMD_FOR) WCMD_for (p, cmdList);
- else if (i==WCMD_IF) WCMD_if (p, cmdList);
- break;
- }
- /* else: drop through */
+ WCMD_if(p, cmdList);
+ break;
default:
prev_echo_mode = echo_mode;
WCMD_run_program (whichcmd, FALSE);
--
2.7.4
More information about the wine-patches
mailing list