reactos/base/setup/usetup/cmdcons.c
2021-07-23 22:03:48 +02:00

1199 lines
30 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS text-mode setup
* FILE: base/setup/usetup/cmdcons.c
* PURPOSE: Recovery console
* PROGRAMMER:
*/
#include "usetup.h"
#define NDEBUG
#include <debug.h>
//#define FEATURE_HISTORY
typedef struct _CONSOLE_STATE
{
SHORT maxx;
SHORT maxy;
BOOLEAN bInsert;
BOOLEAN bExit;
} CONSOLE_STATE, *PCONSOLE_STATE;
typedef struct tagCOMMAND
{
LPSTR name;
INT flags;
INT (*func)(PCONSOLE_STATE, LPSTR);
VOID (*help)(VOID);
} COMMAND, *LPCOMMAND;
static
VOID
HelpCls(VOID);
static
INT
CommandCls(
PCONSOLE_STATE State,
LPSTR param);
static
VOID
HelpDumpSector(VOID);
static
INT
CommandDumpSector(
PCONSOLE_STATE State,
LPSTR param);
static
VOID
HelpExit(VOID);
static
INT
CommandExit(
PCONSOLE_STATE State,
LPSTR param);
static
VOID
HelpHelp(VOID);
static
INT
CommandHelp(
PCONSOLE_STATE State,
LPSTR param);
static
VOID
HelpPartInfo(VOID);
static
INT
CommandPartInfo(
PCONSOLE_STATE State,
LPSTR param);
COMMAND
Commands[] =
{
{"cls", 0, CommandCls, HelpCls},
{"dumpsector", 0, CommandDumpSector, HelpDumpSector},
{"exit", 0, CommandExit, HelpExit},
{"help", 0, CommandHelp, HelpHelp},
{"partinfo", 0, CommandPartInfo, HelpPartInfo},
{NULL, 0, NULL}
};
static
VOID
freep(
LPSTR *p)
{
LPSTR *q;
if (!p)
return;
q = p;
while (*q)
RtlFreeHeap(ProcessHeap, 0, *q++);
RtlFreeHeap(ProcessHeap, 0, p);
}
static
VOID
StripQuotes(
LPSTR in)
{
LPSTR out = in;
for (; *in; in++)
{
if (*in != '"')
*out++ = *in;
}
*out = '\0';
}
BOOL
add_entry(
LPINT ac,
LPSTR **arg,
LPCSTR entry)
{
LPSTR q;
LPSTR *oldarg;
q = RtlAllocateHeap(ProcessHeap, 0, strlen(entry) + 1);
if (q == NULL)
return FALSE;
strcpy(q, entry);
oldarg = *arg;
*arg = RtlReAllocateHeap(ProcessHeap, 0, oldarg, (*ac + 2) * sizeof(LPSTR));
if (*arg == NULL)
{
RtlFreeHeap(ProcessHeap, 0, q);
*arg = oldarg;
return FALSE;
}
/* save new entry */
(*arg)[*ac] = q;
(*arg)[++(*ac)] = NULL;
return TRUE;
}
static
LPSTR *
split(
LPSTR s,
LPINT args)
{
LPSTR *arg;
LPSTR start;
LPSTR q;
INT ac;
INT_PTR len;
BOOL bQuoted;
arg = RtlAllocateHeap(ProcessHeap, 0 , sizeof(LPTSTR));
if (arg == NULL)
return NULL;
*arg = NULL;
ac = 0;
while (*s)
{
bQuoted = FALSE;
/* skip leading spaces */
while (*s && (isspace(*s) || iscntrl(*s)))
++s;
start = s;
/* the first character can be '/' */
if (*s == '/')
s++;
/* skip to next word delimiter or start of next option */
while (isprint(*s))
{
/* if quote (") then set bQuoted */
bQuoted ^= (*s == '\"');
/* Check if we have unquoted text */
if (!bQuoted)
{
/* check for separators */
if (isspace(*s) || (*s == '/'))
{
/* Make length at least one character */
if (s == start)
s++;
break;
}
}
s++;
}
/* a word was found */
if (s != start)
{
len = s - start;
q = RtlAllocateHeap(ProcessHeap, 0, len + 1);
if (q == NULL)
{
freep(arg);
return NULL;
}
memcpy(q, start, len);
q[len] = '\0';
StripQuotes(q);
if (!add_entry(&ac, &arg, q))
{
RtlFreeHeap(ProcessHeap, 0, q);
freep(arg);
return NULL;
}
RtlFreeHeap(ProcessHeap, 0, q);
}
}
*args = ac;
return arg;
}
static
VOID
HelpCls(VOID)
{
CONSOLE_ConOutPrintf("CLS\n\nClears the screen.\n\n");
}
static
INT
CommandCls(
PCONSOLE_STATE State,
LPSTR param)
{
if (!strcmp(param, "/?"))
{
HelpCls();
return 0;
}
CONSOLE_ClearScreen();
CONSOLE_SetCursorXY(0, 0);
return 0;
}
void HexDump(PUCHAR buffer, ULONG size)
{
ULONG offset = 0;
PUCHAR ptr;
while (offset < (size & ~15))
{
ptr = (PUCHAR)((ULONG_PTR)buffer + offset);
CONSOLE_ConOutPrintf("%04lx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx\n",
offset,
ptr[0],
ptr[1],
ptr[2],
ptr[3],
ptr[4],
ptr[5],
ptr[6],
ptr[7],
ptr[8],
ptr[9],
ptr[10],
ptr[11],
ptr[12],
ptr[13],
ptr[14],
ptr[15]);
offset += 16;
}
if (offset < size)
{
ptr = (PUCHAR)((ULONG_PTR)buffer + offset);
CONSOLE_ConOutPrintf("%04lx ", offset);
while (offset < size)
{
CONSOLE_ConOutPrintf(" %02hx", *ptr);
offset++;
ptr++;
}
CONSOLE_ConOutPrintf("\n");
}
CONSOLE_ConOutPrintf("\n");
}
static
VOID
HelpDumpSector(VOID)
{
CONSOLE_ConOutPrintf("DUMPSECT DiskNumber Sector\n\nDumps a disk sector to the screen.\n\n");
}
static
INT
CommandDumpSector(
PCONSOLE_STATE State,
LPSTR param)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING PathName;
HANDLE hDisk = NULL;
DISK_GEOMETRY DiskGeometry;
NTSTATUS Status;
LPTSTR *argv = NULL;
INT argc = 0;
WCHAR DriveName[40];
ULONG ulDrive;
// ULONG ulSector;
LARGE_INTEGER Sector, SectorCount, Offset;
PUCHAR Buffer = NULL;
DPRINT1("param: %s\n", param);
if (!strcmp(param, "/?"))
{
HelpDumpSector();
return 0;
}
argv = split(param, &argc);
DPRINT1("argc: %d\n", argc);
DPRINT1("argv: %p\n", argv);
if (argc != 2)
{
goto done;
}
DPRINT1("Device: %s\n", argv[0]);
DPRINT1("Sector: %s\n", argv[1]);
ulDrive = strtoul(argv[0], NULL, 0);
// ulSector = strtoul(argv[1], NULL, 0);
Sector.QuadPart = _atoi64(argv[1]);
/* Build full drive name */
// swprintf(DriveName, L"\\\\.\\PHYSICALDRIVE%lu", ulDrive);
swprintf(DriveName, L"\\Device\\Harddisk%lu\\Partition0", ulDrive);
RtlInitUnicodeString(&PathName,
DriveName);
InitializeObjectAttributes(&ObjectAttributes,
&PathName,
OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
NULL,
NULL);
Status = NtOpenFile(&hDisk,
GENERIC_READ | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateFile failed (Status 0x%08lx)\n", Status);
goto done;
}
Status = NtDeviceIoControlFile(hDisk,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
&DiskGeometry,
sizeof(DISK_GEOMETRY));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtDeviceIoControlFile failed (Status 0x%08lx)\n", Status);
goto done;
}
DPRINT1("Drive number: %lu\n", ulDrive);
DPRINT1("Cylinders: %I64u\nMediaType: %x\nTracksPerCylinder: %lu\n"
"SectorsPerTrack: %lu\nBytesPerSector: %lu\n\n",
DiskGeometry.Cylinders.QuadPart,
DiskGeometry.MediaType,
DiskGeometry.TracksPerCylinder,
DiskGeometry.SectorsPerTrack,
DiskGeometry.BytesPerSector);
DPRINT1("Sector: %I64u\n", Sector.QuadPart);
SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
(ULONGLONG)DiskGeometry.TracksPerCylinder *
(ULONGLONG)DiskGeometry.SectorsPerTrack;
if (Sector.QuadPart >= SectorCount.QuadPart)
{
CONSOLE_ConOutPrintf("Invalid sector number! Valid range: [0 - %I64u]\n", SectorCount.QuadPart - 1);
goto done;
}
Buffer = RtlAllocateHeap(ProcessHeap, 0, DiskGeometry.BytesPerSector);
if (Buffer == NULL)
{
DPRINT1("Buffer allocation failed\n");
goto done;
}
Offset.QuadPart = Sector.QuadPart * DiskGeometry.BytesPerSector;
DPRINT1("Offset: %I64u\n", Offset.QuadPart);
Status = NtReadFile(hDisk,
NULL,
NULL,
NULL,
&IoStatusBlock,
Buffer,
DiskGeometry.BytesPerSector,
&Offset,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtReadFile failed (Status 0x%08lx)\n", Status);
goto done;
}
HexDump(Buffer, DiskGeometry.BytesPerSector);
done:
if (Buffer != NULL)
RtlFreeHeap(ProcessHeap, 0, Buffer);
if (hDisk != NULL)
NtClose(hDisk);
freep(argv);
return 0;
}
static
VOID
HelpExit(VOID)
{
CONSOLE_ConOutPrintf("EXIT\n\nExits the repair console.\n\n");
}
static
INT
CommandExit(
PCONSOLE_STATE State,
LPSTR param)
{
if (!strcmp(param, "/?"))
{
HelpExit();
return 0;
}
State->bExit = TRUE;
return 0;
}
static
VOID
HelpHelp(VOID)
{
CONSOLE_ConOutPrintf("HELP [Command]\n\nShows help on repair console commands.\n\n");
}
static
INT
CommandHelp(
PCONSOLE_STATE State,
LPSTR param)
{
LPCOMMAND cmdptr;
DPRINT1("param: %p %u '%s'\n", param, strlen(param), param);
if (!strcmp(param, "/?"))
{
HelpHelp();
return 0;
}
if (param != NULL && strlen(param) > 0)
{
for (cmdptr = Commands; cmdptr->name != NULL; cmdptr++)
{
if (!stricmp(param, cmdptr->name))
{
if (cmdptr->help != NULL)
{
cmdptr->help();
return 0;
}
}
}
}
CONSOLE_ConOutPrintf("CLS\n");
CONSOLE_ConOutPrintf("DUMPSECTOR\n");
CONSOLE_ConOutPrintf("EXIT\n");
CONSOLE_ConOutPrintf("HELP\n");
CONSOLE_ConOutPrintf("\n");
return 0;
}
static
VOID
HelpPartInfo(VOID)
{
CONSOLE_ConOutPrintf("PARTINFO DiskNumber\n\nDumps a partition table to the screen.\n\n");
}
static
INT
CommandPartInfo(
PCONSOLE_STATE State,
LPSTR param)
{
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING PathName;
HANDLE hDisk = NULL;
DISK_GEOMETRY DiskGeometry;
NTSTATUS Status;
LPTSTR *argv = NULL;
INT argc = 0;
WCHAR DriveName[40];
ULONG ulDrive, i;
PDRIVE_LAYOUT_INFORMATION LayoutBuffer = NULL;
PPARTITION_INFORMATION PartitionInfo;
DPRINT1("param: %s\n", param);
if (!strcmp(param, "/?"))
{
HelpPartInfo();
return 0;
}
argv = split(param, &argc);
DPRINT1("argc: %d\n", argc);
DPRINT1("argv: %p\n", argv);
if (argc != 1)
{
goto done;
}
DPRINT1("Device: %s\n", argv[0]);
ulDrive = strtoul(argv[0], NULL, 0);
/* Build full drive name */
swprintf(DriveName, L"\\Device\\Harddisk%lu\\Partition0", ulDrive);
RtlInitUnicodeString(&PathName,
DriveName);
InitializeObjectAttributes(&ObjectAttributes,
&PathName,
OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
NULL,
NULL);
Status = NtOpenFile(&hDisk,
GENERIC_READ | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateFile failed (Status 0x%08lx)\n", Status);
goto done;
}
Status = NtDeviceIoControlFile(hDisk,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
&DiskGeometry,
sizeof(DISK_GEOMETRY));
if (!NT_SUCCESS(Status))
{
DPRINT1("NtDeviceIoControlFile failed (Status 0x%08lx)\n", Status);
goto done;
}
CONSOLE_ConOutPrintf("Drive number: %lu\n", ulDrive);
CONSOLE_ConOutPrintf("Cylinders: %I64u\nMediaType: %x\nTracksPerCylinder: %lu\n"
"SectorsPerTrack: %lu\nBytesPerSector: %lu\n\n",
DiskGeometry.Cylinders.QuadPart,
DiskGeometry.MediaType,
DiskGeometry.TracksPerCylinder,
DiskGeometry.SectorsPerTrack,
DiskGeometry.BytesPerSector);
LayoutBuffer = RtlAllocateHeap(ProcessHeap,
HEAP_ZERO_MEMORY,
8192);
if (LayoutBuffer == NULL)
{
DPRINT1("LayoutBuffer allocation failed\n");
goto done;
}
Status = NtDeviceIoControlFile(hDisk,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DISK_GET_DRIVE_LAYOUT,
NULL,
0,
LayoutBuffer,
8192);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtDeviceIoControlFile(IOCTL_DISK_GET_DRIVE_LAYOUT) failed (Status 0x%08lx)\n", Status);
goto done;
}
CONSOLE_ConOutPrintf("Partitions: %lu Signature: %lx\n\n",
LayoutBuffer->PartitionCount,
LayoutBuffer->Signature);
CONSOLE_ConOutPrintf(" # Start Size Hidden Nr Type Boot\n");
CONSOLE_ConOutPrintf("-- --------------- --------------- ------------ -- ---- ----\n");
for (i = 0; i < LayoutBuffer->PartitionCount; i++)
{
PartitionInfo = &LayoutBuffer->PartitionEntry[i];
CONSOLE_ConOutPrintf("%2lu %15I64u %15I64u %12lu %2lu %2x %c\n",
i,
PartitionInfo->StartingOffset.QuadPart / DiskGeometry.BytesPerSector,
PartitionInfo->PartitionLength.QuadPart / DiskGeometry.BytesPerSector,
PartitionInfo->HiddenSectors,
PartitionInfo->PartitionNumber,
PartitionInfo->PartitionType,
PartitionInfo->BootIndicator ? '*': ' ');
}
CONSOLE_ConOutPrintf("\n");
done:
if (LayoutBuffer != NULL)
RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
if (hDisk != NULL)
NtClose(hDisk);
freep(argv);
return 0;
}
static
VOID
ClearCommandLine(
LPSTR str,
INT maxlen,
SHORT orgx,
SHORT orgy)
{
INT count;
CONSOLE_SetCursorXY(orgx, orgy);
for (count = 0; count < (INT)strlen(str); count++)
CONSOLE_ConOutChar(' ');
memset(str, 0, maxlen);
CONSOLE_SetCursorXY(orgx, orgy);
}
static
BOOL
ReadCommand(
PCONSOLE_STATE State,
LPSTR str,
INT maxlen)
{
SHORT orgx; /* origin x/y */
SHORT orgy;
SHORT curx; /*current x/y cursor position*/
SHORT cury;
SHORT tempscreen;
INT count; /*used in some for loops*/
INT current = 0; /*the position of the cursor in the string (str)*/
INT charcount = 0;/*chars in the string (str)*/
INPUT_RECORD ir;
CHAR ch;
BOOL bReturn = FALSE;
BOOL bCharInput;
#ifdef FEATURE_HISTORY
//BOOL bContinue=FALSE;/*is TRUE the second case will not be executed*/
CHAR PreviousChar;
#endif
CONSOLE_GetCursorXY(&orgx, &orgy);
curx = orgx;
cury = orgy;
memset(str, 0, maxlen * sizeof(CHAR));
CONSOLE_SetCursorType(State->bInsert, TRUE);
do
{
bReturn = FALSE;
CONSOLE_ConInKey(&ir);
if (ir.Event.KeyEvent.dwControlKeyState &
(RIGHT_ALT_PRESSED |LEFT_ALT_PRESSED|
RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED) )
{
switch (ir.Event.KeyEvent.wVirtualKeyCode)
{
#ifdef FEATURE_HISTORY
case 'K':
/*add the current command line to the history*/
if (ir.Event.KeyEvent.dwControlKeyState &
(LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
{
if (str[0])
History(0,str);
ClearCommandLine (str, maxlen, orgx, orgy);
current = charcount = 0;
curx = orgx;
cury = orgy;
//bContinue=TRUE;
break;
}
case 'D':
/*delete current history entry*/
if (ir.Event.KeyEvent.dwControlKeyState &
(LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED))
{
ClearCommandLine (str, maxlen, orgx, orgy);
History_del_current_entry(str);
current = charcount = strlen (str);
ConOutPrintf("%s", str);
GetCursorXY(&curx, &cury);
//bContinue=TRUE;
break;
}
#endif /*FEATURE_HISTORY*/
}
}
bCharInput = FALSE;
switch (ir.Event.KeyEvent.wVirtualKeyCode)
{
case VK_BACK:
/* <BACKSPACE> - delete character to left of cursor */
if (current > 0 && charcount > 0)
{
if (current == charcount)
{
/* if at end of line */
str[current - 1] = L'\0';
if (CONSOLE_GetCursorX () != 0)
{
CONSOLE_ConOutPrintf("\b \b");
curx--;
}
else
{
CONSOLE_SetCursorXY((SHORT)(State->maxx - 1), (SHORT)(CONSOLE_GetCursorY () - 1));
CONSOLE_ConOutChar(' ');
CONSOLE_SetCursorXY((SHORT)(State->maxx - 1), (SHORT)(CONSOLE_GetCursorY () - 1));
cury--;
curx = State->maxx - 1;
}
}
else
{
for (count = current - 1; count < charcount; count++)
str[count] = str[count + 1];
if (CONSOLE_GetCursorX () != 0)
{
CONSOLE_SetCursorXY ((SHORT)(CONSOLE_GetCursorX () - 1), CONSOLE_GetCursorY ());
curx--;
}
else
{
CONSOLE_SetCursorXY ((SHORT)(State->maxx - 1), (SHORT)(CONSOLE_GetCursorY () - 1));
cury--;
curx = State->maxx - 1;
}
CONSOLE_GetCursorXY(&curx, &cury);
CONSOLE_ConOutPrintf("%s ", &str[current - 1]);
CONSOLE_SetCursorXY(curx, cury);
}
charcount--;
current--;
}
break;
case VK_INSERT:
/* toggle insert/overstrike mode */
State->bInsert ^= TRUE;
CONSOLE_SetCursorType(State->bInsert, TRUE);
break;
case VK_DELETE:
/* delete character under cursor */
if (current != charcount && charcount > 0)
{
for (count = current; count < charcount; count++)
str[count] = str[count + 1];
charcount--;
CONSOLE_GetCursorXY(&curx, &cury);
CONSOLE_ConOutPrintf("%s ", &str[current]);
CONSOLE_SetCursorXY(curx, cury);
}
break;
case VK_HOME:
/* goto beginning of string */
if (current != 0)
{
CONSOLE_SetCursorXY(orgx, orgy);
curx = orgx;
cury = orgy;
current = 0;
}
break;
case VK_END:
/* goto end of string */
if (current != charcount)
{
CONSOLE_SetCursorXY(orgx, orgy);
CONSOLE_ConOutPrintf("%s", str);
CONSOLE_GetCursorXY(&curx, &cury);
current = charcount;
}
break;
case 'M':
case 'C':
/* ^M does the same as return */
bCharInput = TRUE;
if (!(ir.Event.KeyEvent.dwControlKeyState &
(RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED)))
{
break;
}
case VK_RETURN:
/* end input, return to main */
#ifdef FEATURE_HISTORY
/* add to the history */
if (str[0])
History (0, str);
#endif
str[charcount] = '\0';
CONSOLE_ConOutChar('\n');
bReturn = TRUE;
break;
case VK_ESCAPE:
/* clear str Make this callable! */
ClearCommandLine (str, maxlen, orgx, orgy);
curx = orgx;
cury = orgy;
current = charcount = 0;
break;
#ifdef FEATURE_HISTORY
case VK_F3:
History_move_to_bottom();
#endif
case VK_UP:
#ifdef FEATURE_HISTORY
/* get previous command from buffer */
ClearCommandLine (str, maxlen, orgx, orgy);
History (-1, str);
current = charcount = strlen (str);
if (((charcount + orgx) / maxx) + orgy > maxy - 1)
orgy += maxy - ((charcount + orgx) / maxx + orgy + 1);
CONSOLE_ConOutPrintf("%s", str);
CONSOLE_GetCursorXY(&curx, &cury);
#endif
break;
case VK_DOWN:
#ifdef FEATURE_HISTORY
/* get next command from buffer */
ClearCommandLine (str, maxlen, orgx, orgy);
History (1, str);
current = charcount = strlen (str);
if (((charcount + orgx) / maxx) + orgy > maxy - 1)
orgy += maxy - ((charcount + orgx) / maxx + orgy + 1);
CONSOLE_ConOutPrintf("%s", str);
CONSOLE_GetCursorXY(&curx, &cury);
#endif
break;
case VK_LEFT:
/* move cursor left */
if (current > 0)
{
current--;
if (CONSOLE_GetCursorX() == 0)
{
CONSOLE_SetCursorXY((SHORT)(State->maxx - 1), (SHORT)(CONSOLE_GetCursorY () - 1));
curx = State->maxx - 1;
cury--;
}
else
{
CONSOLE_SetCursorXY((SHORT)(CONSOLE_GetCursorX () - 1), CONSOLE_GetCursorY ());
curx--;
}
}
break;
case VK_RIGHT:
/* move cursor right */
if (current != charcount)
{
current++;
if (CONSOLE_GetCursorX() == State->maxx - 1)
{
CONSOLE_SetCursorXY(0, (SHORT)(CONSOLE_GetCursorY () + 1));
curx = 0;
cury++;
}
else
{
CONSOLE_SetCursorXY((SHORT)(CONSOLE_GetCursorX () + 1), CONSOLE_GetCursorY ());
curx++;
}
}
#ifdef FEATURE_HISTORY
else
{
LPCSTR last = PeekHistory(-1);
if (last && charcount < (INT)strlen (last))
{
PreviousChar = last[current];
CONSOLE_ConOutChar(PreviousChar);
CONSOLE_GetCursorXY(&curx, &cury);
str[current++] = PreviousChar;
charcount++;
}
}
#endif
break;
default:
/* This input is just a normal char */
bCharInput = TRUE;
}
ch = ir.Event.KeyEvent.uChar.UnicodeChar;
if (ch >= 32 && (charcount != (maxlen - 2)) && bCharInput)
{
/* insert character into string... */
if (State->bInsert && current != charcount)
{
/* If this character insertion will cause screen scrolling,
* adjust the saved origin of the command prompt. */
tempscreen = (USHORT)strlen(str + current) + curx;
if ((tempscreen % State->maxx) == (State->maxx - 1) &&
(tempscreen / State->maxx) + cury == (State->maxy - 1))
{
orgy--;
cury--;
}
for (count = charcount; count > current; count--)
str[count] = str[count - 1];
str[current++] = ch;
if (curx == State->maxx - 1)
curx = 0, cury++;
else
curx++;
CONSOLE_ConOutPrintf("%s", &str[current - 1]);
CONSOLE_SetCursorXY(curx, cury);
charcount++;
}
else
{
if (current == charcount)
charcount++;
str[current++] = ch;
if (CONSOLE_GetCursorX () == State->maxx - 1 && CONSOLE_GetCursorY () == State->maxy - 1)
orgy--, cury--;
if (CONSOLE_GetCursorX () == State->maxx - 1)
curx = 0, cury++;
else
curx++;
CONSOLE_ConOutChar(ch);
}
}
}
while (!bReturn);
CONSOLE_SetCursorType(State->bInsert, TRUE);
return TRUE;
}
static
BOOL
IsDelimiter(
CHAR c)
{
return (c == '/' || c == '=' || c == '\0' || isspace(c));
}
static
VOID
DoCommand(
PCONSOLE_STATE State,
LPSTR line)
{
CHAR com[MAX_PATH]; /* the first word in the command */
LPSTR cp = com;
// LPSTR cstart;
LPSTR rest = line; /* pointer to the rest of the command line */
// INT cl;
LPCOMMAND cmdptr;
DPRINT1("DoCommand: (\'%s\')\n", line);
/* Skip over initial white space */
while (isspace(*rest))
rest++;
// cstart = rest;
/* Anything to do ? */
if (*rest)
{
/* Copy over 1st word as lower case */
while (!IsDelimiter(*rest))
*cp++ = tolower(*rest++);
/* Terminate first word */
*cp = '\0';
/* Skip over whitespace to rest of line */
while (isspace (*rest))
rest++;
/* Scan internal command table */
for (cmdptr = Commands; ; cmdptr++)
{
/* If end of table execute ext cmd */
if (cmdptr->name == NULL)
{
CONSOLE_ConOutPuts("Unknown command. Enter HELP to get a list of commands.");
break;
}
if (stricmp(com, cmdptr->name) == 0)
{
cmdptr->func(State, rest);
break;
}
#if 0
/* The following code handles the case of commands like CD which
* are recognised even when the command name and parameter are
* not space separated.
*
* e.g dir..
* cd\freda
*/
/* Get length of command name */
cl = strlen(cmdptr->name);
if ((cmdptr->flags & CMD_SPECIAL) &&
(!strncmp (cmdptr->name, com, cl)) &&
(strchr("\\.-", *(com + cl))))
{
/* OK its one of the specials...*/
/* Call with new rest */
cmdptr->func(State, cstart + cl);
break;
}
#endif
}
}
}
VOID
RecoveryConsole(VOID)
{
CHAR szInputBuffer[256];
CONSOLE_SCREEN_BUFFER_INFO csbi;
CONSOLE_STATE State;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
/* get screen size */
State.maxx = csbi.dwSize.X;
State.maxy = csbi.dwSize.Y;
State.bInsert = TRUE;
State.bExit = FALSE;
CONSOLE_ClearScreen();
CONSOLE_SetCursorXY(0, 0);
CONSOLE_ConOutPrintf("ReactOS Recovery Console\n\nEnter HELP to get a list of commands.\n\n");
while (!State.bExit)
{
/* Prompt */
CONSOLE_ConOutPrintf(">");
ReadCommand(&State, szInputBuffer, 256);
DPRINT1("%s\n", szInputBuffer);
DoCommand(&State, szInputBuffer);
// Cmd = ParseCommand(NULL);
// if (!Cmd)
// continue;
// ExecuteCommand(Cmd);
// FreeCommand(Cmd);
}
}
/* EOF */