windows-nt/Source/XPSP1/NT/base/efiutil/sdk/shell/shellenv/conio.c

612 lines
13 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Intel Corporation
Module Name:
conio.c
Abstract:
Shell Environment driver
Revision History
--*/
#include "shelle.h"
/*
*
*/
#define MAX_HISTORY 20
#define INPUT_LINE_SIGNATURE EFI_SIGNATURE_32('i','s','i','g')
typedef struct {
UINTN Signature;
LIST_ENTRY Link;
CHAR16 Buffer[MAX_CMDLINE];
} INPUT_LINE;
/*
* Globals
*/
static BOOLEAN SEnvInsertMode;
static LIST_ENTRY SEnvLineHistory;
static UINTN SEnvNoHistory;
/*
*
*/
VOID
SEnvConIoInitDosKey (
VOID
)
{
InitializeListHead (&SEnvLineHistory);
SEnvInsertMode = FALSE;
SEnvNoHistory = 0;
}
/*
* Functions used to access the console interface via a file handle
* Used if the console is not being redirected to a file
*/
EFI_STATUS
SEnvConIoOpen (
IN struct _EFI_FILE_HANDLE *File,
OUT struct _EFI_FILE_HANDLE **NewHandle,
IN CHAR16 *FileName,
IN UINT64 OpenMode,
IN UINT64 Attributes
)
{
return EFI_NOT_FOUND;
}
EFI_STATUS
SEnvConIoNop (
IN struct _EFI_FILE_HANDLE *File
)
{
return EFI_SUCCESS;
}
EFI_STATUS
SEnvConIoGetPosition (
IN struct _EFI_FILE_HANDLE *File,
OUT UINT64 *Position
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
SEnvConIoSetPosition (
IN struct _EFI_FILE_HANDLE *File,
OUT UINT64 Position
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
SEnvConIoGetInfo (
IN struct _EFI_FILE_HANDLE *File,
IN EFI_GUID *InformationType,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
SEnvConIoSetInfo (
IN struct _EFI_FILE_HANDLE *File,
IN EFI_GUID *InformationType,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
SEnvConIoWrite (
IN struct _EFI_FILE_HANDLE *File,
IN OUT UINTN *BufferSize,
IN VOID *Buffer
)
{
Print (L"%.*s", *BufferSize, Buffer);
return EFI_SUCCESS;
}
EFI_STATUS
SEnvErrIoWrite (
IN struct _EFI_FILE_HANDLE *File,
IN OUT UINTN *BufferSize,
IN VOID *Buffer
)
{
IPrint (ST->StdErr, L"%.*s", *BufferSize, Buffer);
return EFI_SUCCESS;
}
EFI_STATUS
SEnvErrIoRead (
IN struct _EFI_FILE_HANDLE *File,
IN OUT UINTN *BufferSize,
IN VOID *Buffer
)
{
return EFI_UNSUPPORTED;
}
VOID
SEnvPrintHistory(
VOID
)
{
LIST_ENTRY *Link;
INPUT_LINE *Line;
UINTN Index;
Print (L"\n");
Index = 0;
for (Link=SEnvLineHistory.Flink; Link != &SEnvLineHistory; Link=Link->Flink) {
Index += 1;
Line = CR(Link, INPUT_LINE, Link, INPUT_LINE_SIGNATURE);
Print (L"%2d. %s\n", Index, Line->Buffer);
}
}
EFI_STATUS
SEnvConIoRead (
IN struct _EFI_FILE_HANDLE *File,
IN OUT UINTN *BufferSize,
IN VOID *Buffer
)
{
CHAR16 *Str;
BOOLEAN Done;
UINTN Column, Row;
UINTN Update, Delete;
UINTN Len, StrPos, MaxStr;
UINTN Index;
EFI_INPUT_KEY Key;
SIMPLE_TEXT_OUTPUT_INTERFACE *ConOut;
SIMPLE_INPUT_INTERFACE *ConIn;
INPUT_LINE *NewLine, *LineCmd;
LIST_ENTRY *LinePos, *NewPos;
ConOut = ST->ConOut;
ConIn = ST->ConIn;
Str = Buffer;
if (*BufferSize < sizeof(CHAR16)*2) {
*BufferSize = 0;
return EFI_SUCCESS;
}
/*
* Get input fields location
*/
Column = ConOut->Mode->CursorColumn;
Row = ConOut->Mode->CursorRow;
ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &MaxStr, &Index);
/* bugbug: for now wrapping is not handled */
MaxStr = MaxStr - Column;
/* Clip to max cmdline */
if (MaxStr > MAX_CMDLINE) {
MaxStr = MAX_CMDLINE;
}
/* Clip to user's buffer size */
if (MaxStr > (*BufferSize / sizeof(CHAR16)) - 1) {
MaxStr = (*BufferSize / sizeof(CHAR16)) - 1;
}
/*
* Allocate a new key entry
*/
NewLine = AllocateZeroPool (sizeof(INPUT_LINE));
if (!NewLine) {
return EFI_OUT_OF_RESOURCES;
}
NewLine->Signature = INPUT_LINE_SIGNATURE;
LinePos = &SEnvLineHistory;
/*
* Set new input
*/
Update = 0;
Delete = 0;
NewPos = &SEnvLineHistory;
ZeroMem (Str, MaxStr * sizeof(CHAR16));
Done = FALSE;
do {
/*
* If we have a new position, reset
*/
if (NewPos != &SEnvLineHistory) {
LineCmd = CR(NewPos, INPUT_LINE, Link, INPUT_LINE_SIGNATURE);
LinePos = NewPos;
NewPos = &SEnvLineHistory;
CopyMem (Str, LineCmd->Buffer, MaxStr * sizeof(CHAR16));
Index = Len; /* Save old len */
Len = StrLen(Str); /* Get new len */
StrPos = Len;
Update = 0; /* draw new input string */
if (Index > Len) {
Delete = Index - Len; /* if old string was longer, blank it */
}
}
/*
* If we need to update the output do so now
*/
if (Update != -1) {
PrintAt (Column+Update, Row, L"%s%.*s", Str + Update, Delete, L"");
Len = StrLen (Str);
if (Delete) {
SetMem(Str+Len, Delete * sizeof(CHAR16), 0x00);
}
if (StrPos > Len) {
StrPos = Len;
}
Update = -1;
Delete = 0;
}
/*
* Set the cursor position for this key
*/
ConOut->SetCursorPosition (ConOut, Column+StrPos, Row);
/*
* Read the key
*/
WaitForSingleEvent(ConIn->WaitForKey, 0);
ConIn->ReadKeyStroke(ConIn, &Key);
switch (Key.UnicodeChar) {
case CHAR_CARRIAGE_RETURN:
/*
* All done, print a newline at the end of the string
*/
PrintAt (Column+Len, Row, L"\n");
Done = TRUE;
break;
case CHAR_BACKSPACE:
if (StrPos) {
StrPos -= 1;
Update = StrPos;
Delete = 1;
CopyMem (Str+StrPos, Str+StrPos+1, sizeof(CHAR16) * (Len-StrPos));
}
break;
default:
if (Key.UnicodeChar >= ' ') {
/* If we are at the buffer's end, drop the key */
if (Len == MaxStr-1 &&
(SEnvInsertMode || StrPos == Len)) {
break;
}
if (SEnvInsertMode) {
for (Index=Len; Index > StrPos; Index -= 1) {
Str[Index] = Str[Index-1];
}
}
Str[StrPos] = Key.UnicodeChar;
Update = StrPos;
StrPos += 1;
}
break;
case 0:
switch (Key.ScanCode) {
case SCAN_DELETE:
if (Len) {
Update = StrPos;
Delete = 1;
CopyMem (Str+StrPos, Str+StrPos+1, sizeof(CHAR16) * (Len-StrPos));
}
break;
case SCAN_UP:
NewPos = LinePos->Blink;
if (NewPos == &SEnvLineHistory) {
NewPos = NewPos->Blink;
}
break;
case SCAN_DOWN:
NewPos = LinePos->Flink;
if (NewPos == &SEnvLineHistory) {
NewPos = NewPos->Flink;
}
break;
case SCAN_LEFT:
if (StrPos) {
StrPos -= 1;
}
break;
case SCAN_RIGHT:
if (StrPos < Len) {
StrPos += 1;
}
break;
case SCAN_HOME:
StrPos = 0;
break;
case SCAN_END:
StrPos = Len;
break;
case SCAN_ESC:
Str[0] = 0;
Update = 0;
Delete = Len;
break;
case SCAN_INSERT:
SEnvInsertMode = !SEnvInsertMode;
break;
case SCAN_F7:
SEnvPrintHistory();
*Str = 0;
Done = TRUE;
break;
}
}
} while (!Done);
/*
* Copy the line to the history buffer
*/
StrCpy (NewLine->Buffer, Str);
if (Str[0]) {
InsertTailList (&SEnvLineHistory, &NewLine->Link);
SEnvNoHistory += 1;
} else {
FreePool (NewLine);
}
/*
* If there's too much in the history buffer free an entry
*/
if (SEnvNoHistory > MAX_HISTORY) {
LineCmd = CR(SEnvLineHistory.Flink, INPUT_LINE, Link, INPUT_LINE_SIGNATURE);
RemoveEntryList (&LineCmd->Link);
SEnvNoHistory -= 1;
FreePool (LineCmd);
}
/*
* Return the data to the caller
*/
*BufferSize = Len * sizeof(CHAR16);
StrCpy(Buffer, Str);
return EFI_SUCCESS;
}
/*
*
*/
EFI_STATUS
SEnvReset (
IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
IN BOOLEAN ExtendedVerification
)
{
return EFI_SUCCESS;
}
EFI_STATUS
SEnvOutputString (
IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
IN CHAR16 *String
)
{
EFI_STATUS Status;
ENV_SHELL_REDIR_FILE *Redir;
UINTN Len, Size, WriteSize, Index, Start;
CHAR8 Buffer[100];
CHAR16 UnicodeBuffer[100];
BOOLEAN InvalidChar;
SIMPLE_INPUT_INTERFACE *TextIn = NULL;
SIMPLE_TEXT_OUTPUT_INTERFACE *TextOut = NULL;
Redir = CR(This, ENV_SHELL_REDIR_FILE, Out, ENV_REDIR_SIGNATURE);
if (EFI_ERROR(Redir->WriteError)) {
return(Redir->WriteError);
}
Status = EFI_SUCCESS;
InvalidChar = FALSE;
if (Redir->Ascii) {
Start = 0;
Len = StrLen (String);
while (Len) {
Size = Len > sizeof(Buffer) ? sizeof(Buffer) : Len;
for (Index=0; Index < Size; Index +=1) {
if (String[Start+Index] > 0xff) {
Buffer[Index] = '_';
InvalidChar = TRUE;
} else {
Buffer[Index] = (CHAR8) String[Start+Index];
}
}
WriteSize = Size;
Status = Redir->File->Write (Redir->File, &WriteSize, Buffer);
if (EFI_ERROR(Status)) {
break;
}
Len -= Size;
Start += Size;
}
} else {
Len = StrSize (String) - sizeof(CHAR16);
Status = Redir->File->Write (Redir->File, &Len, String);
}
if (EFI_ERROR(Status)) {
Redir->WriteError = Status;
SEnvBatchGetConsole( &TextIn, &TextOut );
SPrint(UnicodeBuffer,100,L"write error: %r\n\r",Status);
Status = TextOut->OutputString( TextOut, UnicodeBuffer);
}
if (InvalidChar && !EFI_ERROR(Status)) {
Status = EFI_WARN_UNKOWN_GLYPH;
}
return Status;
}
EFI_STATUS
SEnvTestString (
IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
IN CHAR16 *String
)
{
EFI_STATUS Status;
ENV_SHELL_REDIR_FILE *Redir;
Redir = CR(This, ENV_SHELL_REDIR_FILE, Out, ENV_REDIR_SIGNATURE);
Status = ST->ConOut->TestString(ST->ConOut, String);
if (!EFI_ERROR(Status) && Redir->Ascii) {
while (*String && *String < 0x100) {
String += 1;
}
if (*String > 0xff) {
Status = EFI_UNSUPPORTED;
}
}
return Status;
}
EFI_STATUS
SEnvQueryMode (
IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
IN UINTN ModeNumber,
OUT UINTN *Columns,
OUT UINTN *Rows
)
{
if (ModeNumber > 0) {
return EFI_INVALID_PARAMETER;
}
*Columns = 0;
*Rows = 0;
return EFI_SUCCESS;
}
EFI_STATUS
SEnvSetMode (
IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
IN UINTN ModeNumber
)
{
return ModeNumber > 0 ? EFI_INVALID_PARAMETER : EFI_SUCCESS;
}
EFI_STATUS
SEnvSetAttribute (
IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
IN UINTN Attribute
)
{
This->Mode->Attribute = (UINT32) Attribute;
return EFI_SUCCESS;
}
EFI_STATUS
SEnvClearScreen (
IN SIMPLE_TEXT_OUTPUT_INTERFACE *This
)
{
return EFI_SUCCESS;
}
EFI_STATUS
SEnvSetCursorPosition (
IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
IN UINTN Column,
IN UINTN Row
)
{
return EFI_UNSUPPORTED;
}
EFI_STATUS
SEnvEnableCursor (
IN SIMPLE_TEXT_OUTPUT_INTERFACE *This,
IN BOOLEAN Enable
)
{
This->Mode->CursorVisible = Enable;
return EFI_SUCCESS;
}