From 58d21b3319f719b4d0b6972a801b5f81993d5c10 Mon Sep 17 00:00:00 2001 From: Jason Edmeades Date: Mon, 27 Aug 2018 20:41:50 +0100 Subject: [PATCH] cmd: Handle single line 'if' as nested if or with redirects. A single line if statement causes problems when it has redirects and/or continuation type operators (|, &&, || etc) because it is expected that if there is more than one command in the 'if', then it will use brackets. This patch changes the 'if' parsing to emulate brackets at a continuation character. In addition, 'for' and 'if' statements do not have their output redirected immediately, instead it is redirected on the individual commands being executed not the statement itself. We were opening the redirect once for the 'if' and once for the processing of the statement inside the if. Signed-off-by: Jason Edmeades Signed-off-by: Alexandre Julliard --- programs/cmd/builtins.c | 16 +- programs/cmd/tests/test_builtins.cmd | 9 + programs/cmd/tests/test_builtins.cmd.exp | 7 +- programs/cmd/wcmdmain.c | 313 +++++++++++++---------- 4 files changed, 202 insertions(+), 143 deletions(-) diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index 1da61556d9b..5026f9c1a58 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -1544,8 +1544,8 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd, CMD_LIST *curPosition = *cmdList; int myDepth = (*cmdList)->bracketDepth; - WINE_TRACE("cmdList(%p), firstCmd(%s), doIt(%d)\n", cmdList, wine_dbgstr_w(firstcmd), - executecmds); + WINE_TRACE("cmdList(%p), firstCmd(%s), doIt(%d), isIF(%d)\n", cmdList, + wine_dbgstr_w(firstcmd), executecmds, isIF); /* Skip leading whitespace between condition and the command */ while (firstcmd && *firstcmd && (*firstcmd==' ' || *firstcmd=='\t')) firstcmd++; @@ -1592,7 +1592,8 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd, } else if ((*cmdList)->bracketDepth > myDepth) { if (processThese) { *cmdList = WCMD_process_commands(*cmdList, TRUE, FALSE); - WINE_TRACE("Back from processing commands, (next = %p)\n", *cmdList); + } else { + WINE_TRACE("Skipping command %p due to stack depth\n", *cmdList); } if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand; @@ -1626,9 +1627,16 @@ static void WCMD_part_execute(CMD_LIST **cmdList, const WCHAR *firstcmd, processThese = TRUE; } if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand; + + /* If we were in an IF statement and we didnt find an else and yet we get back to + the same bracket depth as the IF, then the IF statement is over. This is required + to handle nested ifs properly */ + } else if (isIF && (*cmdList)->bracketDepth == myDepth) { + WINE_TRACE("Found end of this nested IF statement, ending this if\n"); + break; } else if (!processThese) { if (curPosition == *cmdList) *cmdList = (*cmdList)->nextcommand; - WINE_TRACE("Ignore the next command as well (next = %p)\n", *cmdList); + WINE_TRACE("Skipping this command, as in not process mode (next = %p)\n", *cmdList); } else { WINE_TRACE("Found end of this IF statement (next = %p)\n", *cmdList); break; diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd index 775f21bbdc8..0738f2da6eb 100644 --- a/programs/cmd/tests/test_builtins.cmd +++ b/programs/cmd/tests/test_builtins.cmd @@ -179,6 +179,8 @@ if exist foo (type foo) else echo not supported echo --- redirections within IF statements if 1==1 echo foo1>bar type bar & del bar +if 1==1 echo foo2>>bar +type bar & del bar echo ----- if 1==1 (echo foo2>bar) else echo baz2>bar type bar & del bar @@ -925,6 +927,13 @@ if %elseIF% == 1 ( ) else ( echo else if seems to be broken ) +if "x" == "a" ( + echo broken1 +) else ( + echo expected1 + if "y" == "b" echo broken2 + echo expected post-embedded if +) echo --- case sensitivity with and without /i option if bar==BAR echo if does not default to case sensitivity if not bar==BAR echo if seems to default to case sensitivity diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp index 35e0cf2fa5d..7ec83d7acb0 100644 --- a/programs/cmd/tests/test_builtins.cmd.exp +++ b/programs/cmd/tests/test_builtins.cmd.exp @@ -205,7 +205,8 @@ food21 @todo_wine@foo7@space@@space@@or_broken@not supported@space@ @todo_wine@foo@or_broken@not supported --- redirections within IF statements -@todo_wine@foo1 +foo1 +foo2 ----- foo2 foo3 @@ -430,7 +431,7 @@ p1 q1 @todo_wine@--- --- chain else (if false) -@todo_wine@j3 +j3 --- k3 l3 @@ -661,6 +662,8 @@ if seems not to detect /c as parameter else if seems to work else if seems to work else if seems to work +expected1 +expected post-embedded if --- case sensitivity with and without /i option if seems to default to case sensitivity if /i seems to work diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index b269635c75d..7a7ee16f7d6 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -1277,8 +1277,9 @@ void WCMD_run_program (WCHAR *command, BOOL called) void WCMD_execute (const WCHAR *command, const WCHAR *redirects, CMD_LIST **cmdList, BOOL retrycall) { - WCHAR *cmd, *p, *redir; - int status, i; + WCHAR *cmd, *parms_start, *redir; + WCHAR *pos; + int status, i, cmd_index; DWORD count, creationDisposition; HANDLE h; WCHAR *whichcmd; @@ -1296,13 +1297,42 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, WINE_TRACE("command on entry:%s (%p)\n", wine_dbgstr_w(command), cmdList); + /* Move copy of the command onto the heap so it can be expanded */ + new_cmd = heap_alloc(MAXSTRING * sizeof(WCHAR)); + strcpyW(new_cmd, command); + cmd = new_cmd; + + /* Move copy of the redirects onto the heap so it can be expanded */ + new_redir = heap_alloc(MAXSTRING * sizeof(WCHAR)); + redir = new_redir; + + /* Strip leading whitespaces, and a '@' if supplied */ + whichcmd = WCMD_skip_leading_spaces(cmd); + WINE_TRACE("Command: '%s'\n", wine_dbgstr_w(cmd)); + if (whichcmd[0] == '@') whichcmd++; + + /* Check if the command entered is internal, and identify which one */ + count = 0; + while (IsCharAlphaNumericW(whichcmd[count])) { + count++; + } + for (i=0; i<=WCMD_EXIT; i++) { + if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, + whichcmd, count, inbuilt[i], -1) == CSTR_EQUAL) break; + } + cmd_index = i; + parms_start = WCMD_skip_leading_spaces (&whichcmd[count]); + /* If the next command is a pipe then we implement pipes by redirecting the output from this command to a temp file and input into the next command from that temp file. + Note: Do not do this for a for or if statement as the pipe is for + the individual statements, not the for or if itself. FIXME: Use of named pipes would make more sense here as currently this process has to finish before the next one can start but this requires a change to not wait for the first app to finish but rather the pipe */ - if (cmdList && (*cmdList)->nextcommand && + if (!(cmd_index == WCMD_FOR || cmd_index == WCMD_IF) && + cmdList && (*cmdList)->nextcommand && (*cmdList)->nextcommand->prevDelim == CMD_PIPE) { WCHAR temp_path[MAX_PATH]; @@ -1319,13 +1349,6 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, wine_dbgstr_w((*cmdList)->nextcommand->pipeFile)); } - /* Move copy of the command onto the heap so it can be expanded */ - new_cmd = heap_alloc(MAXSTRING * sizeof(WCHAR)); - strcpyW(new_cmd, command); - - /* Move copy of the redirects onto the heap so it can be expanded */ - new_redir = heap_alloc(MAXSTRING * sizeof(WCHAR)); - /* If piped output, send stdout to the pipe by appending >filename to redirects */ if (piped) { static const WCHAR redirOut[] = {'%','s',' ','>',' ','%','s','\0'}; @@ -1339,7 +1362,6 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, be expanded as the line is read in, except for 'for' loops) */ handleExpansion(new_cmd, (context != NULL), delayedsubst); handleExpansion(new_redir, (context != NULL), delayedsubst); - cmd = new_cmd; /* * Changing default drive has to be handled as a special case, anything @@ -1376,16 +1398,33 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; -/* - * Redirect stdin, stdout and/or stderr if required. - */ + /* + * Redirect stdin, stdout and/or stderr if required. + * Note: Do not do this for a for or if statement as the pipe is for + * the individual statements, not the for or if itself. + */ + if (!(cmd_index == WCMD_FOR || cmd_index == WCMD_IF)) { + /* STDIN could come from a preceding pipe, so delete on close if it does */ + if (cmdList && (*cmdList)->pipeFile[0] != 0x00) { + WINE_TRACE("Input coming from %s\n", wine_dbgstr_w((*cmdList)->pipeFile)); + h = CreateFileW((*cmdList)->pipeFile, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL); + if (h == INVALID_HANDLE_VALUE) { + WCMD_print_error (); + heap_free(cmd); + heap_free(new_redir); + return; + } + SetStdHandle (STD_INPUT_HANDLE, h); - /* STDIN could come from a preceding pipe, so delete on close if it does */ - if (cmdList && (*cmdList)->pipeFile[0] != 0x00) { - WINE_TRACE("Input coming from %s\n", wine_dbgstr_w((*cmdList)->pipeFile)); - h = CreateFileW((*cmdList)->pipeFile, GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL); + /* No need to remember the temporary name any longer once opened */ + (*cmdList)->pipeFile[0] = 0x00; + + /* Otherwise STDIN could come from a '<' redirect */ + } else if ((pos = strchrW(new_redir,'<')) != NULL) { + h = CreateFileW(WCMD_parameter(++pos, 0, NULL, FALSE, FALSE), GENERIC_READ, FILE_SHARE_READ, + &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { WCMD_print_error (); heap_free(cmd); @@ -1393,122 +1432,87 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, return; } SetStdHandle (STD_INPUT_HANDLE, h); - - /* No need to remember the temporary name any longer once opened */ - (*cmdList)->pipeFile[0] = 0x00; - - /* Otherwise STDIN could come from a '<' redirect */ - } else if ((p = strchrW(new_redir,'<')) != NULL) { - h = CreateFileW(WCMD_parameter(++p, 0, NULL, FALSE, FALSE), GENERIC_READ, FILE_SHARE_READ, - &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) { - WCMD_print_error (); - heap_free(cmd); - heap_free(new_redir); - return; - } - SetStdHandle (STD_INPUT_HANDLE, h); - } - - /* Scan the whole command looking for > and 2> */ - redir = new_redir; - while (redir != NULL && ((p = strchrW(redir,'>')) != NULL)) { - int handle = 0; - - if (p > redir && (*(p-1)=='2')) - handle = 2; - else - handle = 1; - - p++; - if ('>' == *p) { - creationDisposition = OPEN_ALWAYS; - p++; - } - else { - creationDisposition = CREATE_ALWAYS; } - /* Add support for 2>&1 */ - redir = p; - if (*p == '&') { - int idx = *(p+1) - '0'; + /* Scan the whole command looking for > and 2> */ + while (redir != NULL && ((pos = strchrW(redir,'>')) != NULL)) { + int handle = 0; - if (DuplicateHandle(GetCurrentProcess(), - GetStdHandle(idx_stdhandles[idx]), - GetCurrentProcess(), - &h, - 0, TRUE, DUPLICATE_SAME_ACCESS) == 0) { - WINE_FIXME("Duplicating handle failed with gle %d\n", GetLastError()); + if (pos > redir && (*(pos-1)=='2')) + handle = 2; + else + handle = 1; + + pos++; + if ('>' == *pos) { + creationDisposition = OPEN_ALWAYS; + pos++; + } + else { + creationDisposition = CREATE_ALWAYS; } - WINE_TRACE("Redirect %d (%p) to %d (%p)\n", handle, GetStdHandle(idx_stdhandles[idx]), idx, h); - } else { - WCHAR *param = WCMD_parameter(p, 0, NULL, FALSE, FALSE); - h = CreateFileW(param, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, - &sa, creationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) { - WCMD_print_error (); - heap_free(cmd); - heap_free(new_redir); - return; + /* Add support for 2>&1 */ + redir = pos; + if (*pos == '&') { + int idx = *(pos+1) - '0'; + + if (DuplicateHandle(GetCurrentProcess(), + GetStdHandle(idx_stdhandles[idx]), + GetCurrentProcess(), + &h, + 0, TRUE, DUPLICATE_SAME_ACCESS) == 0) { + WINE_FIXME("Duplicating handle failed with gle %d\n", GetLastError()); + } + WINE_TRACE("Redirect %d (%p) to %d (%p)\n", handle, GetStdHandle(idx_stdhandles[idx]), idx, h); + + } else { + WCHAR *param = WCMD_parameter(pos, 0, NULL, FALSE, FALSE); + h = CreateFileW(param, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, + &sa, creationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) { + WCMD_print_error (); + heap_free(cmd); + heap_free(new_redir); + return; + } + if (SetFilePointer (h, 0, NULL, FILE_END) == + INVALID_SET_FILE_POINTER) { + WCMD_print_error (); + } + WINE_TRACE("Redirect %d to '%s' (%p)\n", handle, wine_dbgstr_w(param), h); } - if (SetFilePointer (h, 0, NULL, FILE_END) == - INVALID_SET_FILE_POINTER) { - WCMD_print_error (); - } - WINE_TRACE("Redirect %d to '%s' (%p)\n", handle, wine_dbgstr_w(param), h); + + SetStdHandle (idx_stdhandles[handle], h); } - - SetStdHandle (idx_stdhandles[handle], h); + } else { + WINE_TRACE("Not touching redirects for a FOR or IF command\n"); } - -/* - * Strip leading whitespaces, and a '@' if supplied - */ - whichcmd = WCMD_skip_leading_spaces(cmd); - WINE_TRACE("Command: '%s'\n", wine_dbgstr_w(cmd)); - if (whichcmd[0] == '@') whichcmd++; - -/* - * Check if the command entered is internal. If it is, pass the rest of the - * line down to the command. If not try to run a program. - */ - - count = 0; - while (IsCharAlphaNumericW(whichcmd[count])) { - count++; - } - for (i=0; i<=WCMD_EXIT; i++) { - if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, - whichcmd, count, inbuilt[i], -1) == CSTR_EQUAL) break; - } - p = WCMD_skip_leading_spaces (&whichcmd[count]); - WCMD_parse (p, quals, param1, param2); + WCMD_parse (parms_start, quals, param1, param2); WINE_TRACE("param1: %s, param2: %s\n", wine_dbgstr_w(param1), wine_dbgstr_w(param2)); - if (i <= WCMD_EXIT && (p[0] == '/') && (p[1] == '?')) { + if (i <= WCMD_EXIT && (parms_start[0] == '/') && (parms_start[1] == '?')) { /* this is a help request for a builtin program */ i = WCMD_HELP; - memcpy(p, whichcmd, count * sizeof(WCHAR)); - p[count] = '\0'; + memcpy(parms_start, whichcmd, count * sizeof(WCHAR)); + parms_start[count] = '\0'; } switch (i) { case WCMD_CALL: - WCMD_call (p); + WCMD_call (parms_start); break; case WCMD_CD: case WCMD_CHDIR: - WCMD_setshow_default (p); + WCMD_setshow_default (parms_start); break; case WCMD_CLS: WCMD_clear_screen (); break; case WCMD_COPY: - WCMD_copy (p); + WCMD_copy (parms_start); break; case WCMD_CTTY: WCMD_change_tty (); @@ -1518,10 +1522,10 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, break; case WCMD_DEL: case WCMD_ERASE: - WCMD_delete (p); + WCMD_delete (parms_start); break; case WCMD_DIR: - WCMD_directory (p); + WCMD_directory (parms_start); break; case WCMD_ECHO: WCMD_echo(&whichcmd[count]); @@ -1530,20 +1534,20 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, WCMD_goto (cmdList); break; case WCMD_HELP: - WCMD_give_help (p); - break; + WCMD_give_help (parms_start); + break; case WCMD_LABEL: - WCMD_volume (TRUE, p); + WCMD_volume (TRUE, parms_start); break; case WCMD_MD: case WCMD_MKDIR: - WCMD_create_dir (p); - break; + WCMD_create_dir (parms_start); + break; case WCMD_MOVE: WCMD_move (); break; case WCMD_PATH: - WCMD_setshow_path (p); + WCMD_setshow_path (parms_start); break; case WCMD_PAUSE: WCMD_pause (); @@ -1559,22 +1563,22 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, break; case WCMD_RD: case WCMD_RMDIR: - WCMD_remove_dir (p); + WCMD_remove_dir (parms_start); break; case WCMD_SETLOCAL: - WCMD_setlocal(p); + WCMD_setlocal(parms_start); break; case WCMD_ENDLOCAL: WCMD_endlocal(); break; case WCMD_SET: - WCMD_setshow_env (p); - break; + WCMD_setshow_env (parms_start); + break; case WCMD_SHIFT: - WCMD_shift (p); + WCMD_shift (parms_start); break; case WCMD_START: - WCMD_start (p); + WCMD_start (parms_start); break; case WCMD_TIME: WCMD_setshow_time (); @@ -1584,41 +1588,41 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, WCMD_title(&whichcmd[count+1]); break; case WCMD_TYPE: - WCMD_type (p); - break; + WCMD_type (parms_start); + break; case WCMD_VER: WCMD_output_asis(newlineW); WCMD_version (); break; case WCMD_VERIFY: - WCMD_verify (p); + WCMD_verify (parms_start); break; case WCMD_VOL: - WCMD_volume (FALSE, p); + WCMD_volume (FALSE, parms_start); break; case WCMD_PUSHD: - WCMD_pushd(p); + WCMD_pushd(parms_start); break; case WCMD_POPD: WCMD_popd(); break; case WCMD_ASSOC: - WCMD_assoc(p, TRUE); + WCMD_assoc(parms_start, TRUE); break; case WCMD_COLOR: WCMD_color(); break; case WCMD_FTYPE: - WCMD_assoc(p, FALSE); + WCMD_assoc(parms_start, FALSE); break; case WCMD_MORE: - WCMD_more(p); + WCMD_more(parms_start); break; case WCMD_CHOICE: - WCMD_choice(p); + WCMD_choice(parms_start); break; case WCMD_MKLINK: - WCMD_mklink(p); + WCMD_mklink(parms_start); break; case WCMD_EXIT: WCMD_exit (cmdList); @@ -1629,8 +1633,8 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects, 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); + if (i==WCMD_FOR) WCMD_for (parms_start, cmdList); + else if (i==WCMD_IF) WCMD_if (parms_start, cmdList); break; } /* else: drop through */ @@ -1838,6 +1842,8 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE BOOL lastWasElse = FALSE; BOOL lastWasRedirect = TRUE; BOOL lastWasCaret = FALSE; + int lineCurDepth; /* Bracket depth when line was read in */ + BOOL resetAtEndOfLine = FALSE; /* Do we need to reset curdepth at EOL */ /* Allocate working space for a command read from keyboard, file etc */ if (!extraSpace) @@ -1905,6 +1911,7 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE curCopyTo = curString; curLen = &curStringLen; lastWasRedirect = FALSE; /* Required e.g. for spaces between > and filename */ + lineCurDepth = curDepth; /* What was the curdepth at the beginning of the line */ /* Parse every character on the line being processed */ while (*curPos != 0x00) { @@ -1950,6 +1957,15 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE memcpy(&curCopyTo[*curLen], curPos, keyw_len*sizeof(WCHAR)); (*curLen)+=keyw_len; curPos+=keyw_len; + + /* If we had a single line if XXX which reaches an else (needs odd + syntax like if 1=1 command && (command) else command we pretended + to add brackets for the if, so they are now over */ + if (resetAtEndOfLine) { + WINE_TRACE("Resetting curdepth at end of line to %d\n", lineCurDepth); + resetAtEndOfLine = FALSE; + curDepth = lineCurDepth; + } continue; /* In a for loop, the DO command will follow a close bracket followed by @@ -2073,6 +2089,14 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE } else { prevDelim = CMD_PIPE; } + + /* If in an IF or ELSE statement, put subsequent chained + commands at a higher depth as if brackets were supplied + but remember to reset to the original depth at EOL */ + if ((inIf || inElse) && curDepth == lineCurDepth) { + curDepth++; + resetAtEndOfLine = TRUE; + } } else { curCopyTo[(*curLen)++] = *curPos; } @@ -2170,6 +2194,13 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE } else { prevDelim = CMD_NONE; } + /* If in an IF or ELSE statement, put subsequent chained + commands at a higher depth as if brackets were supplied + but remember to reset to the original depth at EOL */ + if ((inIf || inElse) && curDepth == lineCurDepth) { + curDepth++; + resetAtEndOfLine = TRUE; + } } else { curCopyTo[(*curLen)++] = *curPos; } @@ -2232,7 +2263,15 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE &curCopyTo, &curLen, prevDelim, curDepth, &lastEntry, output); - } + + /* If we had a single line if or else, and we pretended to add + brackets, end them now */ + if (resetAtEndOfLine) { + WINE_TRACE("Resetting curdepth at end of line to %d\n", lineCurDepth); + resetAtEndOfLine = FALSE; + curDepth = lineCurDepth; + } + } /* If we have reached the end of the string, see if bracketing or final caret is outstanding */