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