Use FileGetString instead of ReadFile, because ReadFile doesn't return a null termina...
[reactos.git] / reactos / subsys / system / cmd / misc.c
1 /*
2 * MISC.C - misc. functions.
3 *
4 *
5 * History:
6 *
7 * 07/12/98 (Rob Lake)
8 * started
9 *
10 * 07/13/98 (Rob Lake)
11 * moved functions in here
12 *
13 * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
14 * added config.h include
15 *
16 * 18-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
17 * Changed split() to accept quoted arguments.
18 * Removed parse_firstarg().
19 *
20 * 23-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
21 * Fixed an ugly bug in split(). In rare cases (last character
22 * of the string is a space) it ignored the NULL character and
23 * tried to add the following to the argument list.
24 *
25 * 28-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
26 * FileGetString() seems to be working now.
27 *
28 * 06-Nov-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
29 * Added PagePrompt() and FilePrompt().
30 *
31 * 30-Apr-2005 (Magnus Olsen) <magnus@greatlord.com>)
32 * Remove all hardcode string to En.rc
33 */
34
35 #include <precomp.h>
36 #include "resource.h"
37
38
39 /*
40 * get a character out-of-band and honor Ctrl-Break characters
41 */
42 TCHAR cgetchar (VOID)
43 {
44 HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE);
45 INPUT_RECORD irBuffer;
46 DWORD dwRead;
47
48 do
49 {
50 ReadConsoleInput (hInput, &irBuffer, 1, &dwRead);
51 if ((irBuffer.EventType == KEY_EVENT) &&
52 (irBuffer.Event.KeyEvent.bKeyDown == TRUE))
53 {
54 if ((irBuffer.Event.KeyEvent.dwControlKeyState &
55 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) &
56 (irBuffer.Event.KeyEvent.wVirtualKeyCode == 'C'))
57 bCtrlBreak = TRUE;
58
59 break;
60 }
61 }
62 while (TRUE);
63
64 #ifndef _UNICODE
65 return irBuffer.Event.KeyEvent.uChar.AsciiChar;
66 #else
67 return irBuffer.Event.KeyEvent.uChar.UnicodeChar;
68 #endif /* _UNICODE */
69 }
70
71
72 /*
73 * Check if Ctrl-Break was pressed during the last calls
74 */
75
76 BOOL CheckCtrlBreak (INT mode)
77 {
78 static BOOL bLeaveAll = FALSE; /* leave all batch files */
79 TCHAR c;
80
81 switch (mode)
82 {
83 case BREAK_OUTOFBATCH:
84 bLeaveAll = 0;
85 return FALSE;
86
87 case BREAK_BATCHFILE:
88 if (bLeaveAll)
89 return TRUE;
90
91 if (!bCtrlBreak)
92 return FALSE;
93
94 /* we need to be sure the string arrives on the screen! */
95 do
96 ConOutPuts (_T("\r\nCtrl-Break pressed. Cancel batch file? (Yes/No/All) "));
97 while (!_tcschr (_T("YNA\3"), c = _totupper (cgetchar())) || !c);
98
99 ConOutPuts (_T("\r\n"));
100
101 if (c == _T('N'))
102 return bCtrlBreak = FALSE; /* ignore */
103
104 /* leave all batch files */
105 bLeaveAll = ((c == _T('A')) || (c == _T('\3')));
106 break;
107
108 case BREAK_INPUT:
109 if (!bCtrlBreak)
110 return FALSE;
111 break;
112 }
113
114 /* state processed */
115 bCtrlBreak = FALSE;
116 return TRUE;
117 }
118
119 /* add new entry for new argument */
120 static BOOL add_entry (LPINT ac, LPTSTR **arg, LPCTSTR entry)
121 {
122 LPTSTR q;
123 LPTSTR *oldarg;
124
125 q = malloc ((_tcslen(entry) + 1) * sizeof (TCHAR));
126 if (NULL == q)
127 {
128 return FALSE;
129 }
130 _tcscpy (q, entry);
131
132 oldarg = *arg;
133 *arg = realloc (oldarg, (*ac + 2) * sizeof (LPTSTR));
134 if (NULL == *arg)
135 {
136 *arg = oldarg;
137 return FALSE;
138 }
139
140 /* save new entry */
141 (*arg)[*ac] = q;
142 (*arg)[++(*ac)] = NULL;
143
144 return TRUE;
145 }
146
147 static BOOL expand (LPINT ac, LPTSTR **arg, LPCTSTR pattern)
148 {
149 HANDLE hFind;
150 WIN32_FIND_DATA FindData;
151 BOOL ok;
152 LPCTSTR pathend;
153 LPTSTR dirpart, fullname;
154
155 pathend = _tcsrchr (pattern, _T('\\'));
156 if (NULL != pathend)
157 {
158 dirpart = malloc((pathend - pattern + 2) * sizeof(TCHAR));
159 if (NULL == dirpart)
160 {
161 return FALSE;
162 }
163 memcpy(dirpart, pattern, pathend - pattern + 1);
164 dirpart[pathend - pattern + 1] = '\0';
165 }
166 else
167 {
168 dirpart = NULL;
169 }
170 hFind = FindFirstFile (pattern, &FindData);
171 if (INVALID_HANDLE_VALUE != hFind)
172 {
173 do
174 {
175 if (NULL != dirpart)
176 {
177 fullname = malloc((_tcslen(dirpart) + _tcslen(FindData.cFileName) + 1) * sizeof(TCHAR));
178 if (NULL == fullname)
179 {
180 ok = FALSE;
181 }
182 else
183 {
184 _tcscat (_tcscpy (fullname, dirpart), FindData.cFileName);
185 ok = add_entry(ac, arg, fullname);
186 free (fullname);
187 }
188 }
189 else
190 {
191 ok = add_entry(ac, arg, FindData.cFileName);
192 }
193 } while (FindNextFile (hFind, &FindData) && ok);
194 FindClose (hFind);
195 }
196 else
197 {
198 ok = add_entry(ac, arg, pattern);
199 }
200
201 if (NULL != dirpart)
202 {
203 free (dirpart);
204 }
205
206 return ok;
207 }
208
209 /*
210 * split - splits a line up into separate arguments, deliminators
211 * are spaces and slashes ('/').
212 */
213
214 LPTSTR *split (LPTSTR s, LPINT args, BOOL expand_wildcards)
215 {
216 LPTSTR *arg;
217 LPTSTR start;
218 LPTSTR q;
219 INT ac;
220 INT len;
221 BOOL bQuoted = FALSE;
222
223 arg = malloc (sizeof (LPTSTR));
224 if (!arg)
225 return NULL;
226 *arg = NULL;
227
228 ac = 0;
229 while (*s)
230 {
231 /* skip leading spaces */
232 while (*s && (_istspace (*s) || _istcntrl (*s)))
233 ++s;
234
235 /* if quote (") then set bQuoted */
236 if (*s == _T('\"'))
237 {
238 ++s;
239 bQuoted = TRUE;
240 }
241
242 start = s;
243
244 /* the first character can be '/' */
245 if (*s == _T('/'))
246 ++s;
247
248 /* skip to next word delimiter or start of next option */
249 if (bQuoted)
250 {
251 while (_istprint (*s) && (*s != _T('\"')) && (*s != _T('/')))
252 ++s;
253 }
254 else
255 {
256 while (_istprint (*s) && !_istspace (*s) && (*s != _T('/')))
257 ++s;
258 }
259
260 /* a word was found */
261 if (s != start)
262 {
263 q = malloc (((len = s - start) + 1) * sizeof (TCHAR));
264 if (!q)
265 {
266 return NULL;
267 }
268 memcpy (q, start, len * sizeof (TCHAR));
269 q[len] = _T('\0');
270 if (expand_wildcards && _T('/') != *start &&
271 (NULL != _tcschr(q, _T('*')) || NULL != _tcschr(q, _T('?'))))
272 {
273 if (! expand(&ac, &arg, q))
274 {
275 free (q);
276 freep (arg);
277 return NULL;
278 }
279 }
280 else
281 {
282 if (! add_entry(&ac, &arg, q))
283 {
284 free (q);
285 freep (arg);
286 return NULL;
287 }
288 }
289 free (q);
290 }
291
292 /* adjust string pointer if quoted (") */
293 if (bQuoted)
294 {
295 ++s;
296 bQuoted = FALSE;
297 }
298 }
299
300 *args = ac;
301
302 return arg;
303 }
304
305
306 /*
307 * freep -- frees memory used for a call to split
308 *
309 */
310 VOID freep (LPTSTR *p)
311 {
312 LPTSTR *q;
313
314 if (!p)
315 return;
316
317 q = p;
318 while (*q)
319 free(*q++);
320
321 free(p);
322 }
323
324
325 LPTSTR _stpcpy (LPTSTR dest, LPTSTR src)
326 {
327 _tcscpy (dest, src);
328 return (dest + _tcslen (src));
329 }
330
331
332
333 /*
334 * Checks if a path is valid (accessible)
335 */
336
337 BOOL IsValidPathName (LPCTSTR pszPath)
338 {
339 TCHAR szOldPath[MAX_PATH];
340 BOOL bResult;
341
342 GetCurrentDirectory (MAX_PATH, szOldPath);
343 bResult = SetCurrentDirectory (pszPath);
344
345 SetCurrentDirectory (szOldPath);
346
347 return bResult;
348 }
349
350
351 /*
352 * Checks if a file exists (accessible)
353 */
354
355 BOOL IsExistingFile (LPCTSTR pszPath)
356 {
357 DWORD attr = GetFileAttributes (pszPath);
358 return (attr != 0xFFFFFFFF && (! (attr & FILE_ATTRIBUTE_DIRECTORY)) );
359 }
360
361
362 BOOL IsExistingDirectory (LPCTSTR pszPath)
363 {
364 DWORD attr = GetFileAttributes (pszPath);
365 return (attr != 0xFFFFFFFF && (attr & FILE_ATTRIBUTE_DIRECTORY) );
366 }
367
368
369 BOOL FileGetString (HANDLE hFile, LPTSTR lpBuffer, INT nBufferLength)
370 {
371 LPSTR lpString;
372 CHAR ch;
373 DWORD dwRead;
374 INT len;
375 #ifdef _UNICODE
376 lpString = malloc(nBufferLength);
377 #else
378 lpString = lpBuffer;
379 #endif
380 len = 0;
381 while ((--nBufferLength > 0) &&
382 ReadFile(hFile, &ch, 1, &dwRead, NULL) && dwRead)
383 {
384 if (ch == '\r')
385 {
386 /* overread '\n' */
387 ReadFile (hFile, &ch, 1, &dwRead, NULL);
388 break;
389 }
390 lpString[len++] = ch;
391 }
392
393 if (!dwRead && !len)
394 return FALSE;
395
396 lpString[len++] = '\0';
397 #ifdef _UNICODE
398 MultiByteToWideChar(CP_ACP, 0, lpString, len, lpBuffer, len);
399 free(lpString);
400 #endif
401 return TRUE;
402 }
403
404 #ifndef __REACTOS__
405 /*
406 * GetConsoleWindow - returns the handle to the current console window
407 */
408 HWND GetConsoleWindow (VOID)
409 {
410 TCHAR original[256];
411 TCHAR temp[256];
412 HWND h=0;
413
414 if(h)
415 return h;
416
417 GetConsoleTitle (original, sizeof(original) / sizeof(TCHAR));
418
419 _tcscpy (temp, original);
420 _tcscat (temp, _T("-xxx "));
421
422 if (FindWindow (0, temp) == NULL )
423 {
424 SetConsoleTitle (temp);
425 Sleep (0);
426
427 while(!(h = FindWindow (0, temp)))
428 ;
429
430 SetConsoleTitle (original);
431 }
432
433 return h;
434 }
435 #endif
436
437
438 INT PagePrompt (VOID)
439 {
440 INPUT_RECORD ir;
441
442 ConOutResPuts(STRING_MISC_HELP1);
443
444 RemoveBreakHandler ();
445 ConInDisable ();
446
447 do
448 {
449 ConInKey (&ir);
450 }
451 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
452 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
453 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
454
455 AddBreakHandler ();
456 ConInEnable ();
457
458 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
459 ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') &&
460 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
461 return PROMPT_BREAK;
462
463 return PROMPT_YES;
464 }
465
466
467 INT FilePromptYN (LPTSTR szFormat, ...)
468 {
469 TCHAR szMsg[RC_STRING_MAX_SIZE];
470 TCHAR szOut[512];
471 va_list arg_ptr;
472 // TCHAR cKey = 0;
473 // LPTSTR szKeys = _T("yna");
474
475 TCHAR szIn[10];
476 LPTSTR p;
477
478 va_start (arg_ptr, szFormat);
479 _vstprintf (szOut, szFormat, arg_ptr);
480 va_end (arg_ptr);
481
482 ConOutPrintf (szFormat);
483
484 /* preliminary fix */
485 ConInString (szIn, 10);
486 ConOutPrintf (_T("\n"));
487
488 _tcsupr (szIn);
489 for (p = szIn; _istspace (*p); p++)
490 ;
491
492 LoadString(CMD_ModuleHandle, STRING_CHOICE_OPTION, szMsg, RC_STRING_MAX_SIZE);
493
494 if (_tcsncmp(p, &szMsg[0], 1) == 0)
495 return PROMPT_YES;
496 else if (_tcsncmp(p, &szMsg[1], 1) == 0)
497 return PROMPT_NO;
498 #if 0
499 else if (*p == _T('\03'))
500 return PROMPT_BREAK;
501 #endif
502
503 return PROMPT_NO;
504
505
506 /* unfinished sollution */
507 #if 0
508 RemoveBreakHandler ();
509 ConInDisable ();
510
511 do
512 {
513 ConInKey (&ir);
514 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar);
515 if (_tcschr (szKeys, cKey[0]) == NULL)
516 cKey = 0;
517
518
519 }
520 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
521 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
522 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
523
524 AddBreakHandler ();
525 ConInEnable ();
526
527 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
528 ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') &&
529 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
530 return PROMPT_BREAK;
531
532 return PROMPT_YES;
533 #endif
534 }
535
536
537 INT FilePromptYNA (LPTSTR szFormat, ...)
538 {
539 TCHAR szMsg[RC_STRING_MAX_SIZE];
540 TCHAR szOut[512];
541 va_list arg_ptr;
542 // TCHAR cKey = 0;
543 // LPTSTR szKeys = _T("yna");
544
545 TCHAR szIn[10];
546 LPTSTR p;
547
548 va_start (arg_ptr, szFormat);
549 _vstprintf (szOut, szFormat, arg_ptr);
550 va_end (arg_ptr);
551
552 ConOutPrintf (szFormat);
553
554 /* preliminary fix */
555 ConInString (szIn, 10);
556 ConOutPrintf (_T("\n"));
557
558 _tcsupr (szIn);
559 for (p = szIn; _istspace (*p); p++)
560 ;
561
562 LoadString( CMD_ModuleHandle, STRING_COPY_OPTION, szMsg, RC_STRING_MAX_SIZE);
563
564 if (_tcsncmp(p, &szMsg[0], 1) == 0)
565 return PROMPT_YES;
566 else if (_tcsncmp(p, &szMsg[1], 1) == 0)
567 return PROMPT_NO;
568 else if (_tcsncmp(p, &szMsg[2], 1) == 0)
569 return PROMPT_ALL;
570
571 #if 0
572 else if (*p == _T('\03'))
573 return PROMPT_BREAK;
574 #endif
575
576 return PROMPT_NO;
577
578
579 /* unfinished sollution */
580 #if 0
581 RemoveBreakHandler ();
582 ConInDisable ();
583
584 do
585 {
586 ConInKey (&ir);
587 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar);
588 if (_tcschr (szKeys, cKey[0]) == NULL)
589 cKey = 0;
590 }
591 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
592 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
593 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
594
595 AddBreakHandler ();
596 ConInEnable ();
597
598 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
599 ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') &&
600 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
601 return PROMPT_BREAK;
602
603 return PROMPT_YES;
604 #endif
605 }
606
607 /* EOF */