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
freep(LPSTR * p)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
StripQuotes(LPSTR in)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
add_entry(LPINT ac,LPSTR ** arg,LPCSTR entry)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 *
split(LPSTR s,LPINT args)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
HelpCls(VOID)252 HelpCls(VOID)
253 {
254 CONSOLE_ConOutPrintf("CLS\n\nClears the screen.\n\n");
255 }
256
257
258 static
259 INT
CommandCls(PCONSOLE_STATE State,LPSTR param)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
HexDump(PUCHAR buffer,ULONG size)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
HelpDumpSector(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
CommandDumpSector(PCONSOLE_STATE State,LPSTR param)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
HelpExit(VOID)482 HelpExit(VOID)
483 {
484 CONSOLE_ConOutPrintf("EXIT\n\nExits the repair console.\n\n");
485 }
486
487
488 static
489 INT
CommandExit(PCONSOLE_STATE State,LPSTR param)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
HelpHelp(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
CommandHelp(PCONSOLE_STATE State,LPSTR param)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
HelpPartInfo(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
CommandPartInfo(PCONSOLE_STATE State,LPSTR param)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
ClearCommandLine(LPSTR str,INT maxlen,SHORT orgx,SHORT orgy)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
ReadCommand(PCONSOLE_STATE State,LPSTR str,INT maxlen)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 = (USHORT)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
IsDelimiter(CHAR c)1073 IsDelimiter(
1074 CHAR c)
1075 {
1076 return (c == '/' || c == '=' || c == '\0' || isspace(c));
1077 }
1078
1079
1080 static
1081 VOID
DoCommand(PCONSOLE_STATE State,LPSTR line)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
RecoveryConsole(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