ReactOS 0.4.15-dev-7788-g1ad9096
timeout.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Timeout utility
4 * FILE: base/applications/cmdutils/timeout/timeout.c
5 * PURPOSE: An enhanced alternative to the Pause command.
6 * PROGRAMMERS: Lee Schroeder (spaceseel at gmail dot com)
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10#include <stdio.h>
11#include <stdlib.h>
12
13#include <windef.h>
14#include <winbase.h>
15#include <wincon.h>
16#include <winuser.h>
17
18#include <conutils.h>
19
20#include "resource.h"
21
23{
24 if (dwError == ERROR_SUCCESS)
25 return;
26
28 NULL, dwError, LANG_USER_DEFAULT);
29 ConPuts(StdErr, L"\n");
30}
31
32BOOL
35{
36 switch (dwCtrlType)
37 {
38 case CTRL_C_EVENT:
39 ConPuts(StdOut, L"\n");
42 return TRUE;
43 }
44 return FALSE;
45}
46
47INT InputWait(BOOL bNoBreak, INT timerValue)
48{
50 HANDLE hInput;
51 BOOL bUseTimer = (timerValue != -1);
52 HANDLE hTimer = NULL;
53 DWORD dwStartTime;
54 LONG timeElapsed;
55 DWORD dwWaitState;
56 INPUT_RECORD InputRecords[5];
57 ULONG NumRecords, i;
58 BOOL DisplayMsg = TRUE;
59 UINT WaitMsgId = (bNoBreak ? IDS_NOBREAK_INPUT : IDS_USER_INPUT);
60 UINT WaitCountMsgId = (bNoBreak ? IDS_NOBREAK_INPUT_COUNT : IDS_USER_INPUT_COUNT);
61
62 /* Retrieve the current input handle */
64 if (hInput == INVALID_HANDLE_VALUE)
65 {
67 return EXIT_FAILURE;
68 }
69
70 /* Start a new wait if we use the timer */
71 if (bNoBreak && bUseTimer)
72 {
74 if (hTimer == NULL)
75 {
76 /* A problem happened, bail out */
78 return EXIT_FAILURE;
79 }
80 }
81 if (bUseTimer)
82 dwStartTime = GetTickCount();
83
84 /* If /NOBREAK is used, monitor for Ctrl-C input */
85 if (bNoBreak)
87
88 /* Initially flush the console input queue to remove any pending events */
89 if (!GetNumberOfConsoleInputEvents(hInput, &NumRecords) ||
91 {
92 /* A problem happened, bail out */
95 goto Quit;
96 }
97
98 ConPuts(StdOut, L"\n");
99
100 /* If the timer is not used, just show the message */
101 if (!bUseTimer)
102 {
103 ConPuts(StdOut, L"\r");
104 ConResPuts(StdOut, WaitMsgId);
105 }
106
107 while (TRUE)
108 {
109 /* Decrease the timer if we use it */
110 if (bUseTimer)
111 {
112 /*
113 * Compute how much time the previous operations took.
114 * This allows us in particular to take account for any time
115 * elapsed if something slowed down, or if the console has been
116 * paused in the meantime.
117 */
118 timeElapsed = GetTickCount() - dwStartTime;
119 if (timeElapsed >= 1000)
120 {
121 /* Increase dwStartTime by steps of 1 second */
122 timeElapsed /= 1000;
123 dwStartTime += (1000 * timeElapsed);
124
125 if (timeElapsed <= timerValue)
126 timerValue -= timeElapsed;
127 else
128 timerValue = 0;
129
130 DisplayMsg = TRUE;
131 }
132
133 if (DisplayMsg)
134 {
135 ConPuts(StdOut, L"\r");
136 ConResPrintf(StdOut, WaitCountMsgId, timerValue);
137 ConPuts(StdOut, L" \b");
138
139 DisplayMsg = FALSE;
140 }
141
142 /* Stop when the timer reaches zero */
143 if (timerValue <= 0)
144 break;
145 }
146
147 /* If /NOBREAK is used, only allow Ctrl-C input which is handled by the console handler */
148 if (bNoBreak)
149 {
150 if (bUseTimer)
151 {
153
154 /* We use the timer: use a passive wait of maximum 1 second */
155 timeElapsed = GetTickCount() - dwStartTime;
156 if (timeElapsed < 1000)
157 {
158 DueTime.QuadPart = Int32x32To64(1000 - timeElapsed, -10000);
159 SetWaitableTimer(hTimer, &DueTime, 0, NULL, NULL, FALSE);
160 dwWaitState = WaitForSingleObject(hTimer, INFINITE);
161
162 /* Check whether the timer has been signaled */
163 if (dwWaitState != WAIT_OBJECT_0)
164 {
165 /* An error happened, bail out */
168 break;
169 }
170 }
171 }
172 else
173 {
174 /* No timer is used: wait indefinitely */
176 }
177
178 continue;
179 }
180
181 /* /NOBREAK is not used, check for user key presses */
182
183 /*
184 * If the timer is used, use a passive wait of maximum 1 second
185 * while monitoring for incoming console input events, so that
186 * we are still able to display the timing count.
187 * Indeed, ReadConsoleInputW() indefinitely waits until an input
188 * event appears. ReadConsoleInputW() is however used to retrieve
189 * the input events where there are some, as well as for waiting
190 * indefinitely in case we do not use the timer.
191 */
192 if (bUseTimer)
193 {
194 /* Wait a maximum of 1 second for input events */
195 timeElapsed = GetTickCount() - dwStartTime;
196 if (timeElapsed < 1000)
197 dwWaitState = WaitForSingleObject(hInput, 1000 - timeElapsed);
198 else
199 dwWaitState = WAIT_TIMEOUT;
200
201 /* Check whether the input event has been signaled, or a timeout happened */
202 if (dwWaitState == WAIT_TIMEOUT)
203 continue;
204 if (dwWaitState != WAIT_OBJECT_0)
205 {
206 /* An error happened, bail out */
209 break;
210 }
211
212 /* Be sure there is something in the console input queue */
213 if (!PeekConsoleInputW(hInput, InputRecords, ARRAYSIZE(InputRecords), &NumRecords))
214 {
215 /* An error happened, bail out */
218 break;
219 }
220
221 if (NumRecords == 0)
222 continue;
223 }
224
225 /*
226 * Some events have been detected, pop them out from the input queue.
227 * In case we do not use the timer, wait indefinitely until an input
228 * event appears.
229 */
230 if (!ReadConsoleInputW(hInput, InputRecords, ARRAYSIZE(InputRecords), &NumRecords))
231 {
232 /* An error happened, bail out */
235 break;
236 }
237
238 /* Check the input events for a key press */
239 for (i = 0; i < NumRecords; ++i)
240 {
241 /* Ignore any non-key event */
242 if (InputRecords[i].EventType != KEY_EVENT)
243 continue;
244
245 /* Ignore any system key event */
246 if ((InputRecords[i].Event.KeyEvent.wVirtualKeyCode == VK_CONTROL) ||
247 // (InputRecords[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED )) ||
248 // (InputRecords[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) ||
249 (InputRecords[i].Event.KeyEvent.wVirtualKeyCode == VK_MENU))
250 {
251 continue;
252 }
253
254 /* This is a non-system key event, stop waiting */
255 goto Stop;
256 }
257 }
258
259Stop:
260 ConPuts(StdOut, L"\n");
261
262Quit:
263 if (bNoBreak)
265
266 if (bNoBreak && bUseTimer)
267 CloseHandle(hTimer);
268
269 return Status;
270}
271
272int wmain(int argc, WCHAR* argv[])
273{
274 INT timerValue = -1;
275 PWCHAR pszNext;
276 BOOL bDisableInput = FALSE, fTimerFlags = 0;
277 int index = 0;
278
279 /* Initialize the Console Standard Streams */
281
282 if (argc == 1)
283 {
285 return EXIT_SUCCESS;
286 }
287
288 /* Parse the command line for options */
289 for (index = 1; index < argc; index++)
290 {
291 if (argv[index][0] == L'-' || argv[index][0] == L'/')
292 {
293 switch (towupper(argv[index][1]))
294 {
295 case L'?': /* Help */
296 {
298 return EXIT_SUCCESS;
299 }
300
301 case L'T': /* Timer */
302 {
303 /* Consecutive /T switches are invalid */
304 if (fTimerFlags & 2)
305 {
307 return EXIT_FAILURE;
308 }
309
310 /* Remember that a /T switch has been encountered */
311 fTimerFlags |= 2;
312
313 /* Go to the next (timer) value */
314 continue;
315 }
316 }
317
318 /* This flag is used to ignore any keyboard keys but Ctrl-C */
319 if (_wcsicmp(&argv[index][1], L"NOBREAK") == 0)
320 {
321 bDisableInput = TRUE;
322
323 /* Go to next value */
324 continue;
325 }
326 }
327
328 /* The timer value can also be specified without the /T switch */
329
330 /* Only one timer value is supported */
331 if (fTimerFlags & 1)
332 {
334 return EXIT_FAILURE;
335 }
336
337 timerValue = wcstol(argv[index], &pszNext, 10);
338 if (*pszNext)
339 {
341 return EXIT_FAILURE;
342 }
343
344 /* Remember that the timer value has been set */
345 fTimerFlags |= 1;
346 }
347
348 /* A timer value is mandatory in order to continue */
349 if (!(fTimerFlags & 1))
350 {
352 return EXIT_FAILURE;
353 }
354
355 /* Make sure the timer value is within range */
356 if ((timerValue < -1) || (timerValue > 99999))
357 {
359 return EXIT_FAILURE;
360 }
361
362 return InputWait(bDisableInput, timerValue);
363}
static int argc
Definition: ServiceArgs.c:12
#define IDS_USAGE
Definition: resource.h:3
void ConPuts(FILE *fp, LPCWSTR psz)
Definition: fc.c:16
#define ConInitStdStreams()
Definition: fc.c:13
#define StdOut
Definition: fc.c:14
void ConResPrintf(FILE *fp, UINT nID,...)
Definition: fc.c:33
#define StdErr
Definition: fc.c:15
void ConResPuts(FILE *fp, UINT nID)
Definition: fc.c:27
#define IDS_ERROR_OUT_OF_RANGE
Definition: resource.h:4
#define IDS_USER_INPUT_COUNT
Definition: resource.h:12
#define IDS_NOBREAK_INPUT_COUNT
Definition: resource.h:11
#define IDS_ERROR_READ_INPUT
Definition: resource.h:6
#define IDS_ERROR_NO_TIMER_VALUE
Definition: resource.h:7
#define IDS_USER_INPUT
Definition: resource.h:10
#define IDS_ERROR_INVALID_HANDLE_VALUE
Definition: resource.h:5
#define IDS_ERROR_ONE_TIME
Definition: resource.h:8
#define IDS_NOBREAK_INPUT
Definition: resource.h:9
BOOL WINAPI FlushConsoleInputBuffer(IN HANDLE hConsoleInput)
Definition: console.c:220
#define WAIT_TIMEOUT
Definition: dderror.h:14
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define CloseHandle
Definition: compat.h:739
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add)
Definition: console.c:2109
BOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE hConsoleInput, LPDWORD lpNumberOfEvents)
Definition: console.c:1635
BOOL WINAPI DECLSPEC_HOTPATCH ReadConsoleInputW(IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead)
Definition: readwrite.c:1256
BOOL WINAPI DECLSPEC_HOTPATCH PeekConsoleInputW(IN HANDLE hConsoleInput, OUT PINPUT_RECORD lpBuffer, IN DWORD nLength, OUT LPDWORD lpNumberOfEventsRead)
Definition: readwrite.c:1216
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1487
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
#define INFINITE
Definition: serial.h:102
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
Status
Definition: gdiplustypes.h:25
GLuint index
Definition: glext.h:6031
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_Check_return_ long __cdecl wcstol(_In_z_ const wchar_t *_Str, _Out_opt_ _Deref_post_z_ wchar_t **_EndPtr, _In_ int _Radix)
#define EXIT_FAILURE
Definition: jerror.c:33
_In_opt_ PVOID _Out_ BOOLEAN * Stop
Definition: ldrtypes.h:241
#define argv
Definition: mplay32.c:18
unsigned int UINT
Definition: ndis.h:50
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ EVENT_TYPE EventType
Definition: exfuncs.h:167
#define Int32x32To64(a, b)
#define L(x)
Definition: ntvdm.h:50
INT ConMsgPuts(IN PCON_STREAM Stream, IN DWORD dwFlags, IN LPCVOID lpSource OPTIONAL, IN DWORD dwMessageId, IN DWORD dwLanguageId)
Definition: outstream.c:837
long LONG
Definition: pedump.c:60
int wmain()
#define EXIT_SUCCESS
Definition: rdjpgcom.c:55
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
HANDLE ConStreamGetOSHandle(IN PCON_STREAM Stream)
Definition: stream.c:240
#define StdIn
Definition: stream.h:81
union _INPUT_RECORD::@3287 Event
KEY_EVENT_RECORD KeyEvent
Definition: wincon.h:275
WORD wVirtualKeyCode
Definition: wincon.h:242
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:790
BOOL WINAPI SetWaitableTimer(IN HANDLE hTimer, IN const LARGE_INTEGER *pDueTime, IN LONG lPeriod, IN PTIMERAPCROUTINE pfnCompletionRoutine OPTIONAL, IN OPTIONAL LPVOID lpArgToCompletionRoutine, IN BOOL fResume)
Definition: synch.c:382
VOID PrintError(DWORD dwError)
Definition: timeout.c:22
BOOL WINAPI CtrlCIntercept(DWORD dwCtrlType)
Definition: timeout.c:34
INT InputWait(BOOL bNoBreak, INT timerValue)
Definition: timeout.c:47
#define LANG_USER_DEFAULT
Definition: tnerror.cpp:50
#define towupper(c)
Definition: wctype.h:99
int32_t INT
Definition: typedefs.h:58
uint16_t * PWCHAR
Definition: typedefs.h:56
uint32_t ULONG
Definition: typedefs.h:59
_In_ WDFTIMER _In_ LONGLONG DueTime
Definition: wdftimer.h:190
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define FORMAT_MESSAGE_FROM_SYSTEM
Definition: winbase.h:423
#define WAIT_OBJECT_0
Definition: winbase.h:406
#define CreateWaitableTimer
Definition: winbase.h:3696
#define CTRL_C_EVENT
Definition: wincon.h:68
#define KEY_EVENT
Definition: wincon.h:128
#define WINAPI
Definition: msvc.h:6
#define VK_CONTROL
Definition: winuser.h:2203
#define VK_MENU
Definition: winuser.h:2204
__wchar_t WCHAR
Definition: xmlstorage.h:180