ReactOS 0.4.17-dev-540-g8f54750
choice.c
Go to the documentation of this file.
1/*
2 * CHOICE.C - internal command.
3 *
4 *
5 * History:
6 *
7 * 12 Aug 1999 (Eric Kohl)
8 * started.
9 *
10 * 01 Sep 1999 (Eric Kohl)
11 * Fixed help text.
12 *
13 * 26 Sep 1999 (Paolo Pantaleo)
14 * Fixed timeout.
15 *
16 * 02 Apr 2005 (Magnus Olsen)
17 * Remove hardcoded strings so that they can be translated.
18 *
19 */
20
21#include "precomp.h"
22
23#ifdef INCLUDE_CMD_CHOICE
24
25
26#define GC_TIMEOUT -1
27#define GC_NOKEY 0 //an event occurred but it wasn't a key pressed
28#define GC_KEYREAD 1 //a key has been read
29
30
31static INT
32GetCharacterTimeout (LPTCH ch, DWORD dwMilliseconds)
33{
34//--------------------------------------------
35// Get a character from standard input but with a timeout.
36// The function will wait a limited amount
37// of time, then the function returns GC_TIMEOUT.
38//
39// dwMilliseconds is the timeout value, that can
40// be set to INFINITE, so the function works like
41// stdio.h's getchar()
42
43 HANDLE hInput;
44 DWORD dwRead;
45
47
49
50 //if the timeout expired return GC_TIMEOUT
51 if (WaitForSingleObject (hInput, dwMilliseconds) == WAIT_TIMEOUT)
52 return GC_TIMEOUT;
53
54 //otherwise get the event
55 lpBuffer.EventType = !KEY_EVENT;
56 if (!ReadConsoleInput (hInput, &lpBuffer, 1, &dwRead) && GetLastError () == ERROR_INVALID_HANDLE)
57 {
58 *ch = '\0';
59 if (ReadFile(hInput, ch, 1, &dwRead, NULL))
60 return GC_KEYREAD;
61 }
62
63 //if the event is a key pressed
64 if ((lpBuffer.EventType == KEY_EVENT) &&
65 (lpBuffer.Event.KeyEvent.bKeyDown != FALSE))
66 {
67 //read the key
68#ifdef _UNICODE
69 *ch = lpBuffer.Event.KeyEvent.uChar.UnicodeChar;
70#else
71 *ch = lpBuffer.Event.KeyEvent.uChar.AsciiChar;
72#endif
73 return GC_KEYREAD;
74 }
75
76 //else return no key
77 return GC_NOKEY;
78}
79
80static INT
82{
83 LPTCH p = lpString;
84 INT val = 0;
85
86 while (*p)
87 {
89 {
90 if (*p == cKey)
91 return val;
92 }
93 else
94 {
95 if (_totlower (*p) == _totlower (cKey))
96 return val;
97 }
98
99 val++;
100 p++;
101 }
102
103 return -1;
104}
105
106
107INT
109{
110 LPTSTR lpOptions;
111 TCHAR Options[6];
112 LPTSTR lpText = NULL, lpTextParam = NULL;
113 UINT iSkipTextIndex = 0, iTextIndex;
114 BOOL bNoPrompt = FALSE;
116 BOOL bTimeout = FALSE;
117 INT nTimeout = 0;
118 TCHAR cDefault = _T('\0'), cDefParam = _T('\0');
119 INPUT_RECORD ir;
120 LPTSTR p, np;
121 LPTSTR *arg;
122 INT argc;
123 INT i;
124 INT val;
125
126 INT GCret;
127 TCHAR Ch;
128 DWORD amount,clk;
129
131 lpOptions = Options;
132
133 if (_tcsncmp (param, _T("/?"), 2) == 0)
134 {
136 return 0;
137 }
138
139 /* build parameter array */
140 arg = split (param, &argc, FALSE, FALSE);
141
142 /* evaluate arguments */
143 nErrorLevel = 255;
144 if (argc > 0)
145 {
146 for (i = 0; i < argc; i++)
147 {
148 if (_tcsnicmp (arg[i], _T("/s"), 2) == 0) /* DOS */
149 {
151 }
152 else if (_tcsnicmp (arg[i], _T("/cs"), 3) == 0) /* NT */
153 {
155 }
156 else if (_tcsnicmp (arg[i], _T("/c"), 2) == 0) /* Note: This eats /CS so it must come after */
157 {
158 if (arg[i][2] == _T(':'))
159 lpOptions = &arg[i][3]; /* "/c:XYZ" (DOS and NT) */
160 else if (arg[i][2])
161 lpOptions = &arg[i][2]; /* "/cXYZ" (DOS) */
162 else if (i + 1 < argc && *arg[i + 1] != _T('/'))
163 lpOptions = arg[iSkipTextIndex = ++i]; /* "/c XYZ" (NT) */
164
165 if (!*lpOptions)
166 {
167 invalid_choice_characters:
169 freep(arg);
170 return nErrorLevel;
171 }
172 }
173 else if (_tcsnicmp (arg[i], _T("/m"), 2) == 0) /* "/m msg" (NT) */
174 {
175 if (arg[i][2] == _T(':'))
176 lpText = lpTextParam = &arg[i][3];
177 else if (i + 1 < argc && *arg[i + 1] != _T('/'))
178 lpText = lpTextParam = arg[++i];
179 else
180 {
182 freep(arg);
183 return nErrorLevel;
184 }
185 }
186 else if (_tcsnicmp (arg[i], _T("/n"), 2) == 0)
187 {
188 bNoPrompt = TRUE;
189 }
190 else if (_tcsnicmp (arg[i], _T("/d"), 2) == 0) /* "/d:X" and "/d X" (NT) */
191 {
192 if (arg[i][2] == _T(':'))
193 cDefault = cDefParam = arg[i][3];
194 else if (i + 1 < argc)
195 cDefault = cDefParam = arg[iSkipTextIndex = ++i][0];
196 else
197 goto invalid_parameter_format;
198 }
199 else if (_tcsnicmp (arg[i], _T("/t"), 2) == 0)
200 {
201 LPTSTR s, end;
202 TCHAR cSaveDefault = cDefault;
203
204 if (arg[i][2] == _T(':'))
205 {
206 cDefault = arg[i][3];
207 s = &arg[i][4];
208 }
209 else
210 {
211 cDefault = arg[i][2];
212 s = &arg[i][3];
213 }
214
215 if (*s != _T(','))
216 {
217 /* Just a number (NT syntax) */
218 cDefault = cSaveDefault;
219 if (arg[i][2] == _T(':'))
220 s = &arg[i][3];
221 else if (i + 1 < argc)
222 s = arg[iSkipTextIndex = ++i];
223
224 _tcstol(s, &end, 10);
225 if (end > s && !*end)
226 goto parse_timeout_seconds;
227
228 failed_parse_timeout:
230 freep (arg);
231 return nErrorLevel;
232 }
233
234 s++;
235 parse_timeout_seconds:
236 nTimeout = _ttoi(s);
237 bTimeout = TRUE;
238 }
239 else if (arg[i][0] == _T('/'))
240 {
241 invalid_parameter_format:
243 freep (arg);
244 return nErrorLevel;
245 }
246 }
247 }
248
249 if (bTimeout)
250 {
251 if (!cDefault) /* NT /t syntax used without /d */
252 goto failed_parse_timeout;
253 if (nTimeout < 0 || (cDefParam && nTimeout > 9999)) /* DOS seems to be limited to 99, no ">" validation */
254 goto failed_parse_timeout;
255 if (IsKeyInString(lpOptions, cDefault, bCaseSensitive) < 0) /* The default must exist in the list of options */
256 goto failed_parse_timeout;
257
258 /* Duplicate choice characters are not allowed */
259 for (p = lpOptions; *p; ++p)
260 {
261 if (IsKeyInString(p + 1, *p, bCaseSensitive) >= 0)
262 goto invalid_choice_characters;
263 }
264 }
265
266 /* The choice characters are printed uppercase when case-insensitive */
267 if (!bCaseSensitive)
268 _wcsupr(lpOptions);
269
270 /* retrieve text */
271 for (p = param, iTextIndex = 0; !lpTextParam; ++iTextIndex)
272 {
273 if (*p == _T('\0'))
274 break;
275
276 if (*p != _T('/') && (!iSkipTextIndex || iTextIndex > iSkipTextIndex))
277 {
278 lpText = p;
279 break;
280 }
281 np = _tcschr (p, _T(' '));
282 if (!np)
283 break;
284 p = np + 1;
285 }
286
287 /* print text */
288 if (lpText)
289 ConOutPrintf (_T("%s"), lpText);
290
291 /* print options */
292 if (bNoPrompt == FALSE)
293 {
294 LPCTSTR prefix = lpText && lpText == lpTextParam ? _T(" ") : _T("");
295 ConOutPrintf (_T("%s[%c"), prefix, lpOptions[0]);
296
297 for (i = 1; (unsigned)i < _tcslen (lpOptions); i++)
298 ConOutPrintf (_T(",%c"), lpOptions[i]);
299
300 ConOutPrintf (_T("]?"));
301 }
302
303 ConInFlush ();
304
305 if (!bTimeout)
306 {
307 while (TRUE)
308 {
309 ConInKey (&ir);
310
311 val = IsKeyInString (lpOptions,
312#ifdef _UNICODE
314#else
316#endif
318
319 if (val >= 0)
320 {
321 ConOutPrintf (_T("%c\n"), lpOptions[val]);
322
323 nErrorLevel = val + 1;
324
325 break;
326 }
327
328 Beep (440, 50);
329 }
330
331 freep (arg);
332 TRACE ("ErrorLevel: %d\n", nErrorLevel);
333 return nErrorLevel;
334 }
335
336 clk = GetTickCount ();
337 amount = nTimeout*1000;
338
339loop:
340 nTimeout = amount - (GetTickCount () - clk);
341 if (nTimeout < 0)
342 GCret = GC_TIMEOUT;
343 else
344 GCret = GetCharacterTimeout (&Ch, nTimeout);
345
346 switch (GCret)
347 {
348 case GC_TIMEOUT:
349 TRACE ("GC_TIMEOUT\n");
350 TRACE ("elapsed %d msecs\n", GetTickCount () - clk);
351 break;
352
353 case GC_NOKEY:
354 TRACE ("GC_NOKEY\n");
355 TRACE ("elapsed %d msecs\n", GetTickCount () - clk);
356 goto loop;
357
358 case GC_KEYREAD:
359 TRACE ("GC_KEYREAD\n");
360 TRACE ("elapsed %d msecs\n", GetTickCount () - clk);
361 TRACE ("read %c\n", Ch);
362 if ((val=IsKeyInString(lpOptions,Ch,bCaseSensitive))==-1)
363 {
364 Beep (440, 50);
365 goto loop;
366 }
367 cDefault=Ch;
368 break;
369 }
370
371 TRACE ("exiting wait loop after %d msecs\n",
372 GetTickCount () - clk);
373
374 val = IsKeyInString (lpOptions, cDefault, bCaseSensitive);
375 ConOutPrintf(_T("%c\n"), lpOptions[val]);
376
377 nErrorLevel = val + 1;
378
379 freep (arg);
380
381 TRACE ("ErrorLevel: %d\n", nErrorLevel);
382
383 return nErrorLevel;
384}
385#endif /* INCLUDE_CMD_CHOICE */
386
387/* EOF */
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:203
INT nErrorLevel
Definition: cmd.c:158
HANDLE CMD_ModuleHandle
Definition: cmd.c:165
VOID ConOutResPaging(BOOL StartPaging, UINT resID)
Definition: console.c:178
VOID ConInKey(PINPUT_RECORD lpBuffer)
Definition: console.c:61
VOID ConInFlush(VOID)
Definition: console.c:56
#define ConErrResPuts(uID)
Definition: console.h:38
#define ConOutPrintf(szStr,...)
Definition: console.h:41
#define ConErrResPrintf(uID,...)
Definition: console.h:50
#define STRING_CHOICE_ERROR_TXT
Definition: resource.h:32
#define STRING_CHOICE_OPTION
Definition: resource.h:26
#define STRING_CHOICE_HELP
Definition: resource.h:73
#define STRING_CHOICE_ERROR_OPTION
Definition: resource.h:33
#define STRING_CHOICE_ERROR
Definition: resource.h:31
#define GC_KEYREAD
Definition: choice.c:28
#define GC_NOKEY
Definition: choice.c:27
static INT IsKeyInString(LPTSTR lpString, TCHAR cKey, BOOL bCaseSensitive)
Definition: choice.c:81
#define GC_TIMEOUT
Definition: choice.c:26
static INT GetCharacterTimeout(LPTCH ch, DWORD dwMilliseconds)
Definition: choice.c:32
INT CommandChoice(LPTSTR param)
Definition: choice.c:108
static VOID freep(LPSTR *p)
Definition: cmdcons.c:98
static LPSTR * split(LPSTR s, LPINT args)
Definition: cmdcons.c:163
#define WAIT_TIMEOUT
Definition: dderror.h:14
BOOL WINAPI Beep(IN DWORD dwFreq, IN DWORD dwDuration)
Definition: deviceio.c:48
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define ERROR_INVALID_HANDLE
Definition: compat.h:98
ULONG WINAPI DECLSPEC_HOTPATCH GetTickCount(void)
Definition: sync.c:182
MonoAssembly int argc
Definition: metahost.c:107
unsigned char ch[4][2]
Definition: console.c:118
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLdouble s
Definition: gl.h:2039
GLuint GLuint end
Definition: gl.h:1545
GLuint GLfloat * val
Definition: glext.h:7180
GLfloat GLfloat p
Definition: glext.h:8902
GLfloat param
Definition: glext.h:5796
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
unsigned int UINT
Definition: sysinfo.c:13
char TCHAR
Definition: tchar.h:1402
#define _ttoi
Definition: tchar.h:611
#define _tcsncmp
Definition: tchar.h:1428
#define _tcsnicmp
Definition: tchar.h:1431
#define _tcslen
Definition: tchar.h:626
#define _tcstol
Definition: tchar.h:594
#define _tcschr
Definition: tchar.h:1406
#define _totlower
Definition: tchar.h:1511
static unsigned(__cdecl *hash_bstr)(bstr_t s)
LPSTR LPTSTR
Definition: ms-dtyp.idl:131
LPCSTR LPCTSTR
Definition: ms-dtyp.idl:130
_Out_ LPWSTR lpBuffer
Definition: netsh.h:68
_wcsupr
#define Ch(x, y, z)
Definition: sha2.c:141
#define TRACE(s)
Definition: solgame.cpp:4
union _INPUT_RECORD::@3579 Event
KEY_EVENT_RECORD KeyEvent
Definition: wincon.h:296
union _KEY_EVENT_RECORD::@3578 uChar
WCHAR UnicodeChar
Definition: wincon.h:266
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
static BOOL bCaseSensitive
Definition: systempage.cpp:56
Character const *const prefix
Definition: tempnam.cpp:195
#define _UNICODE
Definition: textw.c:5
int32_t INT
Definition: typedefs.h:58
#define _T(x)
Definition: vfdio.h:22
_In_ PWDFDEVICE_INIT _In_ PWDF_REMOVE_LOCK_OPTIONS Options
Definition: wdfdevice.h:3540
#define STD_INPUT_HANDLE
Definition: winbase.h:292
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define ReadConsoleInput
Definition: wincon.h:1048
#define KEY_EVENT
Definition: wincon.h:156
void * arg
Definition: msvc.h:10
#define LoadString
Definition: winuser.h:5985