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 */ 729