Eric Pouech : cmd: Implement timeout support in CHOICE command.
Module: wine Branch: master Commit: 787fb63720a4ecedd3818b281ceb036520897dde URL: https://gitlab.winehq.org/wine/wine/-/commit/787fb63720a4ecedd3818b281ceb036... Author: Eric Pouech <epouech(a)codeweavers.com> Date: Sat Jul 13 11:09:36 2024 +0200 cmd: Implement timeout support in CHOICE command. Signed-off-by: Eric Pouech <epouech(a)codeweavers.com> --- programs/cmd/builtins.c | 93 ++++++++++++++++++++------------ programs/cmd/tests/test_builtins.cmd.exp | 24 ++++----- 2 files changed, 70 insertions(+), 47 deletions(-) diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index d2071a17d3c..2654ad750fa 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -290,7 +290,6 @@ RETURN_CODE WCMD_choice(WCHAR *args) WCHAR opt_default = 0; DWORD opt_timeout = -1; WCHAR *end; - DWORD count; DWORD oldmode; BOOL have_console; BOOL opt_n = FALSE; @@ -370,39 +369,24 @@ RETURN_CODE WCMD_choice(WCHAR *args) (opt_timeout != -1 && opt_timeout > 9999)) { WCMD_output_stderr(WCMD_LoadMessage(WCMD_ARGERR)); - if (return_code == NO_ERROR) return_code = ERROR_INVALID_FUNCTION; + errorlevel = 255; if (opt_c != buffer) free(opt_c); free(opt_m); - return errorlevel = return_code; - } - if (opt_timeout != -1) - { - WINE_FIXME("timeout not supported: %c,%ld\n", opt_default, opt_timeout); - return errorlevel = ERROR_INVALID_FUNCTION; + return ERROR_INVALID_FUNCTION; } + have_console = GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &oldmode); if (have_console) SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), 0); - /* use default keys, when needed: localized versions of "Y"es and "No" */ - if (!opt_c) - { - LoadStringW(hinst, WCMD_YES, buffer, ARRAY_SIZE(buffer)); - LoadStringW(hinst, WCMD_NO, buffer + 1, ARRAY_SIZE(buffer) - 1); - opt_c = buffer; - buffer[2] = L'\0'; - } - /* print the question, when needed */ if (opt_m) WCMD_output_asis(opt_m); - if (!opt_cs) - wcsupr(opt_c); - if (!opt_n) { /* print a list of all allowed answers inside brackets */ + if (opt_m) WCMD_output_asis(L" "); WCMD_output_asis(L"["); answer[1] = L'\0'; for (ptr = opt_c; *ptr; ptr++) @@ -415,41 +399,80 @@ RETURN_CODE WCMD_choice(WCHAR *args) WCMD_output_asis(L"]?"); } - while (TRUE) + while (return_code == NO_ERROR) { - /* FIXME: Add support for option /T */ - answer[1] = 0; /* terminate single character string */ - if (!WCMD_ReadFile(GetStdHandle(STD_INPUT_HANDLE), answer, 1, &count) || !count) + if (opt_timeout == 0) + answer[0] = opt_default; + else + { + LARGE_INTEGER li, zeroli = {0}; + OVERLAPPED overlapped = {0}; + DWORD count; + + overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + if (SetFilePointerEx(GetStdHandle(STD_INPUT_HANDLE), zeroli, &li, FILE_CURRENT)) + { + overlapped.Offset = li.LowPart; + overlapped.OffsetHigh = li.HighPart; + } + if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), answer, 1, NULL, &overlapped)) + { + switch (WaitForSingleObject(overlapped.hEvent, opt_timeout == -1 ? INFINITE : opt_timeout * 1000)) + { + case WAIT_OBJECT_0: + break; + case WAIT_TIMEOUT: + answer[0] = opt_default; + break; + default: + return_code = ERROR_INVALID_FUNCTION; + } + } + else if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), answer, 1, &count, NULL)) + { + if (count == 0) + { + if (opt_timeout != -1) + answer[0] = opt_default; + else + return_code = ERROR_INVALID_FUNCTION; + } + } + else + return_code = ERROR_INVALID_FUNCTION; + CloseHandle(overlapped.hEvent); + } + if (return_code != NO_ERROR) { - /* FIXME: is this choice 1 or ERROR_INVALID_FUNCTION? */ - return_code = 1; + errorlevel = 255; break; } - if (!opt_cs) answer[0] = towupper(answer[0]); + answer[1] = L'\0'; /* terminate single character string */ ptr = wcschr(opt_c, answer[0]); - if (ptr) { + if (ptr) + { WCMD_output_asis(answer); WCMD_output_asis(L"\r\n"); - if (have_console) - SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), oldmode); - return_code = (ptr - opt_c) + 1; - TRACE("answer: %d\n", errorlevel); - break; + return_code = errorlevel = (ptr - opt_c) + 1; + TRACE("answer: %d\n", return_code); } else { /* key not allowed: play the bell */ - WINE_TRACE("key not allowed: %s\n", wine_dbgstr_w(answer)); + TRACE("key not allowed: %s\n", wine_dbgstr_w(answer)); WCMD_output_asis(L"\a"); } } + if (have_console) + SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), oldmode); + if (opt_c != buffer) free(opt_c); free(opt_m); - return errorlevel = return_code; + return return_code; } /**************************************************************************** diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp index 5d9629e35a9..03bcb674bdb 100644 --- a/programs/cmd/tests/test_builtins.cmd.exp +++ b/programs/cmd/tests/test_builtins.cmd.exp @@ -707,19 +707,19 @@ I'm here!@space@ I'm here!@space@ I'm here!@space@ ------------ Testing 'choice' ------------ -(a)todo_wine@Example message [A,B,C]?A(a)or_broken@choice unavailable +Example message [A,B,C]?A(a)or_broken@choice unavailable 1(a)or_broken@9009 -(a)todo_wine@Example message [A,B,C]?B(a)or_broken@choice unavailable -(a)todo_wine@2(a)or_broken@9009 -(a)todo_wine@[D,E,F]?F(a)or_broken@choice unavailable -(a)todo_wine@3(a)or_broken@9009 -(a)todo_wine@[A,B,C,X,Y,Z]?Y(a)or_broken@choice unavailable -(a)todo_wine@5(a)or_broken@9009 -(a)todo_wine@A(a)or_broken@choice unavailable -(a)todo_wine@1(a)or_broken@9009 -(a)todo_wine@[a,b,c,A,B,C]?A(a)or_broken@choice unavailable -(a)todo_wine@4(a)or_broken@9009 -(a)todo_wine@255(a)or_broken@9009 +Example message [A,B,C]?B(a)or_broken@choice unavailable +2(a)or_broken@9009 +[D,E,F]?F(a)or_broken@choice unavailable +3(a)or_broken@9009 +[A,B,C,X,Y,Z]?Y(a)or_broken@choice unavailable +5(a)or_broken@9009 +A(a)or_broken@choice unavailable +1(a)or_broken@9009 +[a,b,c,A,B,C]?A(a)or_broken@choice unavailable +4(a)or_broken@9009 +255(a)or_broken@9009 ------------ Testing variable expansion ------------ ~p0 should be path containing batch file @path@
participants (1)
-
Alexandre Julliard