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