From: Myah Caron qsniyg@protonmail.com
Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=56068 Signed-off-by: Myah Caron qsniyg@protonmail.com --- configure.ac | 1 + programs/timeout/Makefile.in | 6 + programs/timeout/timeout_main.c | 266 ++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 programs/timeout/Makefile.in create mode 100644 programs/timeout/timeout_main.c
diff --git a/configure.ac b/configure.ac index 3f54230b46b..3ae541232ca 100644 --- a/configure.ac +++ b/configure.ac @@ -3523,6 +3523,7 @@ WINE_CONFIG_MAKEFILE(programs/tasklist) WINE_CONFIG_MAKEFILE(programs/tasklist/tests) WINE_CONFIG_MAKEFILE(programs/taskmgr) WINE_CONFIG_MAKEFILE(programs/termsv) +WINE_CONFIG_MAKEFILE(programs/timeout) WINE_CONFIG_MAKEFILE(programs/uninstaller) WINE_CONFIG_MAKEFILE(programs/unlodctr) WINE_CONFIG_MAKEFILE(programs/view) diff --git a/programs/timeout/Makefile.in b/programs/timeout/Makefile.in new file mode 100644 index 00000000000..4502a291175 --- /dev/null +++ b/programs/timeout/Makefile.in @@ -0,0 +1,6 @@ +MODULE = timeout.exe + +EXTRADLLFLAGS = -mconsole + +SOURCES = \ + timeout_main.c diff --git a/programs/timeout/timeout_main.c b/programs/timeout/timeout_main.c new file mode 100644 index 00000000000..f9b4d3668cb --- /dev/null +++ b/programs/timeout/timeout_main.c @@ -0,0 +1,266 @@ +/* + * timeout program + * + * Copyright (C) 2024 Myah Caron + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <conio.h> +#include <math.h> + +#include <windows.h> + +static void usage(void) +{ + printf("Usage: timeout [-t] seconds [-nobreak]\n\n" + "Options:\n" + " -t Timeout in seconds to wait.\n" + " -nobreak Ignore key presses.\n" + " -? Display this help message.\n"); +} + +static HANDLE get_stdin(void) +{ + static HANDLE hStdin = NULL; + + if (!hStdin) + hStdin = GetStdHandle(STD_INPUT_HANDLE); + + return hStdin; +} + +static BOOL is_piped(void) +{ + DWORD count = 0; + return !GetNumberOfConsoleInputEvents(get_stdin(), &count); +} + +static BOOL is_key_hit(void) +{ + INPUT_RECORD *records = NULL; + DWORD count = 0, i; + BOOL retval = FALSE; + + GetNumberOfConsoleInputEvents(get_stdin(), &count); + if (!count) + return FALSE; + + records = malloc(count * sizeof(INPUT_RECORD)); + if (!records) + return FALSE; + + if (!ReadConsoleInputA(get_stdin(), records, count, &count)) + return FALSE; + + for (i = 0; i < count; i++) + { + if (records[i].EventType == KEY_EVENT && + records[i].Event.KeyEvent.bKeyDown) + { + retval = TRUE; + break; + } + } + + free(records); + + return retval; +} + +static BOOL wait_for_keypress(DWORD timeout_millis) +{ + return WaitForSingleObject(get_stdin(), timeout_millis) == WAIT_OBJECT_0 && is_key_hit(); +} + +static void sleep_without_timeout(BOOL nobreak) +{ + if (!nobreak) + { + printf("Press any key to continue ..."); + + for (;;) + { + if (wait_for_keypress(INFINITE)) + break; + } + } + else + { + printf("Press CTRL+C to quit ..."); + + for (;;) + { + Sleep(10000); + } + } +} + +static void sleep_with_timeout(int timeout, BOOL nobreak) +{ + ULONGLONG start_ticks = GetTickCount64(); + ULONGLONG end_ticks = start_ticks + (timeout * 1000); + LONGLONG ticks_remaining, wait_millis; + + do + { + ticks_remaining = end_ticks - GetTickCount64(); + + wait_millis = ticks_remaining; + if (wait_millis > 1000) + wait_millis = 1000; + + printf("\rWaiting for %d seconds, ", (int)roundf(ticks_remaining / 1000.)); + + if (!nobreak) + { + printf("press a key to continue ... "); + + if (wait_millis > 0 && wait_for_keypress(wait_millis)) + break; + } + else + { + printf("press CTRL+C to quit ... "); + + if (wait_millis > 0) + Sleep(wait_millis); + } + } while (ticks_remaining > 0); +} + +static BOOL str_is_number(char* str) +{ + if (str[0] == '-') + str++; + + while (*str) + { + if (!isdigit(*str++)) + return FALSE; + } + + return TRUE; +} + +static BOOL check_timeout_arg(char* str, BOOL timeout_set) +{ + if (timeout_set) + { + printf("Timeout value cannot be specified more than once.\n"); + return FALSE; + } + + if (!str_is_number(str)) + { + printf("Invalid timeout: %s\n", str); + return FALSE; + } + + return TRUE; +} + +int __cdecl main(int argc, char** argv) +{ + int i, timeout = 0; + BOOL timeout_set = FALSE, nobreak = FALSE; + + if (argc == 1) + { + usage(); + return 1; + } + + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-' || argv[i][0] == '/') + { + if (!strcmp(argv[i] + 1, "t")) + { + if (i == argc - 1) + { + printf("Missing value for option %s\n", argv[i]); + exit(1); + } + + if (!check_timeout_arg(argv[++i], timeout_set)) + return 1; + + timeout = atoi(argv[i]); + timeout_set = TRUE; + } + else if (!strcmp(argv[i] + 1, "nobreak")) + { + nobreak = TRUE; + } + else if (!strcmp(argv[i] + 1, "?")) + { + usage(); + return 0; + } + else if (!strcmp(argv[i], "-1")) + { + timeout = -1; + timeout_set = TRUE; + } + else + { + printf("Invalid argument: %s\n", argv[i]); + usage(); + return 1; + } + } + else + { + if (!check_timeout_arg(argv[++i], timeout_set)) + return 1; + + timeout = atoi(argv[i]); + timeout_set = TRUE; + } + } + + if (!timeout_set) + { + usage(); + return 1; + } + + if (timeout < -1 || timeout > 99999) + { + printf("Timeout value out of range. Valid range is -1 to 99999.\n"); + return 1; + } + + if (is_piped()) + { + printf("Input redirection is not supported.\n"); + return 1; + } + + printf("\n"); + + if (timeout < 0) + sleep_without_timeout(nobreak); + else + sleep_with_timeout(timeout, nobreak); + + printf("\n"); + + return 0; +}