Author: hbelusca Date: Mon Sep 25 23:31:44 2017 New Revision: 75968
URL: http://svn.reactos.org/svn/reactos?rev=75968&view=rev Log: [TIMEOUT]: Implement the TIMEOUT utility (found on Win2k3 and upwards). This is an improved "pause" command, with elapsed time count display. Based from a patch by Lee Schröder, with modifications by myself. CORE-10044 #resolve
Added: trunk/reactos/base/applications/cmdutils/timeout/ trunk/reactos/base/applications/cmdutils/timeout/CMakeLists.txt (with props) trunk/reactos/base/applications/cmdutils/timeout/lang/ trunk/reactos/base/applications/cmdutils/timeout/lang/en-US.rc (with props) trunk/reactos/base/applications/cmdutils/timeout/lang/fr-FR.rc (with props) trunk/reactos/base/applications/cmdutils/timeout/resource.h (with props) trunk/reactos/base/applications/cmdutils/timeout/timeout.c (with props) trunk/reactos/base/applications/cmdutils/timeout/timeout.rc (with props) Modified: trunk/reactos/base/applications/cmdutils/CMakeLists.txt
Modified: trunk/reactos/base/applications/cmdutils/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/... ============================================================================== --- trunk/reactos/base/applications/cmdutils/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/base/applications/cmdutils/CMakeLists.txt [iso-8859-1] Mon Sep 25 23:31:44 2017 @@ -18,6 +18,7 @@ add_subdirectory(schtasks) add_subdirectory(sort) add_subdirectory(taskkill) +add_subdirectory(timeout) add_subdirectory(tree) add_subdirectory(whoami) add_subdirectory(wmic)
Added: trunk/reactos/base/applications/cmdutils/timeout/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/... ============================================================================== --- trunk/reactos/base/applications/cmdutils/timeout/CMakeLists.txt (added) +++ trunk/reactos/base/applications/cmdutils/timeout/CMakeLists.txt [iso-8859-1] Mon Sep 25 23:31:44 2017 @@ -0,0 +1,8 @@ + +include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils) + +add_executable(timeout timeout.c timeout.rc) +set_module_type(timeout win32cui UNICODE) +target_link_libraries(timeout conutils ${PSEH_LIB}) +add_importlibs(timeout msvcrt kernel32) +add_cd_file(TARGET timeout DESTINATION reactos/system32 FOR all)
Propchange: trunk/reactos/base/applications/cmdutils/timeout/CMakeLists.txt ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/base/applications/cmdutils/timeout/lang/en-US.rc URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/... ============================================================================== --- trunk/reactos/base/applications/cmdutils/timeout/lang/en-US.rc (added) +++ trunk/reactos/base/applications/cmdutils/timeout/lang/en-US.rc [iso-8859-1] Mon Sep 25 23:31:44 2017 @@ -0,0 +1,33 @@ +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +STRINGTABLE +BEGIN + IDS_USAGE "ReactOS Timeout Utility\n\ +\n\ +TIMEOUT [/?] [/T] delay [/NOBREAK]\n\ +\n\ +Description:\n\ + This tool waits until a specified time period (in seconds) has elapsed,\n\ + or until any key is pressed. A parameter to ignore the key press is also\n\ + accepted.\n\ +\n\ +Parameters:\n\ + /? Display this help screen.\n\ +\n\ + /T delay Specify the number of seconds to wait (-1 to 99999).\n\ + A value of -1 means the program will wait until a key is pressed.\n\ + Note that the ""/T"" specification is optional, you can just\n\ + specify the delay value without it.\n\ +\n\ + /NOBREAK Ignore all keyboard input except for Ctrl+C.\n\ +" + IDS_ERROR_OUT_OF_RANGE "ERROR: The timer value must be within range (-1 to 99999).\n" + IDS_ERROR_INVALID_HANDLE_VALUE "ERROR: Unable to get the standard handle for the console (error %lu).\n" + IDS_ERROR_READ_INPUT "ERROR: Unable to read the console input (error %lu).\n" + IDS_ERROR_NO_TIMER_VALUE "ERROR: The timer value must be specified (-1 to 99999).\n" + IDS_ERROR_ONE_TIME "ERROR: Only one timer value is needed.\n" + IDS_NOBREAK_INPUT "Press Ctrl+C to quit..." + IDS_USER_INPUT "Press any key to continue..." + IDS_NOBREAK_INPUT_COUNT "Waiting for %d second(s), press Ctrl+C to quit..." + IDS_USER_INPUT_COUNT "Waiting for %d second(s), press any key to continue..." +END
Propchange: trunk/reactos/base/applications/cmdutils/timeout/lang/en-US.rc ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/base/applications/cmdutils/timeout/lang/fr-FR.rc URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/... ============================================================================== --- trunk/reactos/base/applications/cmdutils/timeout/lang/fr-FR.rc (added) +++ trunk/reactos/base/applications/cmdutils/timeout/lang/fr-FR.rc [iso-8859-1] Mon Sep 25 23:31:44 2017 @@ -0,0 +1,34 @@ +LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL + +STRINGTABLE +BEGIN + IDS_USAGE "ReactOS Timeout Utility\n\ +\n\ +TIMEOUT [/?] [/T] délai [/NOBREAK]\n\ +\n\ +Description :\n\ + Cet outil permet d'attendre jusqu'à ce qu'un délai (en secondes) s'écoule,\n\ + ou bien jusqu'à ce qu'une touche de clavier soit pressée. Un paramètre\n\ + permettant d'ignorer l'appui de touche de clavier est accepté.\n\ +\n\ +Liste de paramètres :\n\ + /? Affiche cet écran d'aide.\n\ +\n\ + /T délai Spécifie le délai d'attente en secondes (entre -1 et 99999).\n\ + La valeur -1 signifie que le programme attend jusqu'à ce qu'une\n\ + touche soit pressée.\n\ + Veuillez noter que la spécification ""/T"" est optionnelle, vous\n\ + pouvez spécifier la valeur de délai sans celle-ci.\n\ +\n\ + /NOBREAK Ignore toute frappe de clavier, sauf pour Ctrl+C.\n\ +" + IDS_ERROR_OUT_OF_RANGE "ERREUR: Le délai d'attente doit être compris dans la plage (entre -1 et 99999).\n" + IDS_ERROR_INVALID_HANDLE_VALUE "ERREUR: Impossible d'obtenir le handle standard pour la console (erreur %lu).\n" + IDS_ERROR_READ_INPUT "ERREUR: Impossible de lire l'entrée de console (erreur %lu).\n" + IDS_ERROR_NO_TIMER_VALUE "ERREUR: Le délai d'attente doit être spécifié (entre -1 et 99999).\n" + IDS_ERROR_ONE_TIME "ERREUR: Une seule valeur de délai est nécessaire.\n" + IDS_NOBREAK_INPUT "Appuyez sur Ctrl+C pour quitter..." + IDS_USER_INPUT "Appuyez sur une touche pour continuer..." + IDS_NOBREAK_INPUT_COUNT "Attendre %d seconde(s), appuyez sur Ctrl+C pour quitter..." + IDS_USER_INPUT_COUNT "Attendre %d seconde(s), appuyez sur une touche pour continuer..." +END
Propchange: trunk/reactos/base/applications/cmdutils/timeout/lang/fr-FR.rc ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/base/applications/cmdutils/timeout/resource.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/... ============================================================================== --- trunk/reactos/base/applications/cmdutils/timeout/resource.h (added) +++ trunk/reactos/base/applications/cmdutils/timeout/resource.h [iso-8859-1] Mon Sep 25 23:31:44 2017 @@ -0,0 +1,12 @@ +#pragma once + +#define IDS_USAGE 0 +#define IDS_ERROR_OUT_OF_RANGE 1 +#define IDS_ERROR_INVALID_HANDLE_VALUE 2 +#define IDS_ERROR_READ_INPUT 3 +#define IDS_ERROR_NO_TIMER_VALUE 4 +#define IDS_ERROR_ONE_TIME 5 +#define IDS_NOBREAK_INPUT 6 +#define IDS_USER_INPUT 7 +#define IDS_NOBREAK_INPUT_COUNT 8 +#define IDS_USER_INPUT_COUNT 9
Propchange: trunk/reactos/base/applications/cmdutils/timeout/resource.h ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/base/applications/cmdutils/timeout/timeout.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/... ============================================================================== --- trunk/reactos/base/applications/cmdutils/timeout/timeout.c (added) +++ trunk/reactos/base/applications/cmdutils/timeout/timeout.c [iso-8859-1] Mon Sep 25 23:31:44 2017 @@ -0,0 +1,332 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Timeout utility + * FILE: base/applications/cmdutils/timeout/timeout.c + * PURPOSE: An enhanced alternative to the Pause command. + * PROGRAMMERS: Lee Schroeder (spaceseel at gmail dot com) + * Hermes Belusca-Maito (hermes.belusca@sfr.fr) + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <windef.h> +#include <winbase.h> +#include <wincon.h> +#include <winuser.h> + +#include <conutils.h> + +#include "resource.h" + +VOID PrintError(DWORD dwError) +{ + if (dwError == ERROR_SUCCESS) + return; + + ConMsgPuts(StdErr, FORMAT_MESSAGE_FROM_SYSTEM, + NULL, dwError, LANG_USER_DEFAULT); + ConPuts(StdErr, L"\n"); +} + +BOOL +WINAPI +CtrlCIntercept(DWORD dwCtrlType) +{ + switch (dwCtrlType) + { + case CTRL_C_EVENT: + ConPuts(StdOut, L"\n"); + SetConsoleCtrlHandler(NULL, FALSE); + ExitProcess(EXIT_FAILURE); + return TRUE; + } + return FALSE; +} + +INT InputWait(BOOL bNoBreak, INT timerValue) +{ + INT Status = EXIT_SUCCESS; + HANDLE hInput; + BOOL bUseTimer = (timerValue != -1); + DWORD dwStartTime; + LONG timeElapsed; + DWORD dwWaitState; + INPUT_RECORD InputRecords[5]; + ULONG NumRecords, i; + BOOL DisplayMsg = TRUE; + UINT WaitMsgId = (bNoBreak ? IDS_NOBREAK_INPUT : IDS_USER_INPUT); + UINT WaitCountMsgId = (bNoBreak ? IDS_NOBREAK_INPUT_COUNT : IDS_USER_INPUT_COUNT); + + /* Retrieve the current input handle */ + hInput = ConStreamGetOSHandle(StdIn); + if (hInput == INVALID_HANDLE_VALUE) + { + ConResPrintf(StdErr, IDS_ERROR_INVALID_HANDLE_VALUE, GetLastError()); + return EXIT_FAILURE; + } + + /* Start a new wait if we use the timer */ + if (bUseTimer) + dwStartTime = GetTickCount(); + + /* If /NOBREAK is used, monitor for Ctrl-C input */ + if (bNoBreak) + SetConsoleCtrlHandler(CtrlCIntercept, TRUE); + + /* Initially flush the console input queue to remove any pending events */ + if (!GetNumberOfConsoleInputEvents(hInput, &NumRecords) || + !FlushConsoleInputBuffer(hInput)) + { + /* A problem happened, bail out */ + PrintError(GetLastError()); + Status = EXIT_FAILURE; + goto Quit; + } + + ConPuts(StdOut, L"\n"); + + /* If the timer is not used, just show the message */ + if (!bUseTimer) + { + ConPuts(StdOut, L"\r"); + ConResPuts(StdOut, WaitMsgId); + } + + while (TRUE) + { + /* Decrease the timer if we use it */ + if (bUseTimer) + { + /* + * Compute how much time the previous operations took. + * This allows us in particular to take account for any time + * elapsed if something slowed down, or if the console has been + * paused in the meantime. + */ + timeElapsed = GetTickCount() - dwStartTime; + if (timeElapsed >= 1000) + { + /* Increase dwStartTime by steps of 1 second */ + timeElapsed /= 1000; + dwStartTime += (1000 * timeElapsed); + + if (timeElapsed <= timerValue) + timerValue -= timeElapsed; + else + timerValue = 0; + + DisplayMsg = TRUE; + } + + if (DisplayMsg) + { + ConPuts(StdOut, L"\r"); + ConResPrintf(StdOut, WaitCountMsgId, timerValue); + ConPuts(StdOut, L" \b"); + + DisplayMsg = FALSE; + } + + /* Stop when the timer reaches zero */ + if (timerValue <= 0) + break; + } + + /* If /NOBREAK is used, only allow Ctrl-C input which is handled by the console handler */ + if (bNoBreak) + { + if (bUseTimer) + { + /* We use the timer: wait a little bit before updating it */ + Sleep(100); + } + else + { + /* No timer is used: wait indefinitely */ + Sleep(INFINITE); + } + + continue; + } + + /* /NOBREAK is not used, check for user key presses */ + + /* + * If the timer is used, use a passive wait of maximum 1 second + * while monitoring for incoming console input events, so that + * we are still able to display the timing count. + * Indeed, ReadConsoleInputW() indefinitely waits until an input + * event appears. ReadConsoleInputW() is however used to retrieve + * the input events where there are some, as well as for waiting + * indefinitely in case we do not use the timer. + */ + if (bUseTimer) + { + /* Wait a maximum of 1 second for input events */ + timeElapsed = GetTickCount() - dwStartTime; + if (timeElapsed < 1000) + dwWaitState = WaitForSingleObject(hInput, 1000 - timeElapsed); + else + dwWaitState = WAIT_TIMEOUT; + + /* Check whether the input handle has been signaled, or a timeout happened */ + if (dwWaitState == WAIT_TIMEOUT) + continue; + if (dwWaitState != WAIT_OBJECT_0) + { + /* An error happened, bail out */ + PrintError(GetLastError()); + Status = EXIT_FAILURE; + break; + } + + /* Be sure there is someting in the console input queue */ + if (!PeekConsoleInputW(hInput, InputRecords, ARRAYSIZE(InputRecords), &NumRecords)) + { + /* An error happened, bail out */ + ConResPrintf(StdErr, IDS_ERROR_READ_INPUT, GetLastError()); + Status = EXIT_FAILURE; + break; + } + + if (NumRecords == 0) + continue; + } + + /* + * Some events have been detected, pop them out from the input queue. + * In case we do not use the timer, wait indefinitely until an input + * event appears. + */ + if (!ReadConsoleInputW(hInput, InputRecords, ARRAYSIZE(InputRecords), &NumRecords)) + { + /* An error happened, bail out */ + ConResPrintf(StdErr, IDS_ERROR_READ_INPUT, GetLastError()); + Status = EXIT_FAILURE; + break; + } + + /* Check the input events for a key press */ + for (i = 0; i < NumRecords; ++i) + { + /* Ignore any non-key event */ + if (InputRecords[i].EventType != KEY_EVENT) + continue; + + /* Ignore any system key event */ + if ((InputRecords[i].Event.KeyEvent.wVirtualKeyCode == VK_CONTROL) || + // (InputRecords[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED )) || + // (InputRecords[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) || + (InputRecords[i].Event.KeyEvent.wVirtualKeyCode == VK_MENU)) + { + continue; + } + + /* This is a non-system key event, stop waiting */ + goto Stop; + } + } + +Stop: + ConPuts(StdOut, L"\n"); + +Quit: + if (bNoBreak) + SetConsoleCtrlHandler(NULL, FALSE); + + return Status; +} + +int wmain(int argc, WCHAR* argv[]) +{ + INT timerValue = -1; + PWCHAR pszNext; + BOOL bDisableInput = FALSE, fTimerFlags = 0; + int index = 0; + + /* Initialize the Console Standard Streams */ + ConInitStdStreams(); + + if (argc == 1) + { + ConResPrintf(StdOut, IDS_USAGE); + return EXIT_SUCCESS; + } + + /* Parse the command line for options */ + for (index = 1; index < argc; index++) + { + if (argv[index][0] == L'-' || argv[index][0] == L'/') + { + switch (towupper(argv[index][1])) + { + case L'?': /* Help */ + { + ConResPrintf(StdOut, IDS_USAGE); + return EXIT_SUCCESS; + } + + case L'T': /* Timer */ + { + /* Consecutive /T switches are invalid */ + if (fTimerFlags & 2) + { + ConResPrintf(StdErr, IDS_ERROR_ONE_TIME); + return EXIT_FAILURE; + } + + /* Remember that a /T switch has been encountered */ + fTimerFlags |= 2; + + /* Go to the next (timer) value */ + continue; + } + } + + /* This flag is used to ignore any keyboard keys but Ctrl-C */ + if (_wcsicmp(&argv[index][1], L"NOBREAK") == 0) + { + bDisableInput = TRUE; + + /* Go to next value */ + continue; + } + } + + /* The timer value can also be specified without the /T switch */ + + /* Only one timer value is supported */ + if (fTimerFlags & 1) + { + ConResPrintf(StdErr, IDS_ERROR_ONE_TIME); + return EXIT_FAILURE; + } + + timerValue = wcstol(argv[index], &pszNext, 10); + if (*pszNext) + { + ConResPrintf(StdErr, IDS_ERROR_OUT_OF_RANGE); + return EXIT_FAILURE; + } + + /* Remember that the timer value has been set */ + fTimerFlags |= 1; + } + + /* A timer value is mandatory in order to continue */ + if (!(fTimerFlags & 1)) + { + ConResPrintf(StdErr, IDS_ERROR_NO_TIMER_VALUE); + return EXIT_FAILURE; + } + + /* Make sure the timer value is within range */ + if ((timerValue < -1) || (timerValue > 99999)) + { + ConResPrintf(StdErr, IDS_ERROR_OUT_OF_RANGE); + return EXIT_FAILURE; + } + + return InputWait(bDisableInput, timerValue); +}
Propchange: trunk/reactos/base/applications/cmdutils/timeout/timeout.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/base/applications/cmdutils/timeout/timeout.rc URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils/... ============================================================================== --- trunk/reactos/base/applications/cmdutils/timeout/timeout.rc (added) +++ trunk/reactos/base/applications/cmdutils/timeout/timeout.rc [iso-8859-1] Mon Sep 25 23:31:44 2017 @@ -0,0 +1,21 @@ +#include <windef.h> +// #include <winuser.h> + +#include "resource.h" + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Timeout Utility" +#define REACTOS_STR_INTERNAL_NAME "timeout" +#define REACTOS_STR_ORIGINAL_FILENAME "timeout.exe" +#include <reactos/version.rc> + +/* UTF-8 */ +#pragma code_page(65001) + +#ifdef LANGUAGE_EN_US + #include "lang/en-US.rc" +#endif +#ifdef LANGUAGE_FR_FR + #include "lang/fr-FR.rc" +#endif
Propchange: trunk/reactos/base/applications/cmdutils/timeout/timeout.rc ------------------------------------------------------------------------------ svn:eol-style = native