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