You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
611 lines
14 KiB
611 lines
14 KiB
/*++
|
|
|
|
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;
|
|
}
|