Continuing lexer state simplification: - removing the remaining state variables in lexer, and fixing a FOR /L regression.
From: Eric Pouech epouech@codeweavers.com
Mainly pairing start / end quote to avoid other characters handling.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/wcmdmain.c | 338 ++++++++++++++++------------------------ 1 file changed, 135 insertions(+), 203 deletions(-)
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 05c7a2737e4..bb1e7c1a3b5 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -2009,60 +2009,6 @@ static WCHAR *find_chr(WCHAR *in, WCHAR *last, const WCHAR *delims) return NULL; }
-/*************************************************************************** - * WCMD_IsEndQuote - * - * Checks if the quote pointed to is the end-quote. - * - * Quotes end if: - * - * 1) The current parameter ends at EOL or at the beginning - * of a redirection or pipe and not in a quote section. - * - * 2) If the next character is a space and not in a quote section. - * - * Returns TRUE if this is an end quote, and FALSE if it is not. - * - */ -static BOOL WCMD_IsEndQuote(const WCHAR *quote, int quoteIndex) -{ - int quoteCount = quoteIndex; - int i; - - /* If we are not in a quoted section, then we are not an end-quote */ - if(quoteIndex == 0) - { - return FALSE; - } - - /* Check how many quotes are left for this parameter */ - for(i=0;quote[i];i++) - { - if(quote[i] == '"') - { - quoteCount++; - } - - /* Quote counting ends at EOL, redirection, space or pipe if current quote is complete */ - else if(((quoteCount % 2) == 0) - && ((quote[i] == '<') || (quote[i] == '>') || (quote[i] == '|') || (quote[i] == ' ') || - (quote[i] == '&'))) - { - break; - } - } - - /* If the quote is part of the last part of a series of quotes-on-quotes, then it must - be an end-quote */ - if(quoteIndex >= (quoteCount / 2)) - { - return TRUE; - } - - /* No cigar */ - return FALSE; -} - static WCHAR *for_fileset_option_split(WCHAR *from, const WCHAR* key) { size_t len = wcslen(key); @@ -2869,7 +2815,6 @@ static BOOL lexer_white_space_only(const WCHAR *string, int len) enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **output) { WCHAR *curPos; - int inQuotes = 0; WCHAR curString[MAXSTRING]; int curStringLen = 0; WCHAR curRedirs[MAXSTRING]; @@ -2934,7 +2879,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** (curPos = fetch_next_line(TRUE, FALSE, extraSpace))) { TRACE("Need to read more data as outstanding brackets or carets\n"); - inQuotes = 0; acceptCommand = TRUE; } else break; @@ -3029,166 +2973,154 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **
switch (thisChar) {
- case '=': /* drop through - ignore token delimiters at the start of a command */ - case ',': /* drop through - ignore token delimiters at the start of a command */ - case '\t':/* drop through - ignore token delimiters at the start of a command */ - case ' ': - /* If a redirect in place, it ends here */ - if (!inQuotes && !lastWasRedirect) { - - /* If finishing off a redirect, add a whitespace delimiter */ - if (curCopyTo == curRedirs) { - curCopyTo[(*curLen)++] = ' '; - } - curCopyTo = curString; - curLen = &curStringLen; - } - if (*curLen > 0) { - curCopyTo[(*curLen)++] = *curPos; - } - break; + case L'=': /* drop through - ignore token delimiters at the start of a command */ + case L',': /* drop through - ignore token delimiters at the start of a command */ + case L'\t':/* drop through - ignore token delimiters at the start of a command */ + case L' ': + /* If a redirect in place, it ends here */ + if (!lastWasRedirect) {
- case '>': /* drop through - handle redirect chars the same */ - case '<': - /* Make a redirect start here */ - if (!inQuotes) { - curCopyTo = curRedirs; - curLen = &curRedirsLen; - lastWasRedirect = TRUE; - } + /* If finishing off a redirect, add a whitespace delimiter */ + if (curCopyTo == curRedirs) { + curCopyTo[(*curLen)++] = L' '; + } + curCopyTo = curString; + curLen = &curStringLen; + } + if (*curLen > 0) { + curCopyTo[(*curLen)++] = *curPos; + } + break;
- /* See if 1>, 2> etc, in which case we have some patching up - to do (provided there's a preceding whitespace, and enough - chars read so far) */ - if (curPos[-1] >= '1' && curPos[-1] <= '9' - && (curStringLen == 1 || - curPos[-2] == ' ' || curPos[-2] == '\t')) { - curStringLen--; - curString[curStringLen] = 0x00; - curCopyTo[(*curLen)++] = *(curPos-1); - } + case L'>': /* drop through - handle redirect chars the same */ + case L'<': + /* Make a redirect start here */ + curCopyTo = curRedirs; + curLen = &curRedirsLen; + lastWasRedirect = TRUE; + + /* See if 1>, 2> etc, in which case we have some patching up + to do (provided there's a preceding whitespace, and enough + chars read so far) */ + if (curPos[-1] >= L'1' && curPos[-1] <= L'9' && (curStringLen == 1 || iswspace(curPos[-2]))) + { + curStringLen--; + curString[curStringLen] = L'\0'; + curCopyTo[(*curLen)++] = *(curPos-1); + }
- curCopyTo[(*curLen)++] = *curPos; + curCopyTo[(*curLen)++] = *curPos;
- /* If a redirect is immediately followed by '&' (ie. 2>&1) then - do not process that ampersand as an AND operator */ - if ((thisChar == '>' || thisChar == '<') && *(curPos+1) == '&') { - curCopyTo[(*curLen)++] = *(curPos+1); - curPos++; - } - break; + /* If a redirect is immediately followed by '&' (ie. 2>&1) then + do not process that ampersand as an AND operator */ + if ((thisChar == '>' || thisChar == '<') && *(curPos+1) == '&') { + curCopyTo[(*curLen)++] = *(curPos+1); + curPos++; + } + break;
- case '|': /* Pipe character only if not || */ - if (!inQuotes) { - lastWasRedirect = FALSE; - - lexer_push_command(&builder, curString, &curStringLen, - curRedirs, &curRedirsLen, - &curCopyTo, &curLen); - - if (*(curPos+1) == '|') { - curPos++; /* Skip other | */ - node_builder_push_token(&builder, TKN_BARBAR); - } else { - node_builder_push_token(&builder, TKN_BAR); - } - acceptCommand = TRUE; - } else { - curCopyTo[(*curLen)++] = *curPos; - } - break; + case L'|': /* Pipe character only if not || */ + lastWasRedirect = FALSE;
- case '"': if (WCMD_IsEndQuote(curPos, inQuotes)) { - inQuotes--; - } else { - inQuotes++; /* Quotes within quotes are fun! */ - } - curCopyTo[(*curLen)++] = *curPos; - lastWasRedirect = FALSE; - break; + lexer_push_command(&builder, curString, &curStringLen, + curRedirs, &curRedirsLen, + &curCopyTo, &curLen); + + if (curPos[1] == L'|') { + curPos++; /* Skip other | */ + node_builder_push_token(&builder, TKN_BARBAR); + } else { + node_builder_push_token(&builder, TKN_BAR); + } + acceptCommand = TRUE; + break; + + case L'"': + /* copy all chars between a pair of " */ + curCopyTo[(*curLen)++] = *curPos; + while (curPos[1]) + { + curCopyTo[(*curLen)++] = *++curPos; + if (*curPos == L'"') break; + } + lastWasRedirect = FALSE; + break;
- case '(': /* If a '(' is the first non whitespace in a command portion + case L'(': /* If a '(' is the first non whitespace in a command portion ie start of line or just after &&, then we read until an unquoted ) is found */ - lastWasRedirect = FALSE; - - if (inQuotes) { - curCopyTo[(*curLen)++] = *curPos; - - /* In a FOR loop, an unquoted '(' may occur straight after - IN or DO - In an IF statement just handle it regardless as we don't - parse the operands - In an ELSE statement, only allow it straight away after - the ELSE and whitespace - */ - } else if ((acceptCommand || node_builder_top(&builder, 0) == TKN_IN) && - lexer_white_space_only(curString, curStringLen)) { - node_builder_push_token(&builder, TKN_OPENPAR); - acceptCommand = TRUE; - } else { - curCopyTo[(*curLen)++] = *curPos; - } - break; + lastWasRedirect = FALSE; + + /* In a FOR loop, an unquoted '(' may occur straight after + IN or DO + In an IF statement just handle it regardless as we don't + parse the operands + In an ELSE statement, only allow it straight away after + the ELSE and whitespace + */ + if ((acceptCommand || node_builder_top(&builder, 0) == TKN_IN) && + lexer_white_space_only(curString, curStringLen)) { + node_builder_push_token(&builder, TKN_OPENPAR); + acceptCommand = TRUE; + } else { + curCopyTo[(*curLen)++] = *curPos; + } + break;
- case '^': if (!inQuotes) { - /* If we reach the end of the input, we need to wait for more */ - if (curPos[1] == L'\0') { - TRACE("Caret found at end of line\n"); - extraSpace[0] = L'^'; - if (optionalcmd) break; - if (!fetch_next_line(TRUE, FALSE, extraSpace + 1)) - break; - if (!extraSpace[1]) /* empty line */ - { - extraSpace[1] = L'\r'; - if (!fetch_next_line(TRUE, FALSE, extraSpace + 2)) - break; - } - curPos = extraSpace; - break; - } - curPos++; - } - curCopyTo[(*curLen)++] = *curPos; - break; + case L'^': /* If we reach the end of the input, we need to wait for more */ + if (curPos[1] == L'\0') { + TRACE("Caret found at end of line\n"); + extraSpace[0] = L'^'; + if (optionalcmd) break; + if (!fetch_next_line(TRUE, FALSE, extraSpace + 1)) + break; + if (!extraSpace[1]) /* empty line */ + { + extraSpace[1] = L'\r'; + if (!fetch_next_line(TRUE, FALSE, extraSpace + 2)) + break; + } + curPos = extraSpace; + break; + } + curPos++; + curCopyTo[(*curLen)++] = *curPos; + break;
- case '&': if (!inQuotes) { - lastWasRedirect = FALSE; - - /* Add an entry to the command list */ - lexer_push_command(&builder, curString, &curStringLen, - curRedirs, &curRedirsLen, - &curCopyTo, &curLen); - - if (*(curPos+1) == '&') { - curPos++; /* Skip other & */ - node_builder_push_token(&builder, TKN_AMPAMP); - } else { - node_builder_push_token(&builder, TKN_AMP); - } - acceptCommand = TRUE; - } else { - curCopyTo[(*curLen)++] = *curPos; - } - break; + case L'&': + lastWasRedirect = FALSE;
- case ')': if (!inQuotes && builder.opened_parenthesis > 0) { - lastWasRedirect = FALSE; - - /* Add the current command if there is one */ - lexer_push_command(&builder, curString, &curStringLen, - curRedirs, &curRedirsLen, - &curCopyTo, &curLen); - node_builder_push_token(&builder, TKN_CLOSEPAR); - acceptCommand = FALSE; - } else { - curCopyTo[(*curLen)++] = *curPos; - } - break; + /* Add an entry to the command list */ + lexer_push_command(&builder, curString, &curStringLen, + curRedirs, &curRedirsLen, + &curCopyTo, &curLen); + + if (*(curPos+1) == L'&') { + curPos++; /* Skip other & */ + node_builder_push_token(&builder, TKN_AMPAMP); + } else { + node_builder_push_token(&builder, TKN_AMP); + } + acceptCommand = TRUE; + break; + + case L')': + if (builder.opened_parenthesis > 0) { + lastWasRedirect = FALSE; + + /* Add the current command if there is one */ + lexer_push_command(&builder, curString, &curStringLen, + curRedirs, &curRedirsLen, + &curCopyTo, &curLen); + node_builder_push_token(&builder, TKN_CLOSEPAR); + acceptCommand = FALSE; + } else { + curCopyTo[(*curLen)++] = *curPos; + } + break; default: - lastWasRedirect = FALSE; - curCopyTo[(*curLen)++] = *curPos; + lastWasRedirect = FALSE; + curCopyTo[(*curLen)++] = *curPos; }
curPos++;
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/wcmdmain.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index bb1e7c1a3b5..f81e6628ec0 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -2852,9 +2852,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** curPos = WCMD_strip_for_command_start(curPos); /* Parse every character on the line being processed */ for (;;) { - - WCHAR thisChar; - /* Debugging AID: WINE_TRACE("Looking at '%c' (len:%d)\n", *curPos, *curLen); */ @@ -2969,9 +2966,7 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** } }
- thisChar = *curPos; - - switch (thisChar) { + switch (*curPos) {
case L'=': /* drop through - ignore token delimiters at the start of a command */ case L',': /* drop through - ignore token delimiters at the start of a command */ @@ -3013,7 +3008,7 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **
/* If a redirect is immediately followed by '&' (ie. 2>&1) then do not process that ampersand as an AND operator */ - if ((thisChar == '>' || thisChar == '<') && *(curPos+1) == '&') { + if ((*curPos == L'>' || *curPos == L'<') && curPos[1] == L'&') { curCopyTo[(*curLen)++] = *(curPos+1); curPos++; }
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/wcmdmain.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-)
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index f81e6628ec0..0fc572adf24 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -2789,6 +2789,24 @@ static BOOL lexer_can_accept_do(const struct node_builder *builder) return node_builder_top(builder, d) == TKN_IN; }
+static BOOL lexer_at_command_start(const struct node_builder *builder) +{ + switch (node_builder_top(builder, 0)) + { + case TKN_EOF: + case TKN_EOL: + case TKN_DO: + case TKN_ELSE: + case TKN_AMP: + case TKN_AMPAMP: + case TKN_BAR: + case TKN_BARBAR: return TRUE; + case TKN_OPENPAR: return node_builder_top(builder, 1) != TKN_IN; + case TKN_COMMAND: return node_builder_top(builder, 1) == TKN_IF; + default: return FALSE; + } +} + static BOOL lexer_white_space_only(const WCHAR *string, int len) { int i; @@ -2823,7 +2841,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** int *curLen; static WCHAR *extraSpace = NULL; /* Deliberately never freed */ BOOL lastWasRedirect = TRUE; - BOOL acceptCommand = TRUE; struct node_builder builder; BOOL ret;
@@ -2876,14 +2893,13 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** (curPos = fetch_next_line(TRUE, FALSE, extraSpace))) { TRACE("Need to read more data as outstanding brackets or carets\n"); - acceptCommand = TRUE; } else break; }
/* Certain commands need special handling */ if (curStringLen == 0 && curCopyTo == curString) { - if (acceptCommand && !*(curPos = WCMD_strip_for_command_start(curPos))) continue; + if (lexer_at_command_start(&builder) && !*(curPos = WCMD_strip_for_command_start(curPos))) continue; /* If command starts with 'rem ' or identifies a label, use whole line */ if (WCMD_keyword_ws_found(L"rem", curPos) || *curPos == L':') { size_t line_len = wcslen(curPos); @@ -2904,8 +2920,7 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** should suffice for now. To be able to handle ('s in the condition part take as much as evaluate_if_condition would take and skip parsing it here. */ - acceptCommand = FALSE; - } else if (acceptCommand && WCMD_keyword_ws_found(L"if", curPos)) { + } else if (lexer_at_command_start(&builder) && WCMD_keyword_ws_found(L"if", curPos)) { WCHAR *command;
node_builder_push_token(&builder, TKN_IF); @@ -2926,10 +2941,8 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** &curCopyTo, &curLen);
} - acceptCommand = TRUE; continue; } else if (WCMD_keyword_ws_found(L"else", curPos)) { - acceptCommand = TRUE; node_builder_push_token(&builder, TKN_ELSE);
curPos = WCMD_skip_leading_spaces(curPos + 4 /* else */); @@ -2941,7 +2954,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** } else if (lexer_can_accept_do(&builder) && WCMD_keyword_ws_found(L"do", curPos)) {
WINE_TRACE("Found 'DO '\n"); - acceptCommand = TRUE;
node_builder_push_token(&builder, TKN_DO); curPos = WCMD_skip_leading_spaces(curPos + 2 /* do */); @@ -3027,7 +3039,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** } else { node_builder_push_token(&builder, TKN_BAR); } - acceptCommand = TRUE; break;
case L'"': @@ -3053,10 +3064,9 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** In an ELSE statement, only allow it straight away after the ELSE and whitespace */ - if ((acceptCommand || node_builder_top(&builder, 0) == TKN_IN) && + if ((lexer_at_command_start(&builder) || node_builder_top(&builder, 0) == TKN_IN) && lexer_white_space_only(curString, curStringLen)) { node_builder_push_token(&builder, TKN_OPENPAR); - acceptCommand = TRUE; } else { curCopyTo[(*curLen)++] = *curPos; } @@ -3096,7 +3106,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** } else { node_builder_push_token(&builder, TKN_AMP); } - acceptCommand = TRUE; break;
case L')': @@ -3108,7 +3117,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** curRedirs, &curRedirsLen, &curCopyTo, &curLen); node_builder_push_token(&builder, TKN_CLOSEPAR); - acceptCommand = FALSE; } else { curCopyTo[(*curLen)++] = *curPos; }
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/wcmdmain.c | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-)
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 0fc572adf24..ed9da89918d 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -2840,7 +2840,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** WCHAR *curCopyTo; int *curLen; static WCHAR *extraSpace = NULL; /* Deliberately never freed */ - BOOL lastWasRedirect = TRUE; struct node_builder builder; BOOL ret;
@@ -2864,7 +2863,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** curRedirsLen = 0; curCopyTo = curString; curLen = &curStringLen; - lastWasRedirect = FALSE; /* Required e.g. for spaces between > and filename */
curPos = WCMD_strip_for_command_start(curPos); /* Parse every character on the line being processed */ @@ -2984,19 +2982,14 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** case L',': /* drop through - ignore token delimiters at the start of a command */ case L'\t':/* drop through - ignore token delimiters at the start of a command */ case L' ': - /* If a redirect in place, it ends here */ - if (!lastWasRedirect) { - - /* If finishing off a redirect, add a whitespace delimiter */ - if (curCopyTo == curRedirs) { - curCopyTo[(*curLen)++] = L' '; - } + /* If finishing off a redirect, add a whitespace delimiter */ + if (curCopyTo == curRedirs) { + curCopyTo[(*curLen)++] = L' '; curCopyTo = curString; curLen = &curStringLen; } - if (*curLen > 0) { + if (*curLen > 0) curCopyTo[(*curLen)++] = *curPos; - } break;
case L'>': /* drop through - handle redirect chars the same */ @@ -3004,7 +2997,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** /* Make a redirect start here */ curCopyTo = curRedirs; curLen = &curRedirsLen; - lastWasRedirect = TRUE;
/* See if 1>, 2> etc, in which case we have some patching up to do (provided there's a preceding whitespace, and enough @@ -3013,22 +3005,27 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** { curStringLen--; curString[curStringLen] = L'\0'; - curCopyTo[(*curLen)++] = *(curPos-1); + curCopyTo[(*curLen)++] = curPos[-1]; }
curCopyTo[(*curLen)++] = *curPos;
/* If a redirect is immediately followed by '&' (ie. 2>&1) then do not process that ampersand as an AND operator */ - if ((*curPos == L'>' || *curPos == L'<') && curPos[1] == L'&') { - curCopyTo[(*curLen)++] = *(curPos+1); + if ((*curPos == L'>' || *curPos == L'<') && curPos[1] == L'&') + { + curCopyTo[(*curLen)++] = curPos[1]; + curPos++; + } + /* advance until start of filename */ + while (iswspace(curPos[1]) || curPos[1] == L',' || curPos[1] == L'=') + { + curCopyTo[(*curLen)++] = curPos[1]; curPos++; } break;
case L'|': /* Pipe character only if not || */ - lastWasRedirect = FALSE; - lexer_push_command(&builder, curString, &curStringLen, curRedirs, &curRedirsLen, &curCopyTo, &curLen); @@ -3049,13 +3046,11 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** curCopyTo[(*curLen)++] = *++curPos; if (*curPos == L'"') break; } - lastWasRedirect = FALSE; break;
case L'(': /* If a '(' is the first non whitespace in a command portion ie start of line or just after &&, then we read until an unquoted ) is found */ - lastWasRedirect = FALSE;
/* In a FOR loop, an unquoted '(' may occur straight after IN or DO @@ -3093,8 +3088,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** break;
case L'&': - lastWasRedirect = FALSE; - /* Add an entry to the command list */ lexer_push_command(&builder, curString, &curStringLen, curRedirs, &curRedirsLen, @@ -3110,8 +3103,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE **
case L')': if (builder.opened_parenthesis > 0) { - lastWasRedirect = FALSE; - /* Add the current command if there is one */ lexer_push_command(&builder, curString, &curStringLen, curRedirs, &curRedirsLen, @@ -3122,7 +3113,6 @@ enum read_parse_line WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_NODE ** } break; default: - lastWasRedirect = FALSE; curCopyTo[(*curLen)++] = *curPos; }
From: Eric Pouech epouech@codeweavers.com
Likely regression introduced by 86f3e21d659b3c94eccc42353467cbdbbbf80eeb. FOR /L %v in () DO ... should execute as an infinite loop.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/wcmdmain.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index ed9da89918d..84d3f52970e 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -3614,8 +3614,13 @@ static RETURN_CODE for_control_execute_numbers(CMD_FOR_CONTROL *for_ctrl, CMD_NO int numbers[3] = {0, 0, 0}, var; int i;
- wcscpy(set, for_ctrl->set); - handleExpansion(set, TRUE); + if (for_ctrl->set) + { + wcscpy(set, for_ctrl->set); + handleExpansion(set, TRUE); + } + else + set[0] = L'\0';
/* Note: native doesn't check the actual number of parameters, and set * them by default to 0. @@ -3648,7 +3653,7 @@ static RETURN_CODE for_control_execute(CMD_FOR_CONTROL *for_ctrl, CMD_NODE *node { RETURN_CODE return_code;
- if (!for_ctrl->set) return NO_ERROR; + if (!for_ctrl->set && for_ctrl->operator != CMD_FOR_NUMBERS) return NO_ERROR;
WCMD_save_for_loop_context(FALSE);