xref: /reactos/base/setup/usetup/cmdcons.c (revision 40462c92)
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