move explorer and cmd. Add a few .rbuild files
[reactos.git] / reactos / base / shell / 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 do
65 {
66 ReadConsoleInput (hInput, &irBuffer, 1, &dwRead);
67
68 if (irBuffer.EventType == KEY_EVENT)
69 {
70 if (irBuffer.Event.KeyEvent.dwControlKeyState &
71 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
72 {
73 if (irBuffer.Event.KeyEvent.wVirtualKeyCode == 'C')
74 {
75 // if (irBuffer.Event.KeyEvent.bKeyDown == TRUE)
76 // {
77 bCtrlBreak = TRUE;
78 break;
79 // }
80 }
81 }
82 else if ((irBuffer.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
83 (irBuffer.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
84 (irBuffer.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL))
85 {
86 ;
87 }
88
89 else
90 {
91 break;
92 }
93 }
94 }
95 while (TRUE);
96
97 #ifndef _UNICODE
98 return irBuffer.Event.KeyEvent.uChar.AsciiChar;
99 #else
100 return irBuffer.Event.KeyEvent.uChar.UnicodeChar;
101 #endif /* _UNICODE */
102 }
103
104 /*
105 * Takes a path in and returns it with the correct case of the letters
106 */
107 VOID GetPathCase( TCHAR * Path, TCHAR * OutPath)
108 {
109 INT i = 0;
110 TCHAR TempPath[MAX_PATH];
111 WIN32_FIND_DATA FindFileData;
112 HANDLE hFind;
113 _tcscpy(TempPath, _T(""));
114 _tcscpy(OutPath, _T(""));
115
116
117 for(i = 0; i < _tcslen(Path); i++)
118 {
119 if(Path[i] != _T('\\'))
120 {
121 _tcsncat(TempPath, &Path[i], 1);
122 if(i != _tcslen(Path) - 1)
123 continue;
124 }
125 /* Handle the base part of the path different.
126 Because if you put it into findfirstfile, it will
127 return your current folder */
128 if(_tcslen(TempPath) == 2 && TempPath[1] == _T(':'))
129 {
130 _tcscat(OutPath, TempPath);
131 _tcscat(OutPath, _T("\\"));
132 _tcscat(TempPath, _T("\\"));
133 }
134 else
135 {
136 hFind = FindFirstFile(TempPath,&FindFileData);
137 if(hFind == INVALID_HANDLE_VALUE)
138 {
139 _tcscpy(OutPath, Path);
140 return;
141 }
142 _tcscat(TempPath, _T("\\"));
143 _tcscat(OutPath, FindFileData.cFileName);
144 _tcscat(OutPath, _T("\\"));
145 CloseHandle(hFind);
146 }
147 }
148 }
149
150 /*
151 * Check if Ctrl-Break was pressed during the last calls
152 */
153
154 BOOL CheckCtrlBreak (INT mode)
155 {
156 static BOOL bLeaveAll = FALSE; /* leave all batch files */
157 TCHAR c;
158
159 switch (mode)
160 {
161 case BREAK_OUTOFBATCH:
162 bLeaveAll = 0;
163 return FALSE;
164
165 case BREAK_BATCHFILE:
166 if (bLeaveAll)
167 return TRUE;
168
169 if (!bCtrlBreak)
170 return FALSE;
171
172 /* we need to be sure the string arrives on the screen! */
173 do
174 ConOutPuts (_T("\r\nCtrl-Break pressed. Cancel batch file? (Yes/No/All) "));
175 while (!_tcschr (_T("YNA\3"), c = _totupper (cgetchar())) || !c);
176
177 ConOutPuts (_T("\r\n"));
178
179 if (c == _T('N'))
180 return bCtrlBreak = FALSE; /* ignore */
181
182 /* leave all batch files */
183 bLeaveAll = ((c == _T('A')) || (c == _T('\3')));
184 break;
185
186 case BREAK_INPUT:
187 if (!bCtrlBreak)
188 return FALSE;
189 break;
190 }
191
192 /* state processed */
193 bCtrlBreak = FALSE;
194 return TRUE;
195 }
196
197 /* add new entry for new argument */
198 BOOL add_entry (LPINT ac, LPTSTR **arg, LPCTSTR entry)
199 {
200 LPTSTR q;
201 LPTSTR *oldarg;
202
203 q = malloc ((_tcslen(entry) + 1) * sizeof (TCHAR));
204 if (NULL == q)
205 {
206 return FALSE;
207 }
208 _tcscpy (q, entry);
209
210 oldarg = *arg;
211 *arg = realloc (oldarg, (*ac + 2) * sizeof (LPTSTR));
212 if (NULL == *arg)
213 {
214 *arg = oldarg;
215 return FALSE;
216 }
217
218 /* save new entry */
219 (*arg)[*ac] = q;
220 (*arg)[++(*ac)] = NULL;
221
222 return TRUE;
223 }
224
225 static BOOL expand (LPINT ac, LPTSTR **arg, LPCTSTR pattern)
226 {
227 HANDLE hFind;
228 WIN32_FIND_DATA FindData;
229 BOOL ok;
230 LPCTSTR pathend;
231 LPTSTR dirpart, fullname;
232
233 pathend = _tcsrchr (pattern, _T('\\'));
234 if (NULL != pathend)
235 {
236 dirpart = malloc((pathend - pattern + 2) * sizeof(TCHAR));
237 if (NULL == dirpart)
238 {
239 return FALSE;
240 }
241 memcpy(dirpart, pattern, pathend - pattern + 1);
242 dirpart[pathend - pattern + 1] = _T('\0');
243 }
244 else
245 {
246 dirpart = NULL;
247 }
248 hFind = FindFirstFile (pattern, &FindData);
249 if (INVALID_HANDLE_VALUE != hFind)
250 {
251 do
252 {
253 if (NULL != dirpart)
254 {
255 fullname = malloc((_tcslen(dirpart) + _tcslen(FindData.cFileName) + 1) * sizeof(TCHAR));
256 if (NULL == fullname)
257 {
258 ok = FALSE;
259 }
260 else
261 {
262 _tcscat (_tcscpy (fullname, dirpart), FindData.cFileName);
263 ok = add_entry(ac, arg, fullname);
264 free (fullname);
265 }
266 }
267 else
268 {
269 ok = add_entry(ac, arg, FindData.cFileName);
270 }
271 } while (FindNextFile (hFind, &FindData) && ok);
272 FindClose (hFind);
273 }
274 else
275 {
276 ok = add_entry(ac, arg, pattern);
277 }
278
279 if (NULL != dirpart)
280 {
281 free (dirpart);
282 }
283
284 return ok;
285 }
286
287 /*
288 * split - splits a line up into separate arguments, deliminators
289 * are spaces and slashes ('/').
290 */
291
292 LPTSTR *split (LPTSTR s, LPINT args, BOOL expand_wildcards)
293 {
294 LPTSTR *arg;
295 LPTSTR start;
296 LPTSTR q;
297 INT ac;
298 INT len;
299 BOOL bQuoted = FALSE;
300
301 arg = malloc (sizeof (LPTSTR));
302 if (!arg)
303 return NULL;
304 *arg = NULL;
305
306 ac = 0;
307 while (*s)
308 {
309 /* skip leading spaces */
310 while (*s && (_istspace (*s) || _istcntrl (*s)))
311 ++s;
312
313 /* if quote (") then set bQuoted */
314 if (*s == _T('\"'))
315 {
316 ++s;
317 bQuoted = TRUE;
318 }
319
320 start = s;
321
322 /* the first character can be '/' */
323 if (*s == _T('/'))
324 ++s;
325
326 /* skip to next word delimiter or start of next option */
327 if (bQuoted)
328 {
329 while (_istprint (*s) && (*s != _T('\"')) && (*s != _T('/')))
330 ++s;
331 }
332 else
333 {
334 while (_istprint (*s) && !_istspace (*s) && (*s != _T('/')))
335 ++s;
336 }
337
338 /* a word was found */
339 if (s != start)
340 {
341 q = malloc (((len = s - start) + 1) * sizeof (TCHAR));
342 if (!q)
343 {
344 return NULL;
345 }
346 memcpy (q, start, len * sizeof (TCHAR));
347 q[len] = _T('\0');
348 if (expand_wildcards && _T('/') != *start &&
349 (NULL != _tcschr(q, _T('*')) || NULL != _tcschr(q, _T('?'))))
350 {
351 if (! expand(&ac, &arg, q))
352 {
353 free (q);
354 freep (arg);
355 return NULL;
356 }
357 }
358 else
359 {
360 if (! add_entry(&ac, &arg, q))
361 {
362 free (q);
363 freep (arg);
364 return NULL;
365 }
366 }
367 free (q);
368 }
369
370 /* adjust string pointer if quoted (") */
371 if (bQuoted)
372 {
373 /* Check to make sure if there is no ending "
374 * we dont run over the null char */
375 if(*s == _T('\0'))
376 {
377 break;
378 }
379 ++s;
380 bQuoted = FALSE;
381 }
382 }
383
384 *args = ac;
385
386 return arg;
387 }
388
389
390 /*
391 * freep -- frees memory used for a call to split
392 *
393 */
394 VOID freep (LPTSTR *p)
395 {
396 LPTSTR *q;
397
398 if (!p)
399 return;
400
401 q = p;
402 while (*q)
403 free(*q++);
404
405 free(p);
406 }
407
408
409 LPTSTR _stpcpy (LPTSTR dest, LPCTSTR src)
410 {
411 _tcscpy (dest, src);
412 return (dest + _tcslen (src));
413 }
414
415
416
417 /*
418 * Checks if a path is valid (accessible)
419 */
420
421 BOOL IsValidPathName (LPCTSTR pszPath)
422 {
423 TCHAR szOldPath[MAX_PATH];
424 BOOL bResult;
425
426 GetCurrentDirectory (MAX_PATH, szOldPath);
427 bResult = SetCurrentDirectory (pszPath);
428
429 SetCurrentDirectory (szOldPath);
430
431 return bResult;
432 }
433
434
435 /*
436 * Checks if a file exists (accessible)
437 */
438
439 BOOL IsExistingFile (LPCTSTR pszPath)
440 {
441 DWORD attr = GetFileAttributes (pszPath);
442 return (attr != 0xFFFFFFFF && (! (attr & FILE_ATTRIBUTE_DIRECTORY)) );
443 }
444
445
446 BOOL IsExistingDirectory (LPCTSTR pszPath)
447 {
448 DWORD attr = GetFileAttributes (pszPath);
449 return (attr != 0xFFFFFFFF && (attr & FILE_ATTRIBUTE_DIRECTORY) );
450 }
451
452
453 BOOL FileGetString (HANDLE hFile, LPTSTR lpBuffer, INT nBufferLength)
454 {
455 LPSTR lpString;
456 CHAR ch;
457 DWORD dwRead;
458 INT len;
459 #ifdef _UNICODE
460 lpString = malloc(nBufferLength);
461 #else
462 lpString = lpBuffer;
463 #endif
464 len = 0;
465 while ((--nBufferLength > 0) &&
466 ReadFile(hFile, &ch, 1, &dwRead, NULL) && dwRead)
467 {
468 lpString[len++] = ch;
469 if ((ch == _T('\n')) || (ch == _T('\r')))
470 {
471 /* break at new line*/
472 break;
473 }
474 }
475
476 if (!dwRead && !len)
477 return FALSE;
478
479 lpString[len++] = _T('\0');
480 #ifdef _UNICODE
481 MultiByteToWideChar(CP_ACP, 0, lpString, len, lpBuffer, len);
482 free(lpString);
483 #endif
484 return TRUE;
485 }
486
487 INT PagePrompt (VOID)
488 {
489 INPUT_RECORD ir;
490
491 ConOutResPuts(STRING_MISC_HELP1);
492
493 RemoveBreakHandler ();
494 ConInDisable ();
495
496 do
497 {
498 ConInKey (&ir);
499 }
500 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
501 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
502 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
503
504 AddBreakHandler ();
505 ConInEnable ();
506
507 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
508 ((ir.Event.KeyEvent.wVirtualKeyCode == _T('C')) &&
509 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
510 {
511 bCtrlBreak = TRUE;
512 return PROMPT_BREAK;
513 }
514
515 return PROMPT_YES;
516 }
517
518
519 INT FilePromptYN (LPTSTR szFormat, ...)
520 {
521 TCHAR szMsg[RC_STRING_MAX_SIZE];
522 TCHAR szOut[512];
523 va_list arg_ptr;
524 // TCHAR cKey = 0;
525 // LPTSTR szKeys = _T("yna");
526
527 TCHAR szIn[10];
528 LPTSTR p;
529
530 va_start (arg_ptr, szFormat);
531 _vstprintf (szOut, szFormat, arg_ptr);
532 va_end (arg_ptr);
533
534 ConOutPrintf (szFormat);
535
536 /* preliminary fix */
537 ConInString (szIn, 10);
538 ConOutPrintf (_T("\n"));
539
540 _tcsupr (szIn);
541 for (p = szIn; _istspace (*p); p++)
542 ;
543
544 LoadString(CMD_ModuleHandle, STRING_CHOICE_OPTION, szMsg, RC_STRING_MAX_SIZE);
545
546 if (_tcsncmp(p, &szMsg[0], 1) == 0)
547 return PROMPT_YES;
548 else if (_tcsncmp(p, &szMsg[1], 1) == 0)
549 return PROMPT_NO;
550 #if 0
551 else if (*p == _T('\03'))
552 return PROMPT_BREAK;
553 #endif
554
555 return PROMPT_NO;
556
557
558 /* unfinished sollution */
559 #if 0
560 RemoveBreakHandler ();
561 ConInDisable ();
562
563 do
564 {
565 ConInKey (&ir);
566 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar);
567 if (_tcschr (szKeys, cKey[0]) == NULL)
568 cKey = 0;
569
570
571 }
572 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
573 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
574 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
575
576 AddBreakHandler ();
577 ConInEnable ();
578
579 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
580 ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') &&
581 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
582 return PROMPT_BREAK;
583
584 return PROMPT_YES;
585 #endif
586 }
587
588
589 INT FilePromptYNA (LPTSTR szFormat, ...)
590 {
591 TCHAR szMsg[RC_STRING_MAX_SIZE];
592 TCHAR szOut[512];
593 va_list arg_ptr;
594 // TCHAR cKey = 0;
595 // LPTSTR szKeys = _T("yna");
596
597 TCHAR szIn[10];
598 LPTSTR p;
599
600 va_start (arg_ptr, szFormat);
601 _vstprintf (szOut, szFormat, arg_ptr);
602 va_end (arg_ptr);
603
604 ConOutPrintf (szFormat);
605
606 /* preliminary fix */
607 ConInString (szIn, 10);
608 ConOutPrintf (_T("\n"));
609
610 _tcsupr (szIn);
611 for (p = szIn; _istspace (*p); p++)
612 ;
613
614 LoadString( CMD_ModuleHandle, STRING_COPY_OPTION, szMsg, RC_STRING_MAX_SIZE);
615
616 if (_tcsncmp(p, &szMsg[0], 1) == 0)
617 return PROMPT_YES;
618 else if (_tcsncmp(p, &szMsg[1], 1) == 0)
619 return PROMPT_NO;
620 else if (_tcsncmp(p, &szMsg[2], 1) == 0)
621 return PROMPT_ALL;
622
623 #if 0
624 else if (*p == _T('\03'))
625 return PROMPT_BREAK;
626 #endif
627
628 return PROMPT_NO;
629
630
631 /* unfinished sollution */
632 #if 0
633 RemoveBreakHandler ();
634 ConInDisable ();
635
636 do
637 {
638 ConInKey (&ir);
639 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar);
640 if (_tcschr (szKeys, cKey[0]) == NULL)
641 cKey = 0;
642 }
643 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
644 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
645 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
646
647 AddBreakHandler ();
648 ConInEnable ();
649
650 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
651 ((ir.Event.KeyEvent.wVirtualKeyCode == _T('C')) &&
652 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
653 return PROMPT_BREAK;
654
655 return PROMPT_YES;
656 #endif
657 }
658
659 /* EOF */