From: Dmitry Sokolov mr.dmitry.sokolov@gmail.com
Visual Studio's native tool command prompt uses rare FOR loop variables: %%1, %%2. This fix allows to use %%1 var in FOR loops.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55401 --- programs/cmd/batch.c | 4 ++-- programs/cmd/builtins.c | 4 ++-- programs/cmd/tests/test_builtins.cmd | 10 ++++----- programs/cmd/tests/test_builtins.cmd.exp | 16 +++++++------- programs/cmd/wcmd.h | 28 ++++++++++++++---------- programs/cmd/wcmdmain.c | 4 ++-- 6 files changed, 35 insertions(+), 31 deletions(-)
diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c index 3586cd45731..7ea51c3de6b 100644 --- a/programs/cmd/batch.c +++ b/programs/cmd/batch.c @@ -396,7 +396,7 @@ void WCMD_HandleTildeModifiers(WCHAR **start, BOOL atExecute) break;
} else { - int foridx = FOR_VAR_IDX(*lastModifier); + int foridx = get_FOR_var_index(*lastModifier); /* Its a valid parameter identifier - OK */ if ((foridx >= 0) && (forloopcontext.variable[foridx] != NULL)) break;
@@ -424,7 +424,7 @@ void WCMD_HandleTildeModifiers(WCHAR **start, BOOL atExecute) *lastModifier-'0' + context -> shift_count[*lastModifier-'0'], NULL, FALSE, TRUE)); } else { - int foridx = FOR_VAR_IDX(*lastModifier); + int foridx = get_FOR_var_index(*lastModifier); lstrcpyW(outputparam, forloopcontext.variable[foridx]); }
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index c8700a412a3..d8a74a6249f 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -2002,7 +2002,7 @@ static void WCMD_parse_line(CMD_LIST *cmdStart, lasttoken = -1; nexttoken = WCMD_for_nexttoken(lasttoken, forf_tokens, &totalfound, &starfound, &thisduplicate); - varidx = FOR_VAR_IDX(variable); + varidx = get_FOR_var_index(variable);
/* Empty out variables */ for (varoffset=0; @@ -2241,7 +2241,7 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) {
/* Variable should follow */ lstrcpyW(variable, thisArg); - varidx = FOR_VAR_IDX(variable[1]); + varidx = get_FOR_var_index(variable[1]); WINE_TRACE("Variable identified as %s (idx: %d)\n", wine_dbgstr_w(variable), varidx);
/* Ensure line continues with IN */ diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd index 2a617b2225b..f726b124bc1 100644 --- a/programs/cmd/tests/test_builtins.cmd +++ b/programs/cmd/tests/test_builtins.cmd @@ -1608,7 +1608,7 @@ for %%i in (test) do ( echo --- for loop with rare var names set "WINE_LOG_LEVEL=" :test_for_loop_params -set "WINE_ARGS= -sdkver=10.0.22000.0 -type=MD" +set "WINE_ARGS= -foo=bar -x=y" :test_for_loop_params_parse for /F "tokens=1,* delims= " %%a in ("%WINE_ARGS%") do ( for /F "tokens=1,2 delims==" %%1 in ("%%a") do ( @@ -1626,12 +1626,12 @@ goto :test_for_loop_params_end
:test_for_loop_params_inner set "__arg_found=" -if /I "%1"=="-sdkver" ( - echo SDKVER=%2 +if /I "%1"=="-boo" ( + echo foo=%2 set "__arg_found=1" ) -if /I "%1"=="-type" ( - echo TYPE=%2 +if /I "%1"=="-x" ( + echo x=%2 set "__arg_found=1" ) if "%__arg_found%" NEQ "1" ( diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp index 6a90f9d7584..e106a0d2f9a 100644 --- a/programs/cmd/tests/test_builtins.cmd.exp +++ b/programs/cmd/tests/test_builtins.cmd.exp @@ -1066,14 +1066,14 @@ a4 c4 d4 --- for loop with rare var names -SDKVER=10.0.22000.0 -TYPE=MD -SDKVER=10.0.22000.0 -TYPE=MD -[DEBUG] inner argument {-sdkver, 10.0.22000.0} -SDKVER=10.0.22000.0 -[DEBUG] inner argument {-type, MD} -TYPE=MD +foo=bar +x=y +foo=bar +x=y +[DEBUG] inner argument {-foo, bar} +foo=bar +[DEBUG] inner argument {-x, y} +x=y --- set /a ------ individual operations WINE_foo correctly 3 diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index 53e3883683b..829c46100e5 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -186,18 +186,22 @@ typedef struct _DIRECTORY_STACK /* Data structure to for loop variables during for body execution, bearing in mind that for loops can be nested */ #define MAX_FOR_VARIABLES 62 -#define FOR_VAR_IDX(c) ( ((c)>='a'&&(c)<='z')\ - ?((c)-'a')\ - :( ((c)>='A'&&(c)<='Z')\ - ?(26+(c)-'A')\ - :( ((c)>='0'&&(c)<='9')\ - ?(52+(c)-'0')\ - :-1 ) ) ) -#define FOR_VAR_NAME(idx) ( (idx)>=52\ - ?('0'+((idx)-52))\ - :( (idx)>=26\ - ?('A'+((idx)-26))\ - :('a'+(idx)) ) ) + +static inline int get_FOR_var_index(WCHAR c) +{ + if (c >= 'a' && c <= 'z') { return c - 'a'; } + if (c >= 'A' && c <= 'Z') { return 26 + c - 'A'; } + if (c >= '0' && c <= '9') { return 52 + c - '0'; } + return -1; +} + +static inline WCHAR get_FOR_var_name(int index) +{ + if (index >= 52) { return '0' + index - 52; } + if (index >= 26) { return 'A' + index - 26; } + if (index >= 0) { return 'a' + index; } + return 'a'; +}
typedef struct _FOR_CONTEXT { WCHAR *variable[MAX_FOR_VARIABLES]; /* a-z then A-Z then 0-9 */ diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 8e7601b863d..f3f14a005c8 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -816,7 +816,7 @@ void handleExpansion(WCHAR *cmd, BOOL atExecute, BOOL delayed) { for (i=0;i<MAX_FOR_VARIABLES;i++) { if (forloopcontext.variable[i]) { WINE_TRACE("FOR variable context: %c = '%s'\n", - FOR_VAR_NAME(i), + get_FOR_var_name(i), wine_dbgstr_w(forloopcontext.variable[i])); } } @@ -865,7 +865,7 @@ void handleExpansion(WCHAR *cmd, BOOL atExecute, BOOL delayed) { WCMD_strsubstW(p, p+2, NULL, 0);
} else { - int forvaridx = FOR_VAR_IDX(*(p+1)); + int forvaridx = get_FOR_var_index(*(p+1)); if (startchar == '%' && forvaridx != -1 && forloopcontext.variable[forvaridx]) { /* Replace the 2 characters, % and for variable character */ WINE_TRACE("FOR variable substitute %%%c with '%s'\n", *(p+1), wine_dbgstr_w(forloopcontext.variable[forvaridx]));