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