windows-nt/Source/XPSP1/NT/base/efiutil/sdk/shell/shellenv/doskey.c
2020-09-26 16:20:57 +08:00

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;
}