From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/batch.c | 11 ++++---- programs/cmd/builtins.c | 58 ++++++++++++++++------------------------- programs/cmd/wcmd.h | 12 ++++++--- programs/cmd/wcmdmain.c | 52 ++++++++++++++++++++++++++++++++---- 4 files changed, 84 insertions(+), 49 deletions(-)
diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c index b67b14019f3..d85cbf810aa 100644 --- a/programs/cmd/batch.c +++ b/programs/cmd/batch.c @@ -398,7 +398,7 @@ void WCMD_HandleTildeModifiers(WCHAR **start, BOOL atExecute) } else { int foridx = for_var_char_to_index(*lastModifier); /* Its a valid parameter identifier - OK */ - if ((foridx >= 0) && (forloopcontext.variable[foridx] != NULL)) break; + if ((foridx >= 0) && (forloopcontext->variable[foridx] != NULL)) break;
/* Its not a valid parameter identifier - step backwards */ lastModifier--; @@ -425,7 +425,8 @@ void WCMD_HandleTildeModifiers(WCHAR **start, BOOL atExecute) NULL, FALSE, TRUE)); } else { int foridx = for_var_char_to_index(*lastModifier); - lstrcpyW(outputparam, forloopcontext.variable[foridx]); + if (foridx != -1) + lstrcpyW(outputparam, forloopcontext->variable[foridx]); }
/* 1. Handle '~' : Strip surrounding quotes */ @@ -663,12 +664,10 @@ void WCMD_call (WCHAR *command) { if (context) {
LARGE_INTEGER li; - FOR_CONTEXT oldcontext;
/* Save the for variable context, then start with an empty context as for loop variables do not survive a call */ - oldcontext = forloopcontext; - memset(&forloopcontext, 0, sizeof(forloopcontext)); + WCMD_save_for_loop_context(TRUE);
/* Save the current file position, call the same file, restore position */ @@ -680,7 +679,7 @@ void WCMD_call (WCHAR *command) { &li.u.HighPart, FILE_BEGIN);
/* Restore the for loop context */ - forloopcontext = oldcontext; + WCMD_restore_for_loop_context(); } else { WCMD_output_asis_stderr(WCMD_LoadMessage(WCMD_CALLINSCRIPT)); } diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index f94230e6fae..f036f840958 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -1962,7 +1962,6 @@ static void WCMD_parse_line(CMD_NODE *cmdStart, WCHAR *forf_tokens) {
WCHAR *parm; - FOR_CONTEXT oldcontext; int varoffset; int nexttoken, lasttoken = -1; BOOL starfound = FALSE; @@ -1978,7 +1977,7 @@ static void WCMD_parse_line(CMD_NODE *cmdStart, }
/* Save away any existing for variable context (e.g. nested for loops) */ - oldcontext = forloopcontext; + WCMD_save_for_loop_context(FALSE);
/* Extract the parameters based on the tokens= value (There will always be some value, as if it is not supplied, it defaults to tokens=1). @@ -1999,7 +1998,7 @@ static void WCMD_parse_line(CMD_NODE *cmdStart, for (varoffset=0; varidx >= 0 && varoffset<totalfound && for_var_index_in_range(varidx, varoffset); varoffset++) { - forloopcontext.variable[varidx + varoffset] = emptyW; + WCMD_set_for_loop_variable(varidx + varoffset, emptyW); }
/* Loop extracting the tokens @@ -2017,7 +2016,8 @@ static void WCMD_parse_line(CMD_NODE *cmdStart, WINE_TRACE("Parsed token %d(%d) as parameter %s\n", nexttoken, varidx + varoffset, wine_dbgstr_w(parm)); if (varidx >=0) { - if (parm) forloopcontext.variable[varidx + varoffset] = xstrdupW(parm); + if (parm) + WCMD_set_for_loop_variable(varidx + varoffset, parm); varoffset++; }
@@ -2034,30 +2034,19 @@ static void WCMD_parse_line(CMD_NODE *cmdStart, WCMD_parameter_with_delims(buffer, (nexttoken-1), &parm, FALSE, FALSE, forf_delims); WINE_TRACE("Parsed allremaining tokens (%d) as parameter %s\n", varidx + varoffset, wine_dbgstr_w(parm)); - if (parm) forloopcontext.variable[varidx + varoffset] = xstrdupW(parm); + if (parm) + WCMD_set_for_loop_variable(varidx + varoffset, parm); }
/* Execute the body of the foor loop with these values */ - if (varidx >= 0 && forloopcontext.variable[varidx] && forloopcontext.variable[varidx][0] != forf_eol) { + if (varidx >= 0 && forloopcontext->variable[varidx] && forloopcontext->variable[varidx][0] != forf_eol) { CMD_NODE *thisCmdStart = cmdStart; *doExecuted = TRUE; WCMD_part_execute(&thisCmdStart, firstCmd, FALSE, TRUE); *cmdEnd = thisCmdStart; }
- /* Free the duplicated strings, and restore the context */ - if (varidx >=0) { - int i; - for (i=varidx; i<MAX_FOR_VARIABLES; i++) { - if ((forloopcontext.variable[i] != oldcontext.variable[i]) && - (forloopcontext.variable[i] != emptyW)) { - free(forloopcontext.variable[i]); - } - } - } - - /* Restore the original for variable contextx */ - forloopcontext = oldcontext; + WCMD_restore_for_loop_context(); }
/************************************************************************** @@ -2077,7 +2066,7 @@ static void WCMD_parse_line(CMD_NODE *cmdStart, * * Returns a file handle which can be used to read the input lines from. */ -static FILE* WCMD_forf_getinput(BOOL usebackq, WCHAR *itemstr, BOOL iscmd) +static FILE *WCMD_forf_getinput(BOOL usebackq, WCHAR *itemstr, BOOL iscmd) { WCHAR *trimmed = NULL; FILE* ret; @@ -2132,7 +2121,6 @@ void WCMD_for (WCHAR *p, CMD_NODE **cmdList) { CMD_NODE *setStart, *thisSet, *cmdStart, *cmdEnd; WCHAR variable[4]; int varidx = -1; - WCHAR *oldvariablevalue; WCHAR *firstCmd; int thisDepth; WCHAR optionsRoot[MAX_PATH]; @@ -2352,14 +2340,13 @@ void WCMD_for (WCHAR *p, CMD_NODE **cmdList) { } doExecuted = TRUE;
+ WCMD_save_for_loop_context(FALSE); /* Save away any existing for variable context (e.g. nested for loops) and restore it after executing the body of this for loop */ - if (varidx >= 0) { - oldvariablevalue = forloopcontext.variable[varidx]; - forloopcontext.variable[varidx] = fullitem; - } + if (varidx >= 0) + WCMD_set_for_loop_variable(varidx, fullitem); WCMD_part_execute (&thisCmdStart, firstCmd, FALSE, TRUE); - if (varidx >= 0) forloopcontext.variable[varidx] = oldvariablevalue; + WCMD_restore_for_loop_context();
cmdEnd = thisCmdStart; } @@ -2369,14 +2356,13 @@ void WCMD_for (WCHAR *p, CMD_NODE **cmdList) { } else { doExecuted = TRUE;
+ WCMD_save_for_loop_context(FALSE); /* Save away any existing for variable context (e.g. nested for loops) and restore it after executing the body of this for loop */ - if (varidx >= 0) { - oldvariablevalue = forloopcontext.variable[varidx]; - forloopcontext.variable[varidx] = fullitem; - } + if (varidx >= 0) + WCMD_set_for_loop_variable(varidx, fullitem); WCMD_part_execute (&thisCmdStart, firstCmd, FALSE, TRUE); - if (varidx >= 0) forloopcontext.variable[varidx] = oldvariablevalue; + WCMD_restore_for_loop_context();
cmdEnd = thisCmdStart; } @@ -2491,12 +2477,14 @@ void WCMD_for (WCHAR *p, CMD_NODE **cmdList) {
/* Save away any existing for variable context (e.g. nested for loops) and restore it after executing the body of this for loop */ - if (varidx >= 0) { - oldvariablevalue = forloopcontext.variable[varidx]; - forloopcontext.variable[varidx] = thisNum; + if (varidx >= 0) + { + WCMD_save_for_loop_context(FALSE); + WCMD_set_for_loop_variable(varidx, thisNum); } WCMD_part_execute (&thisCmdStart, firstCmd, FALSE, TRUE); - if (varidx >= 0) forloopcontext.variable[varidx] = oldvariablevalue; + if (varidx >= 0) + WCMD_restore_for_loop_context(); } cmdEnd = thisCmdStart; } diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index d556cd59fe8..9d4f55bc414 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -288,10 +288,16 @@ static inline BOOL for_var_index_in_range(int var_idx, int var_offset) return for_var_char_to_index(for_var_index_to_char(var_idx) + var_offset) == var_idx + var_offset; }
-typedef struct _FOR_CONTEXT { - WCHAR *variable[MAX_FOR_VARIABLES]; /* a-z then A-Z */ +typedef struct _FOR_CONTEXT +{ + struct _FOR_CONTEXT *previous; + WCHAR *variable[MAX_FOR_VARIABLES]; /* a-z then A-Z */ } FOR_CONTEXT;
+void WCMD_save_for_loop_context(BOOL reset); +void WCMD_restore_for_loop_context(void); +void WCMD_set_for_loop_variable(int var_idx, const WCHAR *value); + /* * Global variables quals, param1, param2 contain the current qualifiers * (uppercased and concatenated) and parameters entered, with environment @@ -300,7 +306,7 @@ typedef struct _FOR_CONTEXT { extern WCHAR quals[MAXSTRING], param1[MAXSTRING], param2[MAXSTRING]; extern int errorlevel; extern BATCH_CONTEXT *context; -extern FOR_CONTEXT forloopcontext; +extern FOR_CONTEXT *forloopcontext; extern BOOL delayedsubst;
#endif /* !RC_INVOKED */ diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 9e5f1eae241..da9d93f4dde 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -39,7 +39,7 @@ BATCH_CONTEXT *context = NULL; int errorlevel; WCHAR quals[MAXSTRING], param1[MAXSTRING], param2[MAXSTRING]; BOOL interactive; -FOR_CONTEXT forloopcontext; /* The 'for' loop context */ +FOR_CONTEXT *forloopcontext; /* The 'for' loop context */ BOOL delayedsubst = FALSE; /* The current delayed substitution setting */
int defaultColor = 7; @@ -808,10 +808,10 @@ static void handleExpansion(WCHAR *cmd, BOOL atExecute, BOOL delayed) {
/* Display the FOR variables in effect */ for (i=0;i<MAX_FOR_VARIABLES;i++) { - if (forloopcontext.variable[i]) { + if (forloopcontext->variable[i]) { WINE_TRACE("FOR variable context: %c = '%s'\n", for_var_index_to_char(i), - wine_dbgstr_w(forloopcontext.variable[i])); + wine_dbgstr_w(forloopcontext->variable[i])); } }
@@ -860,9 +860,9 @@ static void handleExpansion(WCHAR *cmd, BOOL atExecute, BOOL delayed) {
} else { int forvaridx = for_var_char_to_index(*(p+1)); - if (startchar == '%' && forvaridx != -1 && forloopcontext.variable[forvaridx]) { + if (startchar == '%' && forvaridx != -1 && forloopcontext->variable[forvaridx]) { /* Replace the 2 characters, % and for variable character */ - WCMD_strsubstW(p, p + 2, forloopcontext.variable[forvaridx], -1); + WCMD_strsubstW(p, p + 2, forloopcontext->variable[forvaridx], -1); } else if (!atExecute || startchar == '!') { p = WCMD_expand_envvar(p, startchar);
@@ -2710,6 +2710,44 @@ BOOL if_condition_evaluate(CMD_IF_CONDITION *cond, int *test) return TRUE; }
+void WCMD_save_for_loop_context(BOOL reset) +{ + FOR_CONTEXT *new = xalloc(sizeof(*new)); + if (reset) + memset(new, 0, sizeof(*new)); + else /* clone existing */ + *new = *forloopcontext; + new->previous = forloopcontext; + forloopcontext = new; +} + +void WCMD_restore_for_loop_context(void) +{ + FOR_CONTEXT *old = forloopcontext->previous; + int varidx; + if (!old) + { + FIXME("Unexpected situation\n"); + return; + } + for (varidx = 0; varidx < MAX_FOR_VARIABLES; varidx++) + { + if (forloopcontext->variable[varidx] != old->variable[varidx]) + free(forloopcontext->variable[varidx]); + } + free(forloopcontext); + forloopcontext = old; +} + +void WCMD_set_for_loop_variable(int var_idx, const WCHAR *value) +{ + if (var_idx < 0 || var_idx >= MAX_FOR_VARIABLES) return; + if (forloopcontext->previous && + forloopcontext->previous->variable[var_idx] != forloopcontext->variable[var_idx]) + free(forloopcontext->variable[var_idx]); + forloopcontext->variable[var_idx] = xstrdupW(value); +} + /*************************************************************************** * WCMD_process_commands * @@ -2799,6 +2837,10 @@ int __cdecl wmain (int argc, WCHAR *argvW[]) LocalFree(cmd); cmd = NULL;
+ /* init for loop context */ + forloopcontext = NULL; + WCMD_save_for_loop_context(TRUE); + /* Can't use argc/argv as it will have stripped quotes from parameters * meaning cmd.exe /C echo "quoted string" is impossible */