382 lines
9.5 KiB
C
382 lines
9.5 KiB
C
/*/###########################################################################
|
|
//**
|
|
//** Copyright (C) 1996-97 Intel Corporation. All rights reserved.
|
|
//**
|
|
//** The information and source code contained herein is the exclusive
|
|
//** property of Intel Corporation and may not be disclosed, examined
|
|
//** from the company.
|
|
//**
|
|
*//* ########################################################################### */
|
|
|
|
#include "EfiShell.h"
|
|
#include "doskey.h"
|
|
|
|
#define isprint(a) ((a) >= ' ')
|
|
|
|
CHAR16 *DosKeyInsert (DosKey_t *DosKey);
|
|
CHAR16 *DosKeyPreviousCurrent (DosKey_t *DosKey);
|
|
CHAR16 *DosKeyGetCommandLine (DosKey_t *DosKey);
|
|
|
|
|
|
#define MAX_LINE 256
|
|
#define MAX_HISTORY 20
|
|
|
|
|
|
typedef struct {
|
|
UINTN Signature;
|
|
LIST_ENTRY Link;
|
|
CHAR16 Buffer[MAX_LINE];
|
|
} INPUT_LINE;
|
|
|
|
|
|
/*
|
|
* Globals
|
|
*/
|
|
|
|
|
|
static BOOLEAN ShellEnvInsertMode;
|
|
static LIST_ENTRY *ShellEnvCurrentLine;
|
|
static LIST_ENTRY ShellEnvLineHistory;
|
|
static UINTN ShellEnvNoHistory;
|
|
|
|
|
|
VOID
|
|
DosKeyDelete (
|
|
IN OUT DosKey_t *DosKey
|
|
)
|
|
{
|
|
INTN NewEnd;
|
|
|
|
if (DosKey->Start != DosKey->End) {
|
|
NewEnd = (DosKey->End==0)?(MAX_HISTORY-1):(DosKey->End - 1);
|
|
if (DosKey->Current == NewEnd) {
|
|
DosKey->Current = (DosKey->Current==0)?(MAX_HISTORY-1):(DosKey->Current - 1);
|
|
}
|
|
DosKey->End = NewEnd;
|
|
}
|
|
}
|
|
|
|
CHAR16 *
|
|
DosKeyInsert (
|
|
IN OUT DosKey_t *DosKey
|
|
)
|
|
{
|
|
INTN Next;
|
|
INTN Data;
|
|
INTN i;
|
|
|
|
Data = DosKey->End;
|
|
Next = ((DosKey->End + 1) % MAX_HISTORY);
|
|
if (DosKey->Start == Next) {
|
|
/* Wrap case */
|
|
DosKey->Start = ((DosKey->Start + 1) % MAX_HISTORY);
|
|
}
|
|
DosKey->End = Next;
|
|
for (i=0; i<MAX_CMDLINE; i++) {
|
|
DosKey->Buffer[Data][i] = '\0';
|
|
}
|
|
DosKey->Current = Data;
|
|
return (&(DosKey->Buffer[Data][0]));
|
|
}
|
|
|
|
CHAR16 *
|
|
DosKeyPreviousCurrent (
|
|
IN OUT DosKey_t *DosKey
|
|
)
|
|
{
|
|
INTN Next;
|
|
|
|
Next = (DosKey->Current==0)?(MAX_HISTORY-1):(DosKey->Current - 1);
|
|
if (DosKey->Start < DosKey->End) {
|
|
if ((Next >= DosKey->Start) && (Next != (MAX_HISTORY-1))) {
|
|
DosKey->Current = Next;
|
|
}
|
|
} else if (DosKey->Start > DosKey->End){
|
|
/* Allways a Full Buffer */
|
|
if (Next != DosKey->End) {
|
|
DosKey->Current = Next;
|
|
}
|
|
} else {
|
|
/* No Data */
|
|
}
|
|
return (&(DosKey->Buffer[DosKey->Current][0]));
|
|
}
|
|
|
|
CHAR16 *
|
|
DosKeyNextCurrent (
|
|
IN OUT DosKey_t *DosKey
|
|
)
|
|
{
|
|
INTN Next;
|
|
|
|
Next = ((DosKey->Current + 1) % MAX_HISTORY);
|
|
if (DosKey->Start < DosKey->End) {
|
|
if (Next != DosKey->End) {
|
|
DosKey->Current = Next;
|
|
}
|
|
} else if (DosKey->Start > DosKey->End){
|
|
/* Allways a Full Buffer */
|
|
if (Next != DosKey->Start) {
|
|
DosKey->Current = Next;
|
|
}
|
|
} else {
|
|
/* No Data */
|
|
}
|
|
return (&(DosKey->Buffer[DosKey->Current][0]));
|
|
}
|
|
|
|
VOID
|
|
PrintDosKeyBuffer(
|
|
IN OUT DosKey_t *DosKey
|
|
)
|
|
{
|
|
INTN i;
|
|
INTN Index;
|
|
|
|
Index = 1;
|
|
if (DosKey->Start < DosKey->End) {
|
|
for (i = DosKey->End - 1; i >= DosKey->Start; i--) {
|
|
if (DosKey->Buffer[i][0] != '\0') {
|
|
Print (L"\n%2d:%2d: %s",Index++, i, DosKey->Buffer[i]);
|
|
} else {
|
|
Print (L"\n :%2d:",i);
|
|
}
|
|
}
|
|
} else if (DosKey->Start > DosKey->End) {
|
|
for (i = DosKey->End -1; i >= 0; i--) {
|
|
if (DosKey->Buffer[i][0] != '\0') {
|
|
Print (L"\n%2d:%2d: %s",Index++, i, DosKey->Buffer[i]);
|
|
} else {
|
|
Print (L"\n :%2d:",i);
|
|
}
|
|
}
|
|
for (i = (MAX_HISTORY-1); i >= DosKey->Start; i--) {
|
|
if (DosKey->Buffer[i][0] != '\0') {
|
|
Print(L"\n%2d:%2d: %s",Index++, i, DosKey->Buffer[i]);
|
|
} else {
|
|
Print(L"\n :%2d:",i);
|
|
}
|
|
}
|
|
} else /* if (DosKey->Start == DosKey->End) */{
|
|
}
|
|
}
|
|
|
|
CHAR16 *
|
|
ShellEnvReadLine (
|
|
|
|
|
|
DosKeyGetCommandLine (
|
|
IN DosKey_t *DosKey
|
|
)
|
|
{
|
|
CHAR16 Str[MAX_CMDLINE];
|
|
CHAR16 *CommandLine;
|
|
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;
|
|
|
|
|
|
ConOut = ST->ConOut;
|
|
ConIn = ST->ConIn;
|
|
|
|
/*
|
|
* Get input fields location
|
|
*/
|
|
|
|
Column = ConOut->CursorColumn;
|
|
Row = ConOut->CursorRow;
|
|
ConOut->QueryMode (ConOut, ConOut->Mode, &MaxStr, &Index);
|
|
|
|
/* bugbug: for now wrapping is not handled */
|
|
MaxStr = MaxStr - Column;
|
|
if (MaxStr > MAX_CMDLINE) {
|
|
MaxStr = MAX_CMDLINE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Set new input
|
|
*/
|
|
|
|
CommandLine = DosKeyInsert(DosKey);
|
|
SetMem(Str, sizeof(Str), 0x00);
|
|
Update = 0;
|
|
Delete = 0;
|
|
|
|
Done = FALSE;
|
|
do {
|
|
/*
|
|
* 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
|
|
*/
|
|
|
|
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");
|
|
if (*Str == 0) {
|
|
DosKeyDelete(DosKey);
|
|
}
|
|
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 (isprint(Key.UnicodeChar)) {
|
|
/* If we are at the buffer's end, drop the key */
|
|
if (Len == MaxStr-1 &&
|
|
(DosKey->InsertMode || StrPos == Len)) {
|
|
break;
|
|
}
|
|
|
|
if (DosKey->InsertMode) {
|
|
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 (StrLen) {
|
|
Update = StrPos;
|
|
Delete = 1;
|
|
CopyMem (Str+StrPos, Str+StrPos+1, sizeof(CHAR16) * (Len-StrPos));
|
|
}
|
|
break;
|
|
|
|
case SCAN_UP:
|
|
StrCpy(Str, DosKeyPreviousCurrent(DosKey));
|
|
|
|
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 */
|
|
}
|
|
break;
|
|
|
|
case SCAN_DOWN:
|
|
StrCpy(Str, DosKeyNextCurrent(DosKey));
|
|
|
|
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 */
|
|
}
|
|
|
|
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:
|
|
DosKey->InsertMode = !DosKey->InsertMode;
|
|
break;
|
|
|
|
case SCAN_F7:
|
|
DosKeyDelete(DosKey);
|
|
PrintDosKeyBuffer(DosKey);
|
|
*Str = 0;
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
} while (!Done);
|
|
|
|
StrCpy (CommandLine, Str);
|
|
return (CommandLine);
|
|
}
|
|
|
|
VOID
|
|
RemoveFirstCharFromString(
|
|
IN OUT CHAR16 *Str
|
|
)
|
|
{
|
|
UINTN Length;
|
|
CHAR16 *NewData;
|
|
|
|
NewData = Str + 1;
|
|
Length = StrLen(NewData);
|
|
while (Length-- != 0) {
|
|
*Str++ = *NewData++;
|
|
}
|
|
*Str = 0;
|
|
}
|