Sync with trunk 48067
[reactos.git] / 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 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) && (bQuoted || (!_istspace(*s) && *s != _T('/'))))
308 {
309 /* if quote (") then set bQuoted */
310 bQuoted ^= (*s == _T('\"'));
311 ++s;
312 }
313
314 /* a word was found */
315 if (s != start)
316 {
317 q = cmd_alloc (((len = s - start) + 1) * sizeof (TCHAR));
318 if (!q)
319 {
320 return NULL;
321 }
322 memcpy (q, start, len * sizeof (TCHAR));
323 q[len] = _T('\0');
324 StripQuotes(q);
325 if (expand_wildcards && _T('/') != *start &&
326 (NULL != _tcschr(q, _T('*')) || NULL != _tcschr(q, _T('?'))))
327 {
328 if (! expand(&ac, &arg, q))
329 {
330 cmd_free (q);
331 freep (arg);
332 return NULL;
333 }
334 }
335 else
336 {
337 if (! add_entry(&ac, &arg, q))
338 {
339 cmd_free (q);
340 freep (arg);
341 return NULL;
342 }
343 }
344 cmd_free (q);
345 }
346 }
347
348 *args = ac;
349
350 return arg;
351 }
352
353 /* splitspace() is a function which uses JUST spaces as delimeters. split() uses "/" AND spaces.
354 * The way it works is real similar to split(), search the difference ;)
355 * splitspace is needed for commands such as "move" where paths as C:\this/is\allowed/ are allowed
356 */
357 LPTSTR *splitspace (LPTSTR s, LPINT args)
358 {
359 LPTSTR *arg;
360 LPTSTR start;
361 LPTSTR q;
362 INT ac;
363 INT len;
364
365 arg = cmd_alloc (sizeof (LPTSTR));
366 if (!arg)
367 return NULL;
368 *arg = NULL;
369
370 ac = 0;
371 while (*s)
372 {
373 BOOL bQuoted = FALSE;
374
375 /* skip leading spaces */
376 while (*s && (_istspace (*s) || _istcntrl (*s)))
377 ++s;
378
379 start = s;
380
381 /* skip to next word delimiter or start of next option */
382 while (_istprint(*s) && (bQuoted || !_istspace(*s)))
383 {
384 /* if quote (") then set bQuoted */
385 bQuoted ^= (*s == _T('\"'));
386 ++s;
387 }
388
389 /* a word was found */
390 if (s != start)
391 {
392 q = cmd_alloc (((len = s - start) + 1) * sizeof (TCHAR));
393 if (!q)
394 {
395 return NULL;
396 }
397 memcpy (q, start, len * sizeof (TCHAR));
398 q[len] = _T('\0');
399 StripQuotes(q);
400 if (! add_entry(&ac, &arg, q))
401 {
402 cmd_free (q);
403 freep (arg);
404 return NULL;
405 }
406 cmd_free (q);
407 }
408 }
409
410 *args = ac;
411
412 return arg;
413 }
414
415 /*
416 * freep -- frees memory used for a call to split
417 *
418 */
419 VOID freep (LPTSTR *p)
420 {
421 LPTSTR *q;
422
423 if (!p)
424 return;
425
426 q = p;
427 while (*q)
428 cmd_free(*q++);
429
430 cmd_free(p);
431 }
432
433
434 LPTSTR _stpcpy (LPTSTR dest, LPCTSTR src)
435 {
436 _tcscpy (dest, src);
437 return (dest + _tcslen (src));
438 }
439
440 VOID
441 StripQuotes(TCHAR *in)
442 {
443 TCHAR *out = in;
444 for (; *in; in++)
445 {
446 if (*in != _T('"'))
447 *out++ = *in;
448 }
449 *out = _T('\0');
450 }
451
452
453
454 /*
455 * Checks if a path is valid (accessible)
456 */
457
458 BOOL IsValidPathName (LPCTSTR pszPath)
459 {
460 TCHAR szOldPath[MAX_PATH];
461 BOOL bResult;
462
463 GetCurrentDirectory (MAX_PATH, szOldPath);
464 bResult = SetCurrentDirectory (pszPath);
465
466 SetCurrentDirectory (szOldPath);
467
468 return bResult;
469 }
470
471
472 /*
473 * Checks if a file exists (accessible)
474 */
475
476 BOOL IsExistingFile (LPCTSTR pszPath)
477 {
478 DWORD attr = GetFileAttributes (pszPath);
479 return (attr != 0xFFFFFFFF && (! (attr & FILE_ATTRIBUTE_DIRECTORY)) );
480 }
481
482
483 BOOL IsExistingDirectory (LPCTSTR pszPath)
484 {
485 DWORD attr = GetFileAttributes (pszPath);
486 return (attr != 0xFFFFFFFF && (attr & FILE_ATTRIBUTE_DIRECTORY) );
487 }
488
489
490 BOOL FileGetString (HANDLE hFile, LPTSTR lpBuffer, INT nBufferLength)
491 {
492 LPSTR lpString;
493 DWORD dwRead;
494 INT len = 0;
495 #ifdef _UNICODE
496 lpString = cmd_alloc(nBufferLength);
497 #else
498 lpString = lpBuffer;
499 #endif
500
501 if (ReadFile(hFile, lpString, nBufferLength - 1, &dwRead, NULL))
502 {
503 /* break at new line*/
504 CHAR *end = memchr(lpString, '\n', dwRead);
505 len = dwRead;
506 if (end)
507 {
508 len = (end - lpString) + 1;
509 SetFilePointer(hFile, len - dwRead, NULL, FILE_CURRENT);
510 }
511 }
512
513 if (!len)
514 {
515 #ifdef _UNICODE
516 cmd_free(lpString);
517 #endif
518 return FALSE;
519 }
520
521 lpString[len++] = '\0';
522 #ifdef _UNICODE
523 MultiByteToWideChar(OutputCodePage, 0, lpString, -1, lpBuffer, len);
524 cmd_free(lpString);
525 #endif
526 return TRUE;
527 }
528
529 INT PagePrompt (VOID)
530 {
531 INPUT_RECORD ir;
532
533 ConOutResPuts(STRING_MISC_HELP1);
534
535 RemoveBreakHandler ();
536 ConInDisable ();
537
538 do
539 {
540 ConInKey (&ir);
541 }
542 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
543 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
544 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
545
546 AddBreakHandler ();
547 ConInEnable ();
548
549 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
550 ((ir.Event.KeyEvent.wVirtualKeyCode == _T('C')) &&
551 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
552 {
553 bCtrlBreak = TRUE;
554 return PROMPT_BREAK;
555 }
556
557 return PROMPT_YES;
558 }
559
560
561 INT FilePromptYN (UINT resID)
562 {
563 TCHAR szMsg[RC_STRING_MAX_SIZE];
564 // TCHAR cKey = 0;
565 // LPTSTR szKeys = _T("yna");
566
567 TCHAR szIn[10];
568 LPTSTR p;
569
570 if (resID != 0)
571 ConOutResPrintf (resID);
572
573 /* preliminary fix */
574 ConInString (szIn, 10);
575 ConOutPrintf (_T("\n"));
576
577 _tcsupr (szIn);
578 for (p = szIn; _istspace (*p); p++)
579 ;
580
581 LoadString(CMD_ModuleHandle, STRING_CHOICE_OPTION, szMsg, RC_STRING_MAX_SIZE);
582
583 if (_tcsncmp(p, &szMsg[0], 1) == 0)
584 return PROMPT_YES;
585 else if (_tcsncmp(p, &szMsg[1], 1) == 0)
586 return PROMPT_NO;
587 #if 0
588 else if (*p == _T('\03'))
589 return PROMPT_BREAK;
590 #endif
591
592 return PROMPT_NO;
593
594
595 /* unfinished sollution */
596 #if 0
597 RemoveBreakHandler ();
598 ConInDisable ();
599
600 do
601 {
602 ConInKey (&ir);
603 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar);
604 if (_tcschr (szKeys, cKey[0]) == NULL)
605 cKey = 0;
606
607
608 }
609 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
610 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
611 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
612
613 AddBreakHandler ();
614 ConInEnable ();
615
616 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
617 ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') &&
618 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
619 return PROMPT_BREAK;
620
621 return PROMPT_YES;
622 #endif
623 }
624
625
626 INT FilePromptYNA (UINT resID)
627 {
628 TCHAR szMsg[RC_STRING_MAX_SIZE];
629 // TCHAR cKey = 0;
630 // LPTSTR szKeys = _T("yna");
631
632 TCHAR szIn[10];
633 LPTSTR p;
634
635 if (resID != 0)
636 ConOutResPrintf (resID);
637
638 /* preliminary fix */
639 ConInString (szIn, 10);
640 ConOutPrintf (_T("\n"));
641
642 _tcsupr (szIn);
643 for (p = szIn; _istspace (*p); p++)
644 ;
645
646 LoadString( CMD_ModuleHandle, STRING_COPY_OPTION, szMsg, RC_STRING_MAX_SIZE);
647
648 if (_tcsncmp(p, &szMsg[0], 1) == 0)
649 return PROMPT_YES;
650 else if (_tcsncmp(p, &szMsg[1], 1) == 0)
651 return PROMPT_NO;
652 else if (_tcsncmp(p, &szMsg[2], 1) == 0)
653 return PROMPT_ALL;
654
655 #if 0
656 else if (*p == _T('\03'))
657 return PROMPT_BREAK;
658 #endif
659
660 return PROMPT_NO;
661
662
663 /* unfinished sollution */
664 #if 0
665 RemoveBreakHandler ();
666 ConInDisable ();
667
668 do
669 {
670 ConInKey (&ir);
671 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar);
672 if (_tcschr (szKeys, cKey[0]) == NULL)
673 cKey = 0;
674 }
675 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
676 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) ||
677 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL));
678
679 AddBreakHandler ();
680 ConInEnable ();
681
682 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
683 ((ir.Event.KeyEvent.wVirtualKeyCode == _T('C')) &&
684 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
685 return PROMPT_BREAK;
686
687 return PROMPT_YES;
688 #endif
689 }
690
691 /* EOF */