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(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 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 */ 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 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 */ 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 */ 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 */ 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 474 LPTSTR _stpcpy (LPTSTR dest, LPCTSTR src) 475 { 476 _tcscpy (dest, src); 477 return (dest + _tcslen (src)); 478 } 479 480 VOID 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 */ 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 */ 512 BOOL IsExistingFile(IN LPCTSTR pszPath) 513 { 514 DWORD attr = GetFileAttributes(pszPath); 515 return ((attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_DIRECTORY)); 516 } 517 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 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 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 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