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