[FULLFAT]
[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 *arg = oldarg;
198 return FALSE;
199 }
200
201 /* save new entry */
202 (*arg)[*ac] = q;
203 (*arg)[++(*ac)] = NULL;
204
205 return TRUE;
206 }
207
208 static BOOL expand (LPINT ac, LPTSTR **arg, LPCTSTR pattern)
209 {
210 HANDLE hFind;
211 WIN32_FIND_DATA FindData;
212 BOOL ok;
213 LPCTSTR pathend;
214 LPTSTR dirpart, fullname;
215
216 pathend = _tcsrchr (pattern, _T('\\'));
217 if (NULL != pathend)
218 {
219 dirpart = cmd_alloc((pathend - pattern + 2) * sizeof(TCHAR));
220 if (NULL == dirpart)
221 {
222 return FALSE;
223 }
224 memcpy(dirpart, pattern, pathend - pattern + 1);
225 dirpart[pathend - pattern + 1] = _T('\0');
226 }
227 else
228 {
229 dirpart = NULL;
230 }
231 hFind = FindFirstFile (pattern, &FindData);
232 if (INVALID_HANDLE_VALUE != hFind)
233 {
234 do
235 {
236 if (NULL != dirpart)
237 {
238 fullname = cmd_alloc((_tcslen(dirpart) + _tcslen(FindData.cFileName) + 1) * sizeof(TCHAR));
239 if (NULL == fullname)
240 {
241 ok = FALSE;
242 }
243 else
244 {
245 _tcscat (_tcscpy (fullname, dirpart), FindData.cFileName);
246 ok = add_entry(ac, arg, fullname);
247 cmd_free (fullname);
248 }
249 }
250 else
251 {
252 ok = add_entry(ac, arg, FindData.cFileName);
253 }
254 } while (FindNextFile (hFind, &FindData) && ok);
255 FindClose (hFind);
256 }
257 else
258 {
259 ok = add_entry(ac, arg, pattern);
260 }
261
262 if (NULL != dirpart)
263 {
264 cmd_free (dirpart);
265 }
266
267 return ok;
268 }
269
270 /*
271 * split - splits a line up into separate arguments, deliminators
272 * are spaces and slashes ('/').
273 */
274 LPTSTR *split (LPTSTR s, LPINT args, BOOL expand_wildcards, BOOL handle_plus)
275 {
276 LPTSTR *arg;
277 LPTSTR start;
278 LPTSTR q;
279 INT ac;
280 INT_PTR len;
281
282 arg = cmd_alloc (sizeof (LPTSTR));
283 if (!arg)
284 return NULL;
285 *arg = NULL;
286
287 ac = 0;
288 while (*s)
289 {
290 BOOL bQuoted = FALSE;
291
292 /* skip leading spaces */
293 while (*s && (_istspace(*s) || _istcntrl(*s)))
294 ++s;
295
296 start = s;
297
298 /* the first character can be '/' */
299 if (*s == _T('/'))
300 ++s;
301
302 /* skip to next word delimiter or start of next option */
303 while (_istprint(*s))
304 {
305 /* if quote (") then set bQuoted */
306 bQuoted ^= (*s == _T('\"'));
307
308 /* Check if we have unquoted text */
309 if (!bQuoted)
310 {
311 /* check for separators */
312 if (_istspace(*s) ||
313 (*s == _T('/')) ||
314 (handle_plus && (*s == _T('+'))))
315 {
316 /* Make length at least one character */
317 if (s == start) s++;
318 break;
319 }
320 }
321
322 ++s;
323 }
324
325 /* a word was found */
326 if (s != start)
327 {
328 q = cmd_alloc (((len = s - start) + 1) * sizeof (TCHAR));
329 if (!q)
330 {
331 return NULL;
332 }
333 memcpy (q, start, len * sizeof (TCHAR));
334 q[len] = _T('\0');
335 StripQuotes(q);
336 if (expand_wildcards && (_T('/') != *start) &&
337 (NULL != _tcschr(q, _T('*')) || NULL != _tcschr(q, _T('?'))))
338 {
339 if (! expand(&ac, &arg, q))
340 {
341 cmd_free (q);
342 freep (arg);
343 return NULL;
344 }
345 }
346 else
347 {
348 if (! add_entry(&ac, &arg, q))
349 {
350 cmd_free (q);
351 freep (arg);
352 return NULL;
353 }
354 }
355 cmd_free (q);
356 }
357 }
358
359 *args = ac;
360
361 return arg;
362 }
363
364 /*
365 * splitspace() is a function which uses JUST spaces as delimeters. split() uses "/" AND spaces.
366 * The way it works is real similar to split(), search the difference ;)
367 * splitspace is needed for commands such as "move" where paths as C:\this/is\allowed/ are allowed
368 */
369 LPTSTR *splitspace (LPTSTR s, LPINT args)
370 {
371 LPTSTR *arg;
372 LPTSTR start;
373 LPTSTR q;
374 INT ac;
375 INT_PTR len;
376
377 arg = cmd_alloc (sizeof (LPTSTR));
378 if (!arg)
379 return NULL;
380 *arg = NULL;
381
382 ac = 0;
383 while (*s)
384 {
385 BOOL bQuoted = FALSE;
386
387 /* skip leading spaces */
388 while (*s && (_istspace (*s) || _istcntrl (*s)))
389 ++s;
390
391 start = s;
392
393 /* skip to next word delimiter or start of next option */
394 while (_istprint(*s) && (bQuoted || !_istspace(*s)))
395 {
396 /* if quote (") then set bQuoted */
397 bQuoted ^= (*s == _T('\"'));
398 ++s;
399 }
400
401 /* a word was found */
402 if (s != start)
403 {
404 q = cmd_alloc (((len = s - start) + 1) * sizeof (TCHAR));
405 if (!q)
406 {
407 return NULL;
408 }
409 memcpy (q, start, len * sizeof (TCHAR));
410 q[len] = _T('\0');
411 StripQuotes(q);
412 if (! add_entry(&ac, &arg, q))
413 {
414 cmd_free (q);
415 freep (arg);
416 return NULL;
417 }
418 cmd_free (q);
419 }
420 }
421
422 *args = ac;
423
424 return arg;
425 }
426
427 /*
428 * freep -- frees memory used for a call to split
429 */
430 VOID freep (LPTSTR *p)
431 {
432 LPTSTR *q;
433
434 if (!p)
435 return;
436
437 q = p;
438 while (*q)
439 cmd_free(*q++);
440
441 cmd_free(p);
442 }
443
444 LPTSTR _stpcpy (LPTSTR dest, LPCTSTR src)
445 {
446 _tcscpy (dest, src);
447 return (dest + _tcslen (src));
448 }
449
450 VOID
451 StripQuotes(TCHAR *in)
452 {
453 TCHAR *out = in;
454 for (; *in; in++)
455 {
456 if (*in != _T('"'))
457 *out++ = *in;
458 }
459 *out = _T('\0');
460 }
461
462
463 /*
464 * Checks if a path is valid (accessible)
465 */
466 BOOL IsValidPathName (LPCTSTR pszPath)
467 {
468 TCHAR szOldPath[MAX_PATH];
469 BOOL bResult;
470
471 GetCurrentDirectory (MAX_PATH, szOldPath);
472 bResult = SetCurrentDirectory (pszPath);
473
474 SetCurrentDirectory (szOldPath);
475
476 return bResult;
477 }
478
479
480 /*
481 * Checks if a file exists (accessible)
482 */
483 BOOL IsExistingFile (LPCTSTR pszPath)
484 {
485 DWORD attr = GetFileAttributes (pszPath);
486 return (attr != 0xFFFFFFFF && (! (attr & FILE_ATTRIBUTE_DIRECTORY)) );
487 }
488
489
490 BOOL IsExistingDirectory (LPCTSTR pszPath)
491 {
492 DWORD attr = GetFileAttributes (pszPath);
493 return (attr != 0xFFFFFFFF && (attr & FILE_ATTRIBUTE_DIRECTORY) );
494 }
495
496
497 BOOL FileGetString (HANDLE hFile, LPTSTR lpBuffer, INT nBufferLength)
498 {
499 LPSTR lpString;
500 DWORD dwRead;
501 INT len = 0;
502 #ifdef _UNICODE
503 lpString = cmd_alloc(nBufferLength);
504 #else
505 lpString = lpBuffer;
506 #endif
507
508 if (ReadFile(hFile, lpString, nBufferLength - 1, &dwRead, NULL))
509 {
510 /* break at new line*/
511 CHAR *end = memchr(lpString, '\n', dwRead);
512 len = dwRead;
513 if (end)
514 {
515 len = (INT)(end - lpString) + 1;
516 SetFilePointer(hFile, len - dwRead, NULL, FILE_CURRENT);
517 }
518 }
519
520 if (!len)
521 {
522 #ifdef _UNICODE
523 cmd_free(lpString);
524 #endif
525 return FALSE;
526 }
527
528 lpString[len++] = '\0';
529 #ifdef _UNICODE
530 MultiByteToWideChar(OutputCodePage, 0, lpString, -1, lpBuffer, len);
531 cmd_free(lpString);
532 #endif
533 return TRUE;
534 }
535
536 INT PagePrompt(VOID)
537 {
538 INPUT_RECORD ir;
539
540 ConOutResPuts(STRING_MISC_HELP1);
541
542 RemoveBreakHandler();
543 ConInDisable();
544
545 do
546 {
547 ConInKey(&ir);
548 }
549 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
550 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
551 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
552
553 AddBreakHandler();
554 ConInEnable();
555
556 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
557 ((ir.Event.KeyEvent.wVirtualKeyCode == _T('C')) &&
558 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
559 {
560 bCtrlBreak = TRUE;
561 return PROMPT_BREAK;
562 }
563
564 return PROMPT_YES;
565 }
566
567
568 INT FilePromptYN (UINT resID)
569 {
570 TCHAR szMsg[RC_STRING_MAX_SIZE];
571 // TCHAR cKey = 0;
572 // LPTSTR szKeys = _T("yna");
573
574 TCHAR szIn[10];
575 LPTSTR p;
576
577 if (resID != 0)
578 ConOutResPrintf (resID);
579
580 /* preliminary fix */
581 ConInString(szIn, 10);
582 ConOutChar(_T('\n'));
583
584 _tcsupr (szIn);
585 for (p = szIn; _istspace (*p); p++)
586 ;
587
588 LoadString(CMD_ModuleHandle, STRING_CHOICE_OPTION, szMsg, RC_STRING_MAX_SIZE);
589
590 if (_tcsncmp(p, &szMsg[0], 1) == 0)
591 return PROMPT_YES;
592 else if (_tcsncmp(p, &szMsg[1], 1) == 0)
593 return PROMPT_NO;
594 #if 0
595 else if (*p == _T('\03'))
596 return PROMPT_BREAK;
597 #endif
598
599 return PROMPT_NO;
600
601 /* unfinished solution */
602 #if 0
603 RemoveBreakHandler();
604 ConInDisable();
605
606 do
607 {
608 ConInKey (&ir);
609 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar);
610 if (_tcschr (szKeys, cKey[0]) == NULL)
611 cKey = 0;
612
613
614 }
615 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
616 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
617 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
618
619 AddBreakHandler();
620 ConInEnable();
621
622 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
623 ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') &&
624 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
625 return PROMPT_BREAK;
626
627 return PROMPT_YES;
628 #endif
629 }
630
631
632 INT FilePromptYNA (UINT resID)
633 {
634 TCHAR szMsg[RC_STRING_MAX_SIZE];
635 // TCHAR cKey = 0;
636 // LPTSTR szKeys = _T("yna");
637
638 TCHAR szIn[10];
639 LPTSTR p;
640
641 if (resID != 0)
642 ConOutResPrintf (resID);
643
644 /* preliminary fix */
645 ConInString(szIn, 10);
646 ConOutChar(_T('\n'));
647
648 _tcsupr (szIn);
649 for (p = szIn; _istspace (*p); p++)
650 ;
651
652 LoadString( CMD_ModuleHandle, STRING_COPY_OPTION, szMsg, RC_STRING_MAX_SIZE);
653
654 if (_tcsncmp(p, &szMsg[0], 1) == 0)
655 return PROMPT_YES;
656 else if (_tcsncmp(p, &szMsg[1], 1) == 0)
657 return PROMPT_NO;
658 else if (_tcsncmp(p, &szMsg[2], 1) == 0)
659 return PROMPT_ALL;
660 #if 0
661 else if (*p == _T('\03'))
662 return PROMPT_BREAK;
663 #endif
664
665 return PROMPT_NO;
666
667 /* unfinished solution */
668 #if 0
669 RemoveBreakHandler();
670 ConInDisable();
671
672 do
673 {
674 ConInKey (&ir);
675 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar);
676 if (_tcschr (szKeys, cKey[0]) == NULL)
677 cKey = 0;
678 }
679 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
680 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
681 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
682
683 AddBreakHandler();
684 ConInEnable();
685
686 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
687 ((ir.Event.KeyEvent.wVirtualKeyCode == _T('C')) &&
688 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
689 return PROMPT_BREAK;
690
691 return PROMPT_YES;
692 #endif
693 }
694
695 /* EOF */