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