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