1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS text-mode setup 4 * FILE: base/setup/usetup/cmdcons.c 5 * PURPOSE: Recovery console 6 * PROGRAMMER: 7 */ 8 9 #include "usetup.h" 10 11 #define NDEBUG 12 #include <debug.h> 13 14 15 //#define FEATURE_HISTORY 16 17 typedef struct _CONSOLE_STATE 18 { 19 SHORT maxx; 20 SHORT maxy; 21 BOOLEAN bInsert; 22 BOOLEAN bExit; 23 } CONSOLE_STATE, *PCONSOLE_STATE; 24 25 typedef struct tagCOMMAND 26 { 27 LPSTR name; 28 INT flags; 29 INT (*func)(PCONSOLE_STATE, LPSTR); 30 VOID (*help)(VOID); 31 } COMMAND, *LPCOMMAND; 32 33 34 static 35 VOID 36 HelpCls(VOID); 37 38 static 39 INT 40 CommandCls( 41 PCONSOLE_STATE State, 42 LPSTR param); 43 44 static 45 VOID 46 HelpDumpSector(VOID); 47 48 static 49 INT 50 CommandDumpSector( 51 PCONSOLE_STATE State, 52 LPSTR param); 53 54 static 55 VOID 56 HelpExit(VOID); 57 58 static 59 INT 60 CommandExit( 61 PCONSOLE_STATE State, 62 LPSTR param); 63 64 static 65 VOID 66 HelpHelp(VOID); 67 68 static 69 INT 70 CommandHelp( 71 PCONSOLE_STATE State, 72 LPSTR param); 73 74 static 75 VOID 76 HelpPartInfo(VOID); 77 78 static 79 INT 80 CommandPartInfo( 81 PCONSOLE_STATE State, 82 LPSTR param); 83 84 COMMAND 85 Commands[] = 86 { 87 {"cls", 0, CommandCls, HelpCls}, 88 {"dumpsector", 0, CommandDumpSector, HelpDumpSector}, 89 {"exit", 0, CommandExit, HelpExit}, 90 {"help", 0, CommandHelp, HelpHelp}, 91 {"partinfo", 0, CommandPartInfo, HelpPartInfo}, 92 {NULL, 0, NULL} 93 }; 94 95 96 static 97 VOID 98 freep( 99 LPSTR *p) 100 { 101 LPSTR *q; 102 103 if (!p) 104 return; 105 106 q = p; 107 while (*q) 108 RtlFreeHeap(ProcessHeap, 0, *q++); 109 110 RtlFreeHeap(ProcessHeap, 0, p); 111 } 112 113 114 static 115 VOID 116 StripQuotes( 117 LPSTR in) 118 { 119 LPSTR out = in; 120 121 for (; *in; in++) 122 { 123 if (*in != '"') 124 *out++ = *in; 125 } 126 127 *out = '\0'; 128 } 129 130 131 BOOL 132 add_entry( 133 LPINT ac, 134 LPSTR **arg, 135 LPCSTR entry) 136 { 137 LPSTR q; 138 LPSTR *oldarg; 139 140 q = RtlAllocateHeap(ProcessHeap, 0, strlen(entry) + 1); 141 if (q == NULL) 142 return FALSE; 143 144 strcpy(q, entry); 145 oldarg = *arg; 146 *arg = RtlReAllocateHeap(ProcessHeap, 0, oldarg, (*ac + 2) * sizeof(LPSTR)); 147 if (*arg == NULL) 148 { 149 RtlFreeHeap(ProcessHeap, 0, q); 150 *arg = oldarg; 151 return FALSE; 152 } 153 154 /* save new entry */ 155 (*arg)[*ac] = q; 156 (*arg)[++(*ac)] = NULL; 157 158 return TRUE; 159 } 160 161 static 162 LPSTR * 163 split( 164 LPSTR s, 165 LPINT args) 166 { 167 LPSTR *arg; 168 LPSTR start; 169 LPSTR q; 170 INT ac; 171 INT_PTR len; 172 BOOL bQuoted; 173 174 arg = RtlAllocateHeap(ProcessHeap, 0 , sizeof(LPTSTR)); 175 if (arg == NULL) 176 return NULL; 177 178 *arg = NULL; 179 180 ac = 0; 181 while (*s) 182 { 183 bQuoted = FALSE; 184 185 /* skip leading spaces */ 186 while (*s && (isspace(*s) || iscntrl(*s))) 187 ++s; 188 189 start = s; 190 191 /* the first character can be '/' */ 192 if (*s == '/') 193 s++; 194 195 /* skip to next word delimiter or start of next option */ 196 while (isprint(*s)) 197 { 198 /* if quote (") then set bQuoted */ 199 bQuoted ^= (*s == '\"'); 200 201 /* Check if we have unquoted text */ 202 if (!bQuoted) 203 { 204 /* check for separators */ 205 if (isspace(*s) || (*s == '/')) 206 { 207 /* Make length at least one character */ 208 if (s == start) 209 s++; 210 break; 211 } 212 } 213 214 s++; 215 } 216 217 /* a word was found */ 218 if (s != start) 219 { 220 len = s - start; 221 q = RtlAllocateHeap(ProcessHeap, 0, len + 1); 222 if (q == NULL) 223 { 224 freep(arg); 225 return NULL; 226 } 227 228 memcpy(q, start, len); 229 q[len] = '\0'; 230 231 StripQuotes(q); 232 233 if (!add_entry(&ac, &arg, q)) 234 { 235 RtlFreeHeap(ProcessHeap, 0, q); 236 freep(arg); 237 return NULL; 238 } 239 240 RtlFreeHeap(ProcessHeap, 0, q); 241 } 242 } 243 244 *args = ac; 245 246 return arg; 247 } 248 249 250 static 251 VOID 252 HelpCls(VOID) 253 { 254 CONSOLE_ConOutPrintf("CLS\n\nClears the screen.\n\n"); 255 } 256 257 258 static 259 INT 260 CommandCls( 261 PCONSOLE_STATE State, 262 LPSTR param) 263 { 264 if (!strcmp(param, "/?")) 265 { 266 HelpCls(); 267 return 0; 268 } 269 270 CONSOLE_ClearScreen(); 271 CONSOLE_SetCursorXY(0, 0); 272 273 return 0; 274 } 275 276 277 void HexDump(PUCHAR buffer, ULONG size) 278 { 279 ULONG offset = 0; 280 PUCHAR ptr; 281 282 while (offset < (size & ~15)) 283 { 284 ptr = (PUCHAR)((ULONG_PTR)buffer + offset); 285 CONSOLE_ConOutPrintf("%04lx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx\n", 286 offset, 287 ptr[0], 288 ptr[1], 289 ptr[2], 290 ptr[3], 291 ptr[4], 292 ptr[5], 293 ptr[6], 294 ptr[7], 295 ptr[8], 296 ptr[9], 297 ptr[10], 298 ptr[11], 299 ptr[12], 300 ptr[13], 301 ptr[14], 302 ptr[15]); 303 offset += 16; 304 } 305 306 if (offset < size) 307 { 308 ptr = (PUCHAR)((ULONG_PTR)buffer + offset); 309 CONSOLE_ConOutPrintf("%04lx ", offset); 310 while (offset < size) 311 { 312 CONSOLE_ConOutPrintf(" %02hx", *ptr); 313 offset++; 314 ptr++; 315 } 316 317 CONSOLE_ConOutPrintf("\n"); 318 } 319 320 CONSOLE_ConOutPrintf("\n"); 321 } 322 323 324 static 325 VOID 326 HelpDumpSector(VOID) 327 { 328 CONSOLE_ConOutPrintf("DUMPSECT DiskNumber Sector\n\nDumps a disk sector to the screen.\n\n"); 329 } 330 331 332 static 333 INT 334 CommandDumpSector( 335 PCONSOLE_STATE State, 336 LPSTR param) 337 { 338 OBJECT_ATTRIBUTES ObjectAttributes; 339 IO_STATUS_BLOCK IoStatusBlock; 340 UNICODE_STRING PathName; 341 HANDLE hDisk = NULL; 342 DISK_GEOMETRY DiskGeometry; 343 NTSTATUS Status; 344 345 LPTSTR *argv = NULL; 346 INT argc = 0; 347 WCHAR DriveName[40]; 348 ULONG ulDrive; 349 // ULONG ulSector; 350 LARGE_INTEGER Sector, SectorCount, Offset; 351 PUCHAR Buffer = NULL; 352 353 DPRINT1("param: %s\n", param); 354 355 if (!strcmp(param, "/?")) 356 { 357 HelpDumpSector(); 358 return 0; 359 } 360 361 argv = split(param, &argc); 362 363 DPRINT1("argc: %d\n", argc); 364 DPRINT1("argv: %p\n", argv); 365 366 if (argc != 2) 367 { 368 goto done; 369 } 370 371 DPRINT1("Device: %s\n", argv[0]); 372 DPRINT1("Sector: %s\n", argv[1]); 373 374 ulDrive = strtoul(argv[0], NULL, 0); 375 // ulSector = strtoul(argv[1], NULL, 0); 376 Sector.QuadPart = _atoi64(argv[1]); 377 378 /* Build full drive name */ 379 // swprintf(DriveName, L"\\\\.\\PHYSICALDRIVE%lu", ulDrive); 380 swprintf(DriveName, L"\\Device\\Harddisk%lu\\Partition0", ulDrive); 381 382 RtlInitUnicodeString(&PathName, 383 DriveName); 384 385 InitializeObjectAttributes(&ObjectAttributes, 386 &PathName, 387 OBJ_CASE_INSENSITIVE | OBJ_INHERIT, 388 NULL, 389 NULL); 390 391 Status = NtOpenFile(&hDisk, 392 GENERIC_READ | SYNCHRONIZE, 393 &ObjectAttributes, 394 &IoStatusBlock, 395 FILE_SHARE_READ, 396 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS); 397 if (!NT_SUCCESS(Status)) 398 { 399 DPRINT1("NtCreateFile failed (Status 0x%08lx)\n", Status); 400 goto done; 401 } 402 403 Status = NtDeviceIoControlFile(hDisk, 404 NULL, 405 NULL, 406 NULL, 407 &IoStatusBlock, 408 IOCTL_DISK_GET_DRIVE_GEOMETRY, 409 NULL, 410 0, 411 &DiskGeometry, 412 sizeof(DISK_GEOMETRY)); 413 if (!NT_SUCCESS(Status)) 414 { 415 DPRINT1("NtDeviceIoControlFile failed (Status 0x%08lx)\n", Status); 416 goto done; 417 } 418 419 DPRINT1("Drive number: %lu\n", ulDrive); 420 DPRINT1("Cylinders: %I64u\nMediaType: %x\nTracksPerCylinder: %lu\n" 421 "SectorsPerTrack: %lu\nBytesPerSector: %lu\n\n", 422 DiskGeometry.Cylinders.QuadPart, 423 DiskGeometry.MediaType, 424 DiskGeometry.TracksPerCylinder, 425 DiskGeometry.SectorsPerTrack, 426 DiskGeometry.BytesPerSector); 427 428 DPRINT1("Sector: %I64u\n", Sector.QuadPart); 429 430 SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart * 431 (ULONGLONG)DiskGeometry.TracksPerCylinder * 432 (ULONGLONG)DiskGeometry.SectorsPerTrack; 433 if (Sector.QuadPart >= SectorCount.QuadPart) 434 { 435 CONSOLE_ConOutPrintf("Invalid sector number! Valid range: [0 - %I64u]\n", SectorCount.QuadPart - 1); 436 goto done; 437 } 438 439 Buffer = RtlAllocateHeap(ProcessHeap, 0, DiskGeometry.BytesPerSector); 440 if (Buffer == NULL) 441 { 442 DPRINT1("Buffer allocation failed\n"); 443 goto done; 444 } 445 446 447 Offset.QuadPart = Sector.QuadPart * DiskGeometry.BytesPerSector; 448 DPRINT1("Offset: %I64u\n", Offset.QuadPart); 449 450 Status = NtReadFile(hDisk, 451 NULL, 452 NULL, 453 NULL, 454 &IoStatusBlock, 455 Buffer, 456 DiskGeometry.BytesPerSector, 457 &Offset, 458 NULL); 459 if (!NT_SUCCESS(Status)) 460 { 461 DPRINT1("NtReadFile failed (Status 0x%08lx)\n", Status); 462 goto done; 463 } 464 465 HexDump(Buffer, DiskGeometry.BytesPerSector); 466 467 done: 468 if (Buffer != NULL) 469 RtlFreeHeap(ProcessHeap, 0, Buffer); 470 471 if (hDisk != NULL) 472 NtClose(hDisk); 473 474 freep(argv); 475 476 return 0; 477 } 478 479 480 static 481 VOID 482 HelpExit(VOID) 483 { 484 CONSOLE_ConOutPrintf("EXIT\n\nExits the repair console.\n\n"); 485 } 486 487 488 static 489 INT 490 CommandExit( 491 PCONSOLE_STATE State, 492 LPSTR param) 493 { 494 if (!strcmp(param, "/?")) 495 { 496 HelpExit(); 497 return 0; 498 } 499 500 State->bExit = TRUE; 501 502 return 0; 503 } 504 505 506 static 507 VOID 508 HelpHelp(VOID) 509 { 510 CONSOLE_ConOutPrintf("HELP [Command]\n\nShows help on repair console commands.\n\n"); 511 } 512 513 514 static 515 INT 516 CommandHelp( 517 PCONSOLE_STATE State, 518 LPSTR param) 519 { 520 LPCOMMAND cmdptr; 521 522 DPRINT1("param: %p %u '%s'\n", param, strlen(param), param); 523 524 if (!strcmp(param, "/?")) 525 { 526 HelpHelp(); 527 return 0; 528 } 529 530 if (param != NULL && strlen(param) > 0) 531 { 532 for (cmdptr = Commands; cmdptr->name != NULL; cmdptr++) 533 { 534 if (!stricmp(param, cmdptr->name)) 535 { 536 if (cmdptr->help != NULL) 537 { 538 cmdptr->help(); 539 return 0; 540 } 541 } 542 } 543 } 544 545 CONSOLE_ConOutPrintf("CLS\n"); 546 CONSOLE_ConOutPrintf("DUMPSECTOR\n"); 547 CONSOLE_ConOutPrintf("EXIT\n"); 548 CONSOLE_ConOutPrintf("HELP\n"); 549 CONSOLE_ConOutPrintf("\n"); 550 551 return 0; 552 } 553 554 555 static 556 VOID 557 HelpPartInfo(VOID) 558 { 559 CONSOLE_ConOutPrintf("PARTINFO DiskNumber\n\nDumps a partition table to the screen.\n\n"); 560 } 561 562 563 static 564 INT 565 CommandPartInfo( 566 PCONSOLE_STATE State, 567 LPSTR param) 568 { 569 OBJECT_ATTRIBUTES ObjectAttributes; 570 IO_STATUS_BLOCK IoStatusBlock; 571 UNICODE_STRING PathName; 572 HANDLE hDisk = NULL; 573 DISK_GEOMETRY DiskGeometry; 574 NTSTATUS Status; 575 576 LPTSTR *argv = NULL; 577 INT argc = 0; 578 WCHAR DriveName[40]; 579 ULONG ulDrive, i; 580 PDRIVE_LAYOUT_INFORMATION LayoutBuffer = NULL; 581 PPARTITION_INFORMATION PartitionInfo; 582 583 DPRINT1("param: %s\n", param); 584 585 if (!strcmp(param, "/?")) 586 { 587 HelpPartInfo(); 588 return 0; 589 } 590 591 argv = split(param, &argc); 592 593 DPRINT1("argc: %d\n", argc); 594 DPRINT1("argv: %p\n", argv); 595 596 if (argc != 1) 597 { 598 goto done; 599 } 600 601 DPRINT1("Device: %s\n", argv[0]); 602 603 ulDrive = strtoul(argv[0], NULL, 0); 604 605 /* Build full drive name */ 606 swprintf(DriveName, L"\\Device\\Harddisk%lu\\Partition0", ulDrive); 607 608 RtlInitUnicodeString(&PathName, 609 DriveName); 610 611 InitializeObjectAttributes(&ObjectAttributes, 612 &PathName, 613 OBJ_CASE_INSENSITIVE | OBJ_INHERIT, 614 NULL, 615 NULL); 616 617 Status = NtOpenFile(&hDisk, 618 GENERIC_READ | SYNCHRONIZE, 619 &ObjectAttributes, 620 &IoStatusBlock, 621 FILE_SHARE_READ, 622 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS); 623 if (!NT_SUCCESS(Status)) 624 { 625 DPRINT1("NtCreateFile failed (Status 0x%08lx)\n", Status); 626 goto done; 627 } 628 629 Status = NtDeviceIoControlFile(hDisk, 630 NULL, 631 NULL, 632 NULL, 633 &IoStatusBlock, 634 IOCTL_DISK_GET_DRIVE_GEOMETRY, 635 NULL, 636 0, 637 &DiskGeometry, 638 sizeof(DISK_GEOMETRY)); 639 if (!NT_SUCCESS(Status)) 640 { 641 DPRINT1("NtDeviceIoControlFile failed (Status 0x%08lx)\n", Status); 642 goto done; 643 } 644 645 CONSOLE_ConOutPrintf("Drive number: %lu\n", ulDrive); 646 CONSOLE_ConOutPrintf("Cylinders: %I64u\nMediaType: %x\nTracksPerCylinder: %lu\n" 647 "SectorsPerTrack: %lu\nBytesPerSector: %lu\n\n", 648 DiskGeometry.Cylinders.QuadPart, 649 DiskGeometry.MediaType, 650 DiskGeometry.TracksPerCylinder, 651 DiskGeometry.SectorsPerTrack, 652 DiskGeometry.BytesPerSector); 653 654 LayoutBuffer = RtlAllocateHeap(ProcessHeap, 655 HEAP_ZERO_MEMORY, 656 8192); 657 if (LayoutBuffer == NULL) 658 { 659 DPRINT1("LayoutBuffer allocation failed\n"); 660 goto done; 661 } 662 663 Status = NtDeviceIoControlFile(hDisk, 664 NULL, 665 NULL, 666 NULL, 667 &IoStatusBlock, 668 IOCTL_DISK_GET_DRIVE_LAYOUT, 669 NULL, 670 0, 671 LayoutBuffer, 672 8192); 673 if (!NT_SUCCESS(Status)) 674 { 675 DPRINT1("NtDeviceIoControlFile(IOCTL_DISK_GET_DRIVE_LAYOUT) failed (Status 0x%08lx)\n", Status); 676 goto done; 677 } 678 679 CONSOLE_ConOutPrintf("Partitions: %lu Signature: %lx\n\n", 680 LayoutBuffer->PartitionCount, 681 LayoutBuffer->Signature); 682 683 CONSOLE_ConOutPrintf(" # Start Size Hidden Nr Type Boot\n"); 684 CONSOLE_ConOutPrintf("-- --------------- --------------- ------------ -- ---- ----\n"); 685 686 for (i = 0; i < LayoutBuffer->PartitionCount; i++) 687 { 688 PartitionInfo = &LayoutBuffer->PartitionEntry[i]; 689 690 CONSOLE_ConOutPrintf("%2lu %15I64u %15I64u %12lu %2lu %2x %c\n", 691 i, 692 PartitionInfo->StartingOffset.QuadPart / DiskGeometry.BytesPerSector, 693 PartitionInfo->PartitionLength.QuadPart / DiskGeometry.BytesPerSector, 694 PartitionInfo->HiddenSectors, 695 PartitionInfo->PartitionNumber, 696 PartitionInfo->PartitionType, 697 PartitionInfo->BootIndicator ? '*': ' '); 698 } 699 700 CONSOLE_ConOutPrintf("\n"); 701 702 done: 703 if (LayoutBuffer != NULL) 704 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer); 705 706 if (hDisk != NULL) 707 NtClose(hDisk); 708 709 freep(argv); 710 711 return 0; 712 } 713 714 715 static 716 VOID 717 ClearCommandLine( 718 LPSTR str, 719 INT maxlen, 720 SHORT orgx, 721 SHORT orgy) 722 { 723 INT count; 724 725 CONSOLE_SetCursorXY(orgx, orgy); 726 for (count = 0; count < (INT)strlen(str); count++) 727 CONSOLE_ConOutChar(' '); 728 memset(str, 0, maxlen); 729 CONSOLE_SetCursorXY(orgx, orgy); 730 } 731 732 733 static 734 BOOL 735 ReadCommand( 736 PCONSOLE_STATE State, 737 LPSTR str, 738 INT maxlen) 739 { 740 SHORT orgx; /* origin x/y */ 741 SHORT orgy; 742 SHORT curx; /*current x/y cursor position*/ 743 SHORT cury; 744 SHORT tempscreen; 745 INT count; /*used in some for loops*/ 746 INT current = 0; /*the position of the cursor in the string (str)*/ 747 INT charcount = 0;/*chars in the string (str)*/ 748 INPUT_RECORD ir; 749 CHAR ch; 750 BOOL bReturn = FALSE; 751 BOOL bCharInput; 752 #ifdef FEATURE_HISTORY 753 //BOOL bContinue=FALSE;/*is TRUE the second case will not be executed*/ 754 CHAR PreviousChar; 755 #endif 756 757 758 CONSOLE_GetCursorXY(&orgx, &orgy); 759 curx = orgx; 760 cury = orgy; 761 762 memset(str, 0, maxlen * sizeof(CHAR)); 763 764 CONSOLE_SetCursorType(State->bInsert, TRUE); 765 766 do 767 { 768 bReturn = FALSE; 769 CONSOLE_ConInKey(&ir); 770 771 if (ir.Event.KeyEvent.dwControlKeyState & 772 (RIGHT_ALT_PRESSED |LEFT_ALT_PRESSED| 773 RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED) ) 774 { 775 switch (ir.Event.KeyEvent.wVirtualKeyCode) 776 { 777 #ifdef FEATURE_HISTORY 778 case 'K': 779 /*add the current command line to the history*/ 780 if (ir.Event.KeyEvent.dwControlKeyState & 781 (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) 782 { 783 if (str[0]) 784 History(0,str); 785 786 ClearCommandLine (str, maxlen, orgx, orgy); 787 current = charcount = 0; 788 curx = orgx; 789 cury = orgy; 790 //bContinue=TRUE; 791 break; 792 } 793 794 case 'D': 795 /*delete current history entry*/ 796 if (ir.Event.KeyEvent.dwControlKeyState & 797 (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) 798 { 799 ClearCommandLine (str, maxlen, orgx, orgy); 800 History_del_current_entry(str); 801 current = charcount = strlen (str); 802 ConOutPrintf("%s", str); 803 GetCursorXY(&curx, &cury); 804 //bContinue=TRUE; 805 break; 806 } 807 808 #endif /*FEATURE_HISTORY*/ 809 } 810 } 811 812 bCharInput = FALSE; 813 814 switch (ir.Event.KeyEvent.wVirtualKeyCode) 815 { 816 case VK_BACK: 817 /* <BACKSPACE> - delete character to left of cursor */ 818 if (current > 0 && charcount > 0) 819 { 820 if (current == charcount) 821 { 822 /* if at end of line */ 823 str[current - 1] = L'\0'; 824 if (CONSOLE_GetCursorX () != 0) 825 { 826 CONSOLE_ConOutPrintf("\b \b"); 827 curx--; 828 } 829 else 830 { 831 CONSOLE_SetCursorXY((SHORT)(State->maxx - 1), (SHORT)(CONSOLE_GetCursorY () - 1)); 832 CONSOLE_ConOutChar(' '); 833 CONSOLE_SetCursorXY((SHORT)(State->maxx - 1), (SHORT)(CONSOLE_GetCursorY () - 1)); 834 cury--; 835 curx = State->maxx - 1; 836 } 837 } 838 else 839 { 840 for (count = current - 1; count < charcount; count++) 841 str[count] = str[count + 1]; 842 if (CONSOLE_GetCursorX () != 0) 843 { 844 CONSOLE_SetCursorXY ((SHORT)(CONSOLE_GetCursorX () - 1), CONSOLE_GetCursorY ()); 845 curx--; 846 } 847 else 848 { 849 CONSOLE_SetCursorXY ((SHORT)(State->maxx - 1), (SHORT)(CONSOLE_GetCursorY () - 1)); 850 cury--; 851 curx = State->maxx - 1; 852 } 853 CONSOLE_GetCursorXY(&curx, &cury); 854 CONSOLE_ConOutPrintf("%s ", &str[current - 1]); 855 CONSOLE_SetCursorXY(curx, cury); 856 } 857 charcount--; 858 current--; 859 } 860 break; 861 862 case VK_INSERT: 863 /* toggle insert/overstrike mode */ 864 State->bInsert ^= TRUE; 865 CONSOLE_SetCursorType(State->bInsert, TRUE); 866 break; 867 868 case VK_DELETE: 869 /* delete character under cursor */ 870 if (current != charcount && charcount > 0) 871 { 872 for (count = current; count < charcount; count++) 873 str[count] = str[count + 1]; 874 charcount--; 875 CONSOLE_GetCursorXY(&curx, &cury); 876 CONSOLE_ConOutPrintf("%s ", &str[current]); 877 CONSOLE_SetCursorXY(curx, cury); 878 } 879 break; 880 881 case VK_HOME: 882 /* goto beginning of string */ 883 if (current != 0) 884 { 885 CONSOLE_SetCursorXY(orgx, orgy); 886 curx = orgx; 887 cury = orgy; 888 current = 0; 889 } 890 break; 891 892 case VK_END: 893 /* goto end of string */ 894 if (current != charcount) 895 { 896 CONSOLE_SetCursorXY(orgx, orgy); 897 CONSOLE_ConOutPrintf("%s", str); 898 CONSOLE_GetCursorXY(&curx, &cury); 899 current = charcount; 900 } 901 break; 902 903 case 'M': 904 case 'C': 905 /* ^M does the same as return */ 906 bCharInput = TRUE; 907 if (!(ir.Event.KeyEvent.dwControlKeyState & 908 (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED))) 909 { 910 break; 911 } 912 913 case VK_RETURN: 914 /* end input, return to main */ 915 #ifdef FEATURE_HISTORY 916 /* add to the history */ 917 if (str[0]) 918 History (0, str); 919 #endif 920 str[charcount] = '\0'; 921 CONSOLE_ConOutChar('\n'); 922 bReturn = TRUE; 923 break; 924 925 case VK_ESCAPE: 926 /* clear str Make this callable! */ 927 ClearCommandLine (str, maxlen, orgx, orgy); 928 curx = orgx; 929 cury = orgy; 930 current = charcount = 0; 931 break; 932 933 #ifdef FEATURE_HISTORY 934 case VK_F3: 935 History_move_to_bottom(); 936 #endif 937 case VK_UP: 938 #ifdef FEATURE_HISTORY 939 /* get previous command from buffer */ 940 ClearCommandLine (str, maxlen, orgx, orgy); 941 History (-1, str); 942 current = charcount = strlen (str); 943 if (((charcount + orgx) / maxx) + orgy > maxy - 1) 944 orgy += maxy - ((charcount + orgx) / maxx + orgy + 1); 945 CONSOLE_ConOutPrintf("%s", str); 946 CONSOLE_GetCursorXY(&curx, &cury); 947 #endif 948 break; 949 950 case VK_DOWN: 951 #ifdef FEATURE_HISTORY 952 /* get next command from buffer */ 953 ClearCommandLine (str, maxlen, orgx, orgy); 954 History (1, str); 955 current = charcount = strlen (str); 956 if (((charcount + orgx) / maxx) + orgy > maxy - 1) 957 orgy += maxy - ((charcount + orgx) / maxx + orgy + 1); 958 CONSOLE_ConOutPrintf("%s", str); 959 CONSOLE_GetCursorXY(&curx, &cury); 960 #endif 961 break; 962 963 case VK_LEFT: 964 /* move cursor left */ 965 if (current > 0) 966 { 967 current--; 968 if (CONSOLE_GetCursorX() == 0) 969 { 970 CONSOLE_SetCursorXY((SHORT)(State->maxx - 1), (SHORT)(CONSOLE_GetCursorY () - 1)); 971 curx = State->maxx - 1; 972 cury--; 973 } 974 else 975 { 976 CONSOLE_SetCursorXY((SHORT)(CONSOLE_GetCursorX () - 1), CONSOLE_GetCursorY ()); 977 curx--; 978 } 979 } 980 break; 981 982 case VK_RIGHT: 983 /* move cursor right */ 984 if (current != charcount) 985 { 986 current++; 987 if (CONSOLE_GetCursorX() == State->maxx - 1) 988 { 989 CONSOLE_SetCursorXY(0, (SHORT)(CONSOLE_GetCursorY () + 1)); 990 curx = 0; 991 cury++; 992 } 993 else 994 { 995 CONSOLE_SetCursorXY((SHORT)(CONSOLE_GetCursorX () + 1), CONSOLE_GetCursorY ()); 996 curx++; 997 } 998 } 999 #ifdef FEATURE_HISTORY 1000 else 1001 { 1002 LPCSTR last = PeekHistory(-1); 1003 if (last && charcount < (INT)strlen (last)) 1004 { 1005 PreviousChar = last[current]; 1006 CONSOLE_ConOutChar(PreviousChar); 1007 CONSOLE_GetCursorXY(&curx, &cury); 1008 str[current++] = PreviousChar; 1009 charcount++; 1010 } 1011 } 1012 #endif 1013 break; 1014 1015 default: 1016 /* This input is just a normal char */ 1017 bCharInput = TRUE; 1018 1019 } 1020 1021 ch = ir.Event.KeyEvent.uChar.UnicodeChar; 1022 if (ch >= 32 && (charcount != (maxlen - 2)) && bCharInput) 1023 { 1024 /* insert character into string... */ 1025 if (State->bInsert && current != charcount) 1026 { 1027 /* If this character insertion will cause screen scrolling, 1028 * adjust the saved origin of the command prompt. */ 1029 tempscreen = strlen(str + current) + curx; 1030 if ((tempscreen % State->maxx) == (State->maxx - 1) && 1031 (tempscreen / State->maxx) + cury == (State->maxy - 1)) 1032 { 1033 orgy--; 1034 cury--; 1035 } 1036 1037 for (count = charcount; count > current; count--) 1038 str[count] = str[count - 1]; 1039 str[current++] = ch; 1040 if (curx == State->maxx - 1) 1041 curx = 0, cury++; 1042 else 1043 curx++; 1044 CONSOLE_ConOutPrintf("%s", &str[current - 1]); 1045 CONSOLE_SetCursorXY(curx, cury); 1046 charcount++; 1047 } 1048 else 1049 { 1050 if (current == charcount) 1051 charcount++; 1052 str[current++] = ch; 1053 if (CONSOLE_GetCursorX () == State->maxx - 1 && CONSOLE_GetCursorY () == State->maxy - 1) 1054 orgy--, cury--; 1055 if (CONSOLE_GetCursorX () == State->maxx - 1) 1056 curx = 0, cury++; 1057 else 1058 curx++; 1059 CONSOLE_ConOutChar(ch); 1060 } 1061 } 1062 } 1063 while (!bReturn); 1064 1065 CONSOLE_SetCursorType(State->bInsert, TRUE); 1066 1067 return TRUE; 1068 } 1069 1070 1071 static 1072 BOOL 1073 IsDelimiter( 1074 CHAR c) 1075 { 1076 return (c == '/' || c == '=' || c == '\0' || isspace(c)); 1077 } 1078 1079 1080 static 1081 VOID 1082 DoCommand( 1083 PCONSOLE_STATE State, 1084 LPSTR line) 1085 { 1086 CHAR com[MAX_PATH]; /* the first word in the command */ 1087 LPSTR cp = com; 1088 // LPSTR cstart; 1089 LPSTR rest = line; /* pointer to the rest of the command line */ 1090 // INT cl; 1091 LPCOMMAND cmdptr; 1092 1093 DPRINT1("DoCommand: (\'%s\')\n", line); 1094 1095 /* Skip over initial white space */ 1096 while (isspace(*rest)) 1097 rest++; 1098 1099 // cstart = rest; 1100 1101 /* Anything to do ? */ 1102 if (*rest) 1103 { 1104 /* Copy over 1st word as lower case */ 1105 while (!IsDelimiter(*rest)) 1106 *cp++ = tolower(*rest++); 1107 1108 /* Terminate first word */ 1109 *cp = '\0'; 1110 1111 /* Skip over whitespace to rest of line */ 1112 while (isspace (*rest)) 1113 rest++; 1114 1115 /* Scan internal command table */ 1116 for (cmdptr = Commands; ; cmdptr++) 1117 { 1118 /* If end of table execute ext cmd */ 1119 if (cmdptr->name == NULL) 1120 { 1121 CONSOLE_ConOutPuts("Unknown command. Enter HELP to get a list of commands."); 1122 break; 1123 } 1124 1125 if (stricmp(com, cmdptr->name) == 0) 1126 { 1127 cmdptr->func(State, rest); 1128 break; 1129 } 1130 1131 #if 0 1132 /* The following code handles the case of commands like CD which 1133 * are recognised even when the command name and parameter are 1134 * not space separated. 1135 * 1136 * e.g dir.. 1137 * cd\freda 1138 */ 1139 1140 /* Get length of command name */ 1141 cl = strlen(cmdptr->name); 1142 1143 if ((cmdptr->flags & CMD_SPECIAL) && 1144 (!strncmp (cmdptr->name, com, cl)) && 1145 (strchr("\\.-", *(com + cl)))) 1146 { 1147 /* OK its one of the specials...*/ 1148 1149 /* Call with new rest */ 1150 cmdptr->func(State, cstart + cl); 1151 break; 1152 } 1153 #endif 1154 } 1155 } 1156 } 1157 1158 1159 VOID 1160 RecoveryConsole(VOID) 1161 { 1162 CHAR szInputBuffer[256]; 1163 CONSOLE_SCREEN_BUFFER_INFO csbi; 1164 CONSOLE_STATE State; 1165 1166 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); 1167 1168 /* get screen size */ 1169 State.maxx = csbi.dwSize.X; 1170 State.maxy = csbi.dwSize.Y; 1171 State.bInsert = TRUE; 1172 State.bExit = FALSE; 1173 1174 CONSOLE_ClearScreen(); 1175 CONSOLE_SetCursorXY(0, 0); 1176 1177 CONSOLE_ConOutPrintf("ReactOS Recovery Console\n\nEnter HELP to get a list of commands.\n\n"); 1178 1179 while (!State.bExit) 1180 { 1181 /* Prompt */ 1182 CONSOLE_ConOutPrintf(">"); 1183 1184 ReadCommand(&State, szInputBuffer, 256); 1185 DPRINT1("%s\n", szInputBuffer); 1186 1187 DoCommand(&State, szInputBuffer); 1188 1189 // Cmd = ParseCommand(NULL); 1190 // if (!Cmd) 1191 // continue; 1192 1193 // ExecuteCommand(Cmd); 1194 // FreeCommand(Cmd); 1195 } 1196 } 1197 1198 /* EOF */ 1199