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
31 static INT
GetCharacterTimeout(LPTCH ch,DWORD dwMilliseconds)32 GetCharacterTimeout (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
46 INPUT_RECORD lpBuffer;
47
48 hInput = GetStdHandle (STD_INPUT_HANDLE);
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 ReadConsoleInput (hInput, &lpBuffer, 1, &dwRead);
56
57 //if the event is a key pressed
58 if ((lpBuffer.EventType == KEY_EVENT) &&
59 (lpBuffer.Event.KeyEvent.bKeyDown != FALSE))
60 {
61 //read the key
62 #ifdef _UNICODE
63 *ch = lpBuffer.Event.KeyEvent.uChar.UnicodeChar;
64 #else
65 *ch = lpBuffer.Event.KeyEvent.uChar.AsciiChar;
66 #endif
67 return GC_KEYREAD;
68 }
69
70 //else return no key
71 return GC_NOKEY;
72 }
73
74 static INT
IsKeyInString(LPTSTR lpString,TCHAR cKey,BOOL bCaseSensitive)75 IsKeyInString (LPTSTR lpString, TCHAR cKey, BOOL bCaseSensitive)
76 {
77 LPTCH p = lpString;
78 INT val = 0;
79
80 while (*p)
81 {
82 if (bCaseSensitive)
83 {
84 if (*p == cKey)
85 return val;
86 }
87 else
88 {
89 if (_totlower (*p) == _totlower (cKey))
90 return val;
91 }
92
93 val++;
94 p++;
95 }
96
97 return -1;
98 }
99
100
101 INT
CommandChoice(LPTSTR param)102 CommandChoice (LPTSTR param)
103 {
104 LPTSTR lpOptions;
105 TCHAR Options[6];
106 LPTSTR lpText = NULL;
107 BOOL bNoPrompt = FALSE;
108 BOOL bCaseSensitive = FALSE;
109 BOOL bTimeout = FALSE;
110 INT nTimeout = 0;
111 TCHAR cDefault = _T('\0');
112 INPUT_RECORD ir;
113 LPTSTR p, np;
114 LPTSTR *arg;
115 INT argc;
116 INT i;
117 INT val;
118
119 INT GCret;
120 TCHAR Ch;
121 DWORD amount,clk;
122
123 LoadString(CMD_ModuleHandle, STRING_CHOICE_OPTION, Options, 4);
124 lpOptions = Options;
125
126 if (_tcsncmp (param, _T("/?"), 2) == 0)
127 {
128 ConOutResPaging(TRUE,STRING_CHOICE_HELP);
129 return 0;
130 }
131
132 /* retrieve text */
133 p = param;
134
135 while (TRUE)
136 {
137 if (*p == _T('\0'))
138 break;
139
140 if (*p != _T('/'))
141 {
142 lpText = p;
143 break;
144 }
145 np = _tcschr (p, _T(' '));
146 if (!np)
147 break;
148 p = np + 1;
149 }
150
151 /* build parameter array */
152 arg = split (param, &argc, FALSE, FALSE);
153
154 /* evaluate arguments */
155 if (argc > 0)
156 {
157 for (i = 0; i < argc; i++)
158 {
159 if (_tcsnicmp (arg[i], _T("/c"), 2) == 0)
160 {
161 if (arg[i][2] == _T(':'))
162 lpOptions = &arg[i][3];
163 else
164 lpOptions = &arg[i][2];
165
166 if (_tcslen (lpOptions) == 0)
167 {
168 ConErrResPuts(STRING_CHOICE_ERROR);
169 freep (arg);
170 return 1;
171 }
172 }
173 else if (_tcsnicmp (arg[i], _T("/n"), 2) == 0)
174 {
175 bNoPrompt = TRUE;
176 }
177 else if (_tcsnicmp (arg[i], _T("/s"), 2) == 0)
178 {
179 bCaseSensitive = TRUE;
180 }
181 else if (_tcsnicmp (arg[i], _T("/t"), 2) == 0)
182 {
183 LPTSTR s;
184
185 if (arg[i][2] == _T(':'))
186 {
187 cDefault = arg[i][3];
188 s = &arg[i][4];
189 }
190 else
191 {
192 cDefault = arg[i][2];
193 s = &arg[i][3];
194 }
195
196 if (*s != _T(','))
197 {
198 ConErrResPuts(STRING_CHOICE_ERROR_TXT);
199 freep (arg);
200 return 1;
201 }
202
203 s++;
204 nTimeout = _ttoi(s);
205 bTimeout = TRUE;
206 }
207 else if (arg[i][0] == _T('/'))
208 {
209 ConErrResPrintf(STRING_CHOICE_ERROR_OPTION, arg[i]);
210 freep (arg);
211 return 1;
212 }
213 }
214 }
215
216 /* print text */
217 if (lpText)
218 ConOutPrintf (_T("%s"), lpText);
219
220 /* print options */
221 if (bNoPrompt == FALSE)
222 {
223 ConOutPrintf (_T("[%c"), lpOptions[0]);
224
225 for (i = 1; (unsigned)i < _tcslen (lpOptions); i++)
226 ConOutPrintf (_T(",%c"), lpOptions[i]);
227
228 ConOutPrintf (_T("]?"));
229 }
230
231 ConInFlush ();
232
233 if (!bTimeout)
234 {
235 while (TRUE)
236 {
237 ConInKey (&ir);
238
239 val = IsKeyInString (lpOptions,
240 #ifdef _UNICODE
241 ir.Event.KeyEvent.uChar.UnicodeChar,
242 #else
243 ir.Event.KeyEvent.uChar.AsciiChar,
244 #endif
245 bCaseSensitive);
246
247 if (val >= 0)
248 {
249 ConOutPrintf (_T("%c\n"), lpOptions[val]);
250
251 nErrorLevel = val + 1;
252
253 break;
254 }
255
256 Beep (440, 50);
257 }
258
259 freep (arg);
260 TRACE ("ErrorLevel: %d\n", nErrorLevel);
261 return 0;
262 }
263
264 clk = GetTickCount ();
265 amount = nTimeout*1000;
266
267 loop:
268 GCret = GetCharacterTimeout (&Ch, amount - (GetTickCount () - clk));
269
270 switch (GCret)
271 {
272 case GC_TIMEOUT:
273 TRACE ("GC_TIMEOUT\n");
274 TRACE ("elapsed %d msecs\n", GetTickCount () - clk);
275 break;
276
277 case GC_NOKEY:
278 TRACE ("GC_NOKEY\n");
279 TRACE ("elapsed %d msecs\n", GetTickCount () - clk);
280 goto loop;
281
282 case GC_KEYREAD:
283 TRACE ("GC_KEYREAD\n");
284 TRACE ("elapsed %d msecs\n", GetTickCount () - clk);
285 TRACE ("read %c\n", Ch);
286 if ((val=IsKeyInString(lpOptions,Ch,bCaseSensitive))==-1)
287 {
288 Beep (440, 50);
289 goto loop;
290 }
291 cDefault=Ch;
292 break;
293 }
294
295 TRACE ("exiting wait loop after %d msecs\n",
296 GetTickCount () - clk);
297
298 val = IsKeyInString (lpOptions, cDefault, bCaseSensitive);
299 ConOutPrintf(_T("%c\n"), lpOptions[val]);
300
301 nErrorLevel = val + 1;
302
303 freep (arg);
304
305 TRACE ("ErrorLevel: %d\n", nErrorLevel);
306
307 return 0;
308 }
309 #endif /* INCLUDE_CMD_CHOICE */
310
311 /* EOF */
312