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 (is accessible) 481 */ 482 BOOL IsValidPathName(IN LPCTSTR pszPath) 483 { 484 BOOL bResult; 485 TCHAR szOldPath[MAX_PATH]; 486 487 GetCurrentDirectory(ARRAYSIZE(szOldPath), szOldPath); 488 bResult = SetCurrentDirectory(pszPath); 489 490 SetCurrentDirectory(szOldPath); 491 492 return bResult; 493 } 494 495 /* 496 * Checks if a file exists (is accessible) 497 */ 498 BOOL IsExistingFile(IN LPCTSTR pszPath) 499 { 500 DWORD attr = GetFileAttributes(pszPath); 501 return ((attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_DIRECTORY)); 502 } 503 504 BOOL IsExistingDirectory(IN LPCTSTR pszPath) 505 { 506 DWORD attr = GetFileAttributes(pszPath); 507 return ((attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY)); 508 } 509 510 511 // See r874 512 BOOL __stdcall PagePrompt(PCON_PAGER Pager, DWORD Done, DWORD Total) 513 { 514 SHORT iScreenWidth, iCursorY; 515 INPUT_RECORD ir; 516 517 ConOutResPuts(STRING_MISC_HELP1); 518 519 RemoveBreakHandler(); 520 ConInDisable(); 521 522 do 523 { 524 ConInKey(&ir); 525 } 526 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) || 527 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) || 528 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL)); 529 530 AddBreakHandler(); 531 ConInEnable(); 532 533 /* 534 * Get the screen width, erase the full line where the cursor is, 535 * and move the cursor back to the beginning of the line. 536 */ 537 GetScreenSize(&iScreenWidth, NULL); 538 iCursorY = GetCursorY(); 539 SetCursorXY(0, iCursorY); 540 while (iScreenWidth-- > 0) // Or call FillConsoleOutputCharacter ? 541 ConOutChar(_T(' ')); 542 SetCursorXY(0, iCursorY); 543 544 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) || 545 ((ir.Event.KeyEvent.wVirtualKeyCode == _T('C')) && 546 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)))) 547 { 548 /* We break, output a newline */ 549 ConOutChar(_T('\n')); 550 551 bCtrlBreak = TRUE; 552 return FALSE; 553 } 554 555 return TRUE; 556 } 557 558 559 INT FilePromptYN (UINT resID) 560 { 561 TCHAR szMsg[RC_STRING_MAX_SIZE]; 562 // TCHAR cKey = 0; 563 // LPTSTR szKeys = _T("yna"); 564 565 TCHAR szIn[10]; 566 LPTSTR p; 567 568 if (resID != 0) 569 ConOutResPrintf (resID); 570 571 /* preliminary fix */ 572 ConInString(szIn, 10); 573 574 _tcsupr (szIn); 575 for (p = szIn; _istspace (*p); p++) 576 ; 577 578 LoadString(CMD_ModuleHandle, STRING_CHOICE_OPTION, szMsg, ARRAYSIZE(szMsg)); 579 580 if (_tcsncmp(p, &szMsg[0], 1) == 0) 581 return PROMPT_YES; 582 else if (_tcsncmp(p, &szMsg[1], 1) == 0) 583 return PROMPT_NO; 584 #if 0 585 else if (*p == _T('\03')) 586 return PROMPT_BREAK; 587 #endif 588 589 return PROMPT_NO; 590 591 /* unfinished solution */ 592 #if 0 593 RemoveBreakHandler(); 594 ConInDisable(); 595 596 do 597 { 598 ConInKey (&ir); 599 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar); 600 if (_tcschr (szKeys, cKey[0]) == NULL) 601 cKey = 0; 602 603 604 } 605 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) || 606 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) || 607 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL)); 608 609 AddBreakHandler(); 610 ConInEnable(); 611 612 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) || 613 ((ir.Event.KeyEvent.wVirtualKeyCode == 'C') && 614 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)))) 615 return PROMPT_BREAK; 616 617 return PROMPT_YES; 618 #endif 619 } 620 621 622 INT FilePromptYNA (UINT resID) 623 { 624 TCHAR szMsg[RC_STRING_MAX_SIZE]; 625 // TCHAR cKey = 0; 626 // LPTSTR szKeys = _T("yna"); 627 628 TCHAR szIn[10]; 629 LPTSTR p; 630 631 if (resID != 0) 632 ConOutResPrintf (resID); 633 634 /* preliminary fix */ 635 ConInString(szIn, 10); 636 637 _tcsupr (szIn); 638 for (p = szIn; _istspace (*p); p++) 639 ; 640 641 LoadString(CMD_ModuleHandle, STRING_COPY_OPTION, szMsg, ARRAYSIZE(szMsg)); 642 643 if (_tcsncmp(p, &szMsg[0], 1) == 0) 644 return PROMPT_YES; 645 else if (_tcsncmp(p, &szMsg[1], 1) == 0) 646 return PROMPT_NO; 647 else if (_tcsncmp(p, &szMsg[2], 1) == 0) 648 return PROMPT_ALL; 649 #if 0 650 else if (*p == _T('\03')) 651 return PROMPT_BREAK; 652 #endif 653 654 return PROMPT_NO; 655 656 /* unfinished solution */ 657 #if 0 658 RemoveBreakHandler(); 659 ConInDisable(); 660 661 do 662 { 663 ConInKey (&ir); 664 cKey = _totlower (ir.Event.KeyEvent.uChar.AsciiChar); 665 if (_tcschr (szKeys, cKey[0]) == NULL) 666 cKey = 0; 667 } 668 while ((ir.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) || 669 (ir.Event.KeyEvent.wVirtualKeyCode == VK_MENU) || 670 (ir.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL)); 671 672 AddBreakHandler(); 673 ConInEnable(); 674 675 if ((ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) || 676 ((ir.Event.KeyEvent.wVirtualKeyCode == _T('C')) && 677 (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)))) 678 return PROMPT_BREAK; 679 680 return PROMPT_YES; 681 #endif 682 } 683 684 /* EOF */ 685