mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-14 10:05:43 +01:00
1942 lines
38 KiB
C
1942 lines
38 KiB
C
/*++
|
|
|
|
Copyright (c) 2005 - 2007, Intel Corporation
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
Module Name:
|
|
|
|
IO.c
|
|
|
|
Abstract:
|
|
|
|
the IO library function
|
|
|
|
Revision History
|
|
|
|
--*/
|
|
|
|
//#include "EfiShellLib.h"
|
|
#include "Platform.h"
|
|
|
|
#define PRINT_STRING_LEN 1024
|
|
#define PRINT_ITEM_BUFFER_LEN 100
|
|
#define PRINT_JOINT_BUFFER_LEN 4
|
|
|
|
typedef struct {
|
|
BOOLEAN Ascii;
|
|
UINTN Index;
|
|
union {
|
|
CONST CHAR16 *pw;
|
|
CHAR8 *pc;
|
|
} u;
|
|
} POINTER;
|
|
|
|
typedef struct _pitem {
|
|
|
|
POINTER Item;
|
|
CHAR16 *Scratch;
|
|
UINTN Width;
|
|
UINTN FieldWidth;
|
|
UINTN *WidthParse;
|
|
CHAR16 Pad;
|
|
BOOLEAN PadBefore;
|
|
BOOLEAN Comma;
|
|
BOOLEAN Long;
|
|
} PRINT_ITEM;
|
|
|
|
typedef struct _pstate {
|
|
//
|
|
// Input
|
|
//
|
|
POINTER fmt;
|
|
VA_LIST args;
|
|
|
|
//
|
|
// Output
|
|
//
|
|
CHAR16 *Buffer;
|
|
CHAR16 *End;
|
|
CHAR16 *Pos;
|
|
UINTN Len;
|
|
|
|
UINTN Attr;
|
|
UINTN RestoreAttr;
|
|
|
|
UINTN AttrNorm;
|
|
UINTN AttrHighlight;
|
|
UINTN AttrError;
|
|
UINTN AttrBlueColor;
|
|
UINTN AttrGreenColor;
|
|
|
|
EFI_STATUS (EFIAPI *Output) (VOID *context, CHAR16 *str);
|
|
EFI_STATUS (EFIAPI *SetAttr) (VOID *context, UINTN attr);
|
|
VOID *Context;
|
|
|
|
//
|
|
// Current item being formatted
|
|
//
|
|
struct _pitem *Item;
|
|
} PRINT_STATE;
|
|
|
|
typedef struct {
|
|
BOOLEAN PageBreak;
|
|
BOOLEAN AutoWrap;
|
|
INTN MaxRow;
|
|
INTN MaxColumn;
|
|
INTN InitRow;
|
|
INTN Row;
|
|
INTN Column;
|
|
BOOLEAN OmitPrint;
|
|
BOOLEAN OutputPause;
|
|
} PRINT_MODE;
|
|
|
|
PRINT_MODE mPrintMode;
|
|
|
|
//
|
|
// Internal fucntions
|
|
//
|
|
UINTN
|
|
_PPrint (
|
|
IN PRINT_STATE *ps
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
_SPrint (
|
|
IN VOID *Context,
|
|
IN CHAR16 *Buffer
|
|
);
|
|
|
|
UINTN
|
|
EFIAPI
|
|
_IPrint (
|
|
IN UINTN Column,
|
|
IN UINTN Row,
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Out,
|
|
IN CHAR16 *fmt,
|
|
IN CHAR8 *fmta,
|
|
IN VA_LIST args
|
|
);
|
|
|
|
VOID
|
|
EFIAPI
|
|
_PoolCatPrint (
|
|
IN CONST CHAR16 *fmt,
|
|
IN VA_LIST args,
|
|
IN OUT POOL_PRINT *spc,
|
|
IN EFI_STATUS
|
|
(EFIAPI
|
|
*Output)
|
|
(
|
|
VOID *context,
|
|
CHAR16 *str
|
|
)
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
_PoolPrint (
|
|
IN VOID *Context,
|
|
IN CHAR16 *Buffer
|
|
);
|
|
|
|
VOID
|
|
PFLUSH (
|
|
IN OUT PRINT_STATE *ps
|
|
);
|
|
|
|
VOID
|
|
IFlushWithPageBreak (
|
|
IN OUT PRINT_STATE *ps
|
|
);
|
|
|
|
VOID
|
|
PPUTC (
|
|
IN OUT PRINT_STATE *ps,
|
|
IN CHAR16 c
|
|
);
|
|
|
|
CHAR16
|
|
PGETC (
|
|
IN POINTER *p
|
|
);
|
|
|
|
VOID
|
|
PITEM (
|
|
IN OUT PRINT_STATE *ps
|
|
);
|
|
|
|
VOID
|
|
PSETATTR (
|
|
IN OUT PRINT_STATE *ps,
|
|
IN UINTN Attr
|
|
);
|
|
|
|
VOID
|
|
SetOutputPause (
|
|
IN BOOLEAN Pause
|
|
);
|
|
|
|
VOID
|
|
SetCursorPosition (
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
|
|
IN UINTN Column,
|
|
IN INTN Row,
|
|
IN UINTN LineLength,
|
|
IN UINTN TotalRow,
|
|
IN CHAR16 *Str,
|
|
IN UINTN StrPos,
|
|
IN UINTN Len
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
_DbgOut (
|
|
IN VOID *Context,
|
|
IN CHAR16 *Buffer
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
_SPrint (
|
|
IN VOID *Context,
|
|
IN CHAR16 *Buffer
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Print function
|
|
|
|
Arguments:
|
|
|
|
Context - The Context
|
|
Buffer - The Buffer
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
INTN len;
|
|
POOL_PRINT *spc;
|
|
|
|
// ASSERT (Context != NULL);
|
|
// ASSERT (Buffer != NULL);
|
|
if (!Context || !Buffer) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
spc = Context;
|
|
len = StrLen (Buffer);
|
|
|
|
//
|
|
// Is the string is over the max truncate it
|
|
//
|
|
if (spc->Len + len > spc->Maxlen) {
|
|
len = spc->Maxlen - spc->Len;
|
|
}
|
|
//
|
|
// Append the new text
|
|
//
|
|
CopyMem (spc->Str + spc->Len, Buffer, len * sizeof (CHAR16));
|
|
spc->Len += len;
|
|
|
|
//
|
|
// Null terminate it
|
|
//
|
|
if (spc->Len < spc->Maxlen) {
|
|
spc->Str[spc->Len] = 0;
|
|
} else if (spc->Maxlen) {
|
|
spc->Str[spc->Maxlen] = 0;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
EFIAPI
|
|
_PoolCatPrint (
|
|
IN CONST CHAR16 *fmt,
|
|
IN VA_LIST args,
|
|
IN OUT POOL_PRINT *spc,
|
|
IN EFI_STATUS
|
|
(EFIAPI
|
|
*Output)
|
|
(
|
|
VOID *context,
|
|
CHAR16 *str
|
|
)
|
|
)
|
|
/*++'
|
|
|
|
Routine Description:
|
|
|
|
Pool print
|
|
|
|
Arguments:
|
|
fmt - fmt
|
|
args - args
|
|
spc - spc
|
|
Output - Output
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
PRINT_STATE ps;
|
|
|
|
SetMem (&ps, sizeof (ps), 0);
|
|
ps.Output = Output;
|
|
ps.Context = spc;
|
|
ps.fmt.u.pw = fmt;
|
|
//ps.args = args;
|
|
VA_COPY(ps.args, args);
|
|
_PPrint (&ps);
|
|
VA_END(ps.args);
|
|
}
|
|
|
|
CHAR16 *
|
|
EFIAPI
|
|
PoolPrint (
|
|
IN CONST CHAR16 *fmt,
|
|
...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a formatted unicode string to allocated pool. The caller
|
|
must free the resulting buffer.
|
|
|
|
Arguments:
|
|
|
|
fmt - The format string
|
|
|
|
Returns:
|
|
|
|
Allocated buffer with the formatted string printed in it.
|
|
The caller must free the allocated buffer. The buffer
|
|
allocation is not packed.
|
|
|
|
--*/
|
|
{
|
|
POOL_PRINT spc;
|
|
VA_LIST args;
|
|
|
|
ZeroMem (&spc, sizeof (spc));
|
|
VA_START (args, fmt);
|
|
_PoolCatPrint (fmt, args, &spc, _PoolPrint);
|
|
VA_END(args);
|
|
return spc.Str;
|
|
}
|
|
|
|
UINTN
|
|
EFIAPI
|
|
PrintAt (
|
|
IN UINTN Column,
|
|
IN UINTN Row,
|
|
IN CHAR16 *fmt,
|
|
...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a formatted unicode string to the default console, at
|
|
the supplied cursor position
|
|
|
|
Arguments:
|
|
|
|
fmt - Format string
|
|
Column, Row - The cursor position to print the string at
|
|
|
|
Returns:
|
|
|
|
Length of string printed to the console
|
|
|
|
--*/
|
|
{
|
|
VA_LIST args;
|
|
UINTN ret;
|
|
|
|
VA_START (args, fmt);
|
|
ret = _IPrint (Column, Row, gST->ConOut, fmt, NULL, args);
|
|
VA_END(args);
|
|
return ret;
|
|
}
|
|
|
|
UINTN
|
|
EFIAPI
|
|
_IPrint (
|
|
IN UINTN Column,
|
|
IN UINTN Row,
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Out,
|
|
IN CHAR16 *fmt,
|
|
IN CHAR8 *fmta,
|
|
IN VA_LIST args
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Display string worker for: Print, PrintAt, IPrint, IPrintAt
|
|
|
|
Arguments:
|
|
|
|
Column - Column
|
|
Row - Row
|
|
Out - Out
|
|
fmt - fmt
|
|
fmta - fmta
|
|
args - args
|
|
|
|
Returns:
|
|
|
|
|
|
--*/
|
|
{
|
|
PRINT_STATE ps;
|
|
UINTN back;
|
|
|
|
// ASSERT (NULL != Out);
|
|
if (!Out) {
|
|
return 0;
|
|
}
|
|
|
|
SetMem (&ps, sizeof (ps), 0);
|
|
ps.Context = Out;
|
|
ps.Output = (EFI_STATUS (EFIAPI *) (VOID *, CHAR16 *)) Out->OutputString;
|
|
ps.SetAttr = (EFI_STATUS (EFIAPI *) (VOID *, UINTN)) Out->SetAttribute;
|
|
// ASSERT (NULL != Out->Mode);
|
|
if (!Out->Mode) {
|
|
return 0;
|
|
}
|
|
ps.Attr = Out->Mode->Attribute;
|
|
|
|
back = (ps.Attr >> 4) & 0xF;
|
|
ps.AttrNorm = EFI_TEXT_ATTR (((~back) & 0x07), back);
|
|
ps.AttrHighlight = EFI_TEXT_ATTR (EFI_WHITE, back);
|
|
ps.AttrError = EFI_TEXT_ATTR (EFI_YELLOW, back);
|
|
ps.AttrBlueColor = EFI_TEXT_ATTR (EFI_LIGHTBLUE, back);
|
|
ps.AttrGreenColor = EFI_TEXT_ATTR (EFI_LIGHTGREEN, back);
|
|
|
|
if (fmt) {
|
|
ps.fmt.u.pw = fmt;
|
|
} else {
|
|
ps.fmt.Ascii = TRUE;
|
|
ps.fmt.u.pc = fmta;
|
|
}
|
|
|
|
//ps.args = args;
|
|
VA_COPY(ps.args, args);
|
|
|
|
if (Column != (UINTN) -1) {
|
|
Out->SetCursorPosition (Out, Column, Row);
|
|
}
|
|
|
|
back = _PPrint (&ps);
|
|
VA_END(ps.args);
|
|
return back;
|
|
}
|
|
|
|
UINTN
|
|
EFIAPI
|
|
IPrint (
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Out,
|
|
IN CHAR16 *fmt,
|
|
...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a formatted unicode string to the specified console
|
|
|
|
Arguments:
|
|
|
|
Out - The console to print the string too
|
|
|
|
fmt - Format string
|
|
|
|
Returns:
|
|
|
|
Length of string printed to the console
|
|
|
|
--*/
|
|
{
|
|
VA_LIST args;
|
|
UINTN ret;
|
|
|
|
VA_START (args, fmt);
|
|
ret = _IPrint ((UINTN) -1, (UINTN) -1, Out, fmt, NULL, args);
|
|
VA_END(args);
|
|
return ret;
|
|
}
|
|
|
|
UINTN
|
|
EFIAPI
|
|
IPrintAt (
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Out,
|
|
IN UINTN Column,
|
|
IN UINTN Row,
|
|
IN CHAR16 *fmt,
|
|
...
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a formatted unicode string to the specified console, at
|
|
the supplied cursor position
|
|
|
|
Arguments:
|
|
|
|
Out - The console to print the string too
|
|
|
|
Column, Row - The cursor position to print the string at
|
|
|
|
fmt - Format string
|
|
|
|
Returns:
|
|
|
|
Length of string printed to the console
|
|
|
|
--*/
|
|
{
|
|
VA_LIST args;
|
|
UINTN ret;
|
|
|
|
VA_START (args, fmt);
|
|
ret = _IPrint (Column, Row, gST->ConOut, fmt, NULL, args);
|
|
VA_END(args);
|
|
return ret;
|
|
}
|
|
|
|
VOID
|
|
PFLUSH (
|
|
IN OUT PRINT_STATE *ps
|
|
)
|
|
{
|
|
EFI_INPUT_KEY Key;
|
|
EFI_STATUS Status;
|
|
|
|
*ps->Pos = 0;
|
|
if (((UINTN) ps->Context == (UINTN) gST->ConOut) && mPrintMode.PageBreak) {
|
|
|
|
IFlushWithPageBreak (ps);
|
|
|
|
} else {
|
|
|
|
if (mPrintMode.OutputPause) {
|
|
|
|
Status = EFI_NOT_READY;
|
|
while (EFI_ERROR (Status)) {
|
|
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
|
|
}
|
|
|
|
SetOutputPause (FALSE);
|
|
}
|
|
|
|
ps->Output (ps->Context, ps->Buffer);
|
|
}
|
|
|
|
CopyMem (
|
|
((CHAR8 *) (ps->Buffer)) - PRINT_JOINT_BUFFER_LEN,
|
|
((CHAR8 *) (ps->Pos)) - PRINT_JOINT_BUFFER_LEN,
|
|
PRINT_JOINT_BUFFER_LEN
|
|
);
|
|
ps->Pos = ps->Buffer;
|
|
}
|
|
|
|
void
|
|
PSETATTR (
|
|
IN OUT PRINT_STATE *ps,
|
|
IN UINTN Attr
|
|
)
|
|
{
|
|
// ASSERT (ps != NULL);
|
|
if (!ps) {
|
|
return;
|
|
}
|
|
PFLUSH (ps);
|
|
|
|
ps->RestoreAttr = ps->Attr;
|
|
if (ps->SetAttr) {
|
|
ps->SetAttr (ps->Context, Attr);
|
|
}
|
|
|
|
ps->Attr = Attr;
|
|
}
|
|
|
|
void
|
|
PPUTC (
|
|
IN OUT PRINT_STATE *ps,
|
|
IN CHAR16 c
|
|
)
|
|
{
|
|
// ASSERT (ps != NULL);
|
|
if (!ps) {
|
|
return;
|
|
}
|
|
//
|
|
// If Omit print to ConOut, then return.
|
|
//
|
|
if (mPrintMode.OmitPrint && ((UINTN) ps->Context == (UINTN) gST->ConOut)) {
|
|
return ;
|
|
}
|
|
//
|
|
// if this is a newline and carriage return does not exist,
|
|
// add a carriage return
|
|
//
|
|
if (c == '\n' && ps->Pos >= ps->Buffer && (CHAR16) *(ps->Pos - 1) != '\r') {
|
|
PPUTC (ps, '\r');
|
|
}
|
|
|
|
*ps->Pos = c;
|
|
ps->Pos += 1;
|
|
ps->Len += 1;
|
|
|
|
//
|
|
// if at the end of the buffer, flush it
|
|
//
|
|
if (ps->Pos >= ps->End) {
|
|
PFLUSH (ps);
|
|
}
|
|
}
|
|
|
|
CHAR16
|
|
PGETC (
|
|
IN POINTER *p
|
|
)
|
|
{
|
|
CHAR16 c;
|
|
|
|
ASSERT (p != NULL);
|
|
if (!p) {
|
|
return 0;
|
|
}
|
|
|
|
c = (CHAR16) (p->Ascii ? p->u.pc[p->Index] : p->u.pw[p->Index]);
|
|
p->Index += 1;
|
|
|
|
return c;
|
|
}
|
|
|
|
void
|
|
PITEM (
|
|
IN OUT PRINT_STATE *ps
|
|
)
|
|
{
|
|
UINTN Len;
|
|
|
|
UINTN i;
|
|
PRINT_ITEM *Item;
|
|
CHAR16 c;
|
|
|
|
// ASSERT (ps != NULL);
|
|
if (!ps) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get the length of the item
|
|
//
|
|
Item = ps->Item;
|
|
Item->Item.Index = 0;
|
|
while (Item->Item.Index < Item->FieldWidth) {
|
|
c = PGETC (&Item->Item);
|
|
if (!c) {
|
|
Item->Item.Index -= 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Len = Item->Item.Index;
|
|
|
|
//
|
|
// if there is no item field width, use the items width
|
|
//
|
|
if (Item->FieldWidth == (UINTN) -1) {
|
|
Item->FieldWidth = Len;
|
|
}
|
|
//
|
|
// if item is larger then width, update width
|
|
//
|
|
if (Len > Item->Width) {
|
|
Item->Width = Len;
|
|
}
|
|
//
|
|
// if pad field before, add pad char
|
|
//
|
|
if (Item->PadBefore) {
|
|
for (i = Item->Width; i < Item->FieldWidth; i += 1) {
|
|
PPUTC (ps, ' ');
|
|
}
|
|
}
|
|
//
|
|
// pad item
|
|
//
|
|
for (i = Len; i < Item->Width; i++) {
|
|
PPUTC (ps, Item->Pad);
|
|
}
|
|
//
|
|
// add the item
|
|
//
|
|
Item->Item.Index = 0;
|
|
while (Item->Item.Index < Len) {
|
|
PPUTC (ps, PGETC (&Item->Item));
|
|
}
|
|
//
|
|
// If pad at the end, add pad char
|
|
//
|
|
if (!Item->PadBefore) {
|
|
for (i = Item->Width; i < Item->FieldWidth; i += 1) {
|
|
PPUTC (ps, ' ');
|
|
}
|
|
}
|
|
}
|
|
|
|
UINTN
|
|
_PPrint (
|
|
IN PRINT_STATE *ps
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
%w.lF - w = width
|
|
l = field width
|
|
F = format of arg
|
|
|
|
Args F:
|
|
0 - pad with zeros
|
|
- - justify on left (default is on right)
|
|
, - add comma's to field
|
|
* - width provided on stack
|
|
n - Set output attribute to normal (for this field only)
|
|
h - Set output attribute to highlight (for this field only)
|
|
e - Set output attribute to error (for this field only)
|
|
b - Set output attribute to blue color (for this field only)
|
|
v - Set output attribute to green color (for this field only)
|
|
l - Value is 64 bits
|
|
|
|
a - ascii string
|
|
s - unicode string
|
|
X - fixed 8 byte value in hex
|
|
x - hex value
|
|
d - value as decimal
|
|
c - Unicode char
|
|
t - EFI time structure
|
|
g - Pointer to GUID
|
|
r - EFI status code (result code)
|
|
|
|
N - Set output attribute to normal
|
|
H - Set output attribute to highlight
|
|
E - Set output attribute to error
|
|
B - Set output attribute to blue color
|
|
V - Set output attribute to green color
|
|
% - Print a %
|
|
|
|
Arguments:
|
|
|
|
ps - Ps
|
|
|
|
Returns:
|
|
|
|
Number of charactors written
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR16 c;
|
|
UINTN Attr;
|
|
PRINT_ITEM Item;
|
|
CHAR16 *Buffer;
|
|
// EFI_GUID *TmpGUID;
|
|
|
|
// ASSERT (ps != NULL);
|
|
if (!ps) {
|
|
return 0;
|
|
}
|
|
//
|
|
// If Omit print to ConOut, then return 0.
|
|
//
|
|
if (mPrintMode.OmitPrint && ((UINTN) ps->Context == (UINTN) gST->ConOut)) {
|
|
return 0;
|
|
}
|
|
|
|
Item.Scratch = (__typeof__(Item.Scratch))AllocateZeroPool (sizeof (CHAR16) * PRINT_ITEM_BUFFER_LEN);
|
|
if (NULL == Item.Scratch) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Buffer = (__typeof__(Buffer))AllocateZeroPool (sizeof (CHAR16) * PRINT_STRING_LEN);
|
|
if (NULL == Buffer) {
|
|
FreePool (Item.Scratch);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ps->Len = 0;
|
|
ps->Buffer = (CHAR16 *) ((CHAR8 *) Buffer + PRINT_JOINT_BUFFER_LEN);
|
|
ps->Pos = ps->Buffer;
|
|
ps->End = Buffer + PRINT_STRING_LEN - 1;
|
|
ps->Item = &Item;
|
|
|
|
ps->fmt.Index = 0;
|
|
c = PGETC (&ps->fmt);
|
|
while (c) {
|
|
|
|
if (c != '%') {
|
|
PPUTC (ps, c);
|
|
c = PGETC (&ps->fmt);
|
|
continue;
|
|
}
|
|
//
|
|
// setup for new item
|
|
//
|
|
Item.FieldWidth = (UINTN) -1;
|
|
Item.Width = 0;
|
|
Item.WidthParse = &Item.Width;
|
|
Item.Pad = ' ';
|
|
Item.PadBefore = TRUE;
|
|
Item.Comma = FALSE;
|
|
Item.Long = FALSE;
|
|
Item.Item.Ascii = FALSE;
|
|
Item.Item.u.pw = NULL;
|
|
ps->RestoreAttr = 0;
|
|
Attr = 0;
|
|
|
|
c = PGETC (&ps->fmt);
|
|
while (c) {
|
|
|
|
switch (c) {
|
|
|
|
case '%':
|
|
//
|
|
// %% -> %
|
|
//
|
|
Item.Scratch[0] = '%';
|
|
Item.Scratch[1] = 0;
|
|
Item.Item.u.pw = Item.Scratch;
|
|
break;
|
|
|
|
case '0':
|
|
Item.Pad = '0';
|
|
break;
|
|
|
|
case '-':
|
|
Item.PadBefore = FALSE;
|
|
break;
|
|
|
|
case ',':
|
|
Item.Comma = TRUE;
|
|
break;
|
|
|
|
case '.':
|
|
Item.WidthParse = &Item.FieldWidth;
|
|
break;
|
|
|
|
case '*':
|
|
*Item.WidthParse = VA_ARG (ps->args, UINTN);
|
|
break;
|
|
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
*Item.WidthParse = 0;
|
|
do {
|
|
*Item.WidthParse = *Item.WidthParse * 10 + c - '0';
|
|
c = PGETC (&ps->fmt);
|
|
} while (c >= '0' && c <= '9');
|
|
ps->fmt.Index -= 1;
|
|
break;
|
|
|
|
case 'a':
|
|
Item.Item.u.pc = VA_ARG (ps->args, CHAR8 *);
|
|
Item.Item.Ascii = TRUE;
|
|
if (!Item.Item.u.pc) {
|
|
Item.Item.u.pc = "(null)";
|
|
}
|
|
|
|
Item.PadBefore = FALSE;
|
|
break;
|
|
|
|
case 's':
|
|
Item.Item.u.pw = VA_ARG (ps->args, CHAR16 *);
|
|
if (!Item.Item.u.pw) {
|
|
Item.Item.u.pw = L"(null)";
|
|
}
|
|
|
|
Item.PadBefore = FALSE;
|
|
break;
|
|
|
|
case 'c':
|
|
Item.Scratch[0] = (CHAR16) VA_ARG (ps->args, UINTN);
|
|
Item.Scratch[1] = 0;
|
|
Item.Item.u.pw = Item.Scratch;
|
|
break;
|
|
|
|
case 'l':
|
|
Item.Long = TRUE;
|
|
break;
|
|
|
|
case 'X':
|
|
Item.Width = Item.Long ? 16 : 8;
|
|
Item.Pad = '0';
|
|
|
|
case 'x':
|
|
//SPrint(Buffer, 64, L"EFI Error №%r", (UINTN)Status);
|
|
// ValueToHex (
|
|
UnicodeSPrint(
|
|
Item.Scratch, 64, L"%x",
|
|
Item.Long ? VA_ARG (ps->args, UINT64) : VA_ARG (ps->args, UINTN)
|
|
);
|
|
Item.Item.u.pw = Item.Scratch;
|
|
|
|
break;
|
|
/*
|
|
case 'g':
|
|
TmpGUID = VA_ARG (ps->args, EFI_GUID *);
|
|
if (TmpGUID != NULL) {
|
|
Item.Item.u.pw = Item.Scratch;
|
|
GuidToString (Item.Item.u.pw, TmpGUID);
|
|
}
|
|
break;
|
|
*/
|
|
case 'd':
|
|
// ValueToString (
|
|
UnicodeSPrint(
|
|
Item.Scratch, 64, L"%d",
|
|
// Item.Comma,
|
|
Item.Long ? VA_ARG (ps->args, UINT64) : VA_ARG (ps->args, INTN)
|
|
);
|
|
Item.Item.u.pw = Item.Scratch;
|
|
break;
|
|
/*
|
|
case 't':
|
|
Item.Item.u.pw = Item.Scratch;
|
|
TimeToString (Item.Item.u.pw, VA_ARG (ps->args, EFI_TIME *));
|
|
break;
|
|
*/
|
|
case 'r':
|
|
// StatusToString
|
|
UnicodeSPrint(Item.Scratch, 64, L"%r", VA_ARG (ps->args, EFI_STATUS));
|
|
Item.Item.u.pw = Item.Scratch;
|
|
break;
|
|
|
|
case 'n':
|
|
PSETATTR (ps, ps->AttrNorm);
|
|
break;
|
|
|
|
case 'h':
|
|
PSETATTR (ps, ps->AttrHighlight);
|
|
break;
|
|
|
|
case 'b':
|
|
PSETATTR (ps, ps->AttrBlueColor);
|
|
break;
|
|
|
|
case 'v':
|
|
PSETATTR (ps, ps->AttrGreenColor);
|
|
break;
|
|
|
|
case 'e':
|
|
PSETATTR (ps, ps->AttrError);
|
|
break;
|
|
|
|
case 'N':
|
|
Attr = ps->AttrNorm;
|
|
break;
|
|
|
|
case 'H':
|
|
Attr = ps->AttrHighlight;
|
|
break;
|
|
|
|
case 'E':
|
|
Attr = ps->AttrError;
|
|
break;
|
|
|
|
case 'B':
|
|
Attr = ps->AttrBlueColor;
|
|
break;
|
|
|
|
case 'V':
|
|
Attr = ps->AttrGreenColor;
|
|
break;
|
|
|
|
default:
|
|
Item.Scratch[0] = '?';
|
|
Item.Scratch[1] = 0;
|
|
Item.Item.u.pw = Item.Scratch;
|
|
break;
|
|
}
|
|
//
|
|
// if we have an Item
|
|
//
|
|
if (Item.Item.u.pw) {
|
|
PITEM (ps);
|
|
break;
|
|
}
|
|
//
|
|
// if we have an Attr set
|
|
//
|
|
if (Attr) {
|
|
PSETATTR (ps, Attr);
|
|
ps->RestoreAttr = 0;
|
|
break;
|
|
}
|
|
|
|
c = PGETC (&ps->fmt);
|
|
}
|
|
|
|
if (ps->RestoreAttr) {
|
|
PSETATTR (ps, ps->RestoreAttr);
|
|
}
|
|
|
|
c = PGETC (&ps->fmt);
|
|
}
|
|
//
|
|
// Flush buffer
|
|
//
|
|
PFLUSH (ps);
|
|
|
|
FreePool (Item.Scratch);
|
|
FreePool (Buffer);
|
|
|
|
return ps->Len;
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
WaitForSingleEvent (
|
|
IN EFI_EVENT Event,
|
|
IN UINT64 Timeout OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
|
|
EFI_EVENT WaitList[3];
|
|
EFI_EVENT TimerEvent;
|
|
|
|
if (Timeout != 0)
|
|
{
|
|
//
|
|
// Create a timer event
|
|
//
|
|
Status = gBS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &TimerEvent);
|
|
if (!EFI_ERROR (Status))
|
|
{
|
|
//
|
|
// Set the timer event
|
|
//
|
|
gBS->SetTimer(TimerEvent, TimerRelative, Timeout);
|
|
|
|
//
|
|
// Wait for the original event or the timer
|
|
//
|
|
WaitList[0] = Event;
|
|
WaitList[1] = TimerEvent;
|
|
|
|
Status = gBS->WaitForEvent(2, WaitList, &Index);
|
|
gBS->CloseEvent (TimerEvent);
|
|
if (!EFI_ERROR (Status) && Index == 1)
|
|
{
|
|
Status = EFI_TIMEOUT;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WaitList[0] = Event;
|
|
Status = gBS->WaitForEvent (1, WaitList, &Index);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
//set Timeout in ms
|
|
EFI_STATUS
|
|
WaitFor2EventWithTsc (
|
|
IN EFI_EVENT Event1,
|
|
IN EFI_EVENT Event2,
|
|
IN UINT64 Timeout OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
EFI_EVENT WaitList[2];
|
|
UINT64 t0, t1;
|
|
UINT64 Delta = DivU64x64Remainder(MultU64x64(Timeout, gCPUStructure.TSCFrequency), 1000, NULL);
|
|
|
|
if (Timeout != 0)
|
|
{
|
|
t0 = AsmReadTsc();
|
|
do {
|
|
Status = gBS->CheckEvent(Event1);
|
|
if (!EFI_ERROR(Status)) {
|
|
break;
|
|
}
|
|
if (Event2) {
|
|
Status = gBS->CheckEvent(Event2);
|
|
if (!EFI_ERROR(Status)) {
|
|
break;
|
|
}
|
|
}
|
|
// Let's try to relax processor a bit
|
|
CpuPause();
|
|
Status = EFI_TIMEOUT;
|
|
t1 = AsmReadTsc();
|
|
} while ((t1 - t0) < Delta);
|
|
}
|
|
else
|
|
{
|
|
WaitList[0] = Event1;
|
|
WaitList[1] = Event2;
|
|
Status = gBS->WaitForEvent (2, WaitList, &Index);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
SetPageBreak (
|
|
IN OUT PRINT_STATE *ps
|
|
)
|
|
{
|
|
EFI_INPUT_KEY Key;
|
|
CHAR16 Str[3];
|
|
|
|
// ASSERT (ps != NULL);
|
|
if (!ps) {
|
|
return FALSE;
|
|
}
|
|
|
|
ps->Output (ps->Context, L"Press ENTER to continue, 'q' to exit:");
|
|
|
|
//
|
|
// Wait for user input
|
|
//
|
|
Str[0] = ' ';
|
|
Str[1] = 0;
|
|
Str[2] = 0;
|
|
for (;;) {
|
|
WaitForSingleEvent (gST->ConIn->WaitForKey, 0);
|
|
gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
|
|
|
|
//
|
|
// handle control keys
|
|
//
|
|
if (Key.UnicodeChar == CHAR_NULL) {
|
|
if (Key.ScanCode == SCAN_ESC) {
|
|
ps->Output (ps->Context, L"\r\n");
|
|
mPrintMode.OmitPrint = TRUE;
|
|
break;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
|
|
ps->Output (ps->Context, L"\r\n");
|
|
mPrintMode.Row = mPrintMode.InitRow;
|
|
break;
|
|
}
|
|
//
|
|
// Echo input
|
|
//
|
|
Str[1] = Key.UnicodeChar;
|
|
if (Str[1] == CHAR_BACKSPACE) {
|
|
continue;
|
|
}
|
|
|
|
ps->Output (ps->Context, Str);
|
|
|
|
if ((Str[1] == L'q') || (Str[1] == L'Q')) {
|
|
mPrintMode.OmitPrint = TRUE;
|
|
} else {
|
|
mPrintMode.OmitPrint = FALSE;
|
|
}
|
|
|
|
Str[0] = CHAR_BACKSPACE;
|
|
}
|
|
|
|
return mPrintMode.OmitPrint;
|
|
}
|
|
|
|
void
|
|
IFlushWithPageBreak (
|
|
IN OUT PRINT_STATE *ps
|
|
)
|
|
{
|
|
CHAR16 *Pos;
|
|
CHAR16 *LineStart;
|
|
CHAR16 LineEndChar;
|
|
|
|
// ASSERT (ps != NULL);
|
|
if (!ps) {
|
|
return;
|
|
}
|
|
|
|
Pos = ps->Buffer;
|
|
LineStart = Pos;
|
|
while ((*Pos != 0) && (Pos < ps->Pos)) {
|
|
if ((*Pos == L'\n') && (*(Pos - 1) == L'\r')) {
|
|
//
|
|
// Output one line
|
|
//
|
|
LineEndChar = *(Pos + 1);
|
|
*(Pos + 1) = 0;
|
|
ps->Output (ps->Context, LineStart);
|
|
*(Pos + 1) = LineEndChar;
|
|
//
|
|
// restore line end char
|
|
//
|
|
LineStart = Pos + 1;
|
|
mPrintMode.Column = 0;
|
|
mPrintMode.Row++;
|
|
if (mPrintMode.Row == mPrintMode.MaxRow) {
|
|
if (SetPageBreak (ps)) {
|
|
return ;
|
|
}
|
|
}
|
|
} else {
|
|
if (*Pos == CHAR_BACKSPACE) {
|
|
mPrintMode.Column--;
|
|
} else {
|
|
mPrintMode.Column++;
|
|
}
|
|
//
|
|
// If column is at the end of line, output a new line feed.
|
|
//
|
|
if ((mPrintMode.Column == mPrintMode.MaxColumn) && (*Pos != L'\n') && (*Pos != L'\r')) {
|
|
|
|
LineEndChar = *(Pos + 1);
|
|
*(Pos + 1) = 0;
|
|
ps->Output (ps->Context, LineStart);
|
|
*(Pos + 1) = LineEndChar;
|
|
//
|
|
// restore line end char
|
|
//
|
|
if (mPrintMode.AutoWrap) {
|
|
ps->Output (ps->Context, L"\r\n");
|
|
}
|
|
|
|
LineStart = Pos + 1;
|
|
mPrintMode.Column = 0;
|
|
mPrintMode.Row++;
|
|
if (mPrintMode.Row == mPrintMode.MaxRow) {
|
|
if (SetPageBreak (ps)) {
|
|
return ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Pos++;
|
|
}
|
|
|
|
if (*LineStart != 0) {
|
|
ps->Output (ps->Context, LineStart);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SetOutputPause (
|
|
IN BOOLEAN Pause
|
|
)
|
|
{
|
|
EFI_TPL Tpl;
|
|
|
|
Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);
|
|
mPrintMode.OutputPause = Pause;
|
|
gBS->RestoreTPL (Tpl);
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
_PoolPrint (
|
|
IN VOID *Context,
|
|
IN CHAR16 *Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Append string worker for PoolPrint and CatPrint
|
|
|
|
Arguments:
|
|
Context - Context
|
|
Buffer - Buffer
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
UINTN newlen;
|
|
POOL_PRINT *spc;
|
|
|
|
// ASSERT (Context != NULL);
|
|
if (!Context) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
spc = Context;
|
|
newlen = spc->Len + StrLen (Buffer) + 1;
|
|
|
|
//
|
|
// Is the string is over the max, grow the buffer
|
|
//
|
|
if (newlen > spc->Maxlen) {
|
|
//
|
|
// Grow the pool buffer
|
|
//
|
|
newlen += PRINT_STRING_LEN;
|
|
spc->Maxlen = newlen;
|
|
spc->Str = (__typeof__(spc->Str))EfiReallocatePool (
|
|
spc->Str,
|
|
spc->Len * sizeof (CHAR16),
|
|
spc->Maxlen * sizeof (CHAR16)
|
|
);
|
|
|
|
if (!spc->Str) {
|
|
spc->Len = 0;
|
|
spc->Maxlen = 0;
|
|
}
|
|
}
|
|
//
|
|
// Append the new text
|
|
//
|
|
return _SPrint (Context, Buffer);
|
|
}
|
|
|
|
VOID
|
|
Output (
|
|
IN CHAR16 *Str
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write a string to the console at the current cursor location
|
|
|
|
Arguments:
|
|
|
|
Str - string
|
|
|
|
Returns:
|
|
|
|
|
|
--*/
|
|
{
|
|
gST->ConOut->OutputString (gST->ConOut, Str);
|
|
}
|
|
|
|
VOID
|
|
Input (
|
|
IN CHAR16 *Prompt OPTIONAL,
|
|
OUT CHAR16 *InStr,
|
|
IN UINTN StrLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Input a string at the current cursor location, for StrLen
|
|
|
|
Arguments:
|
|
|
|
Prompt - Prompt
|
|
InStr - The input string
|
|
StrLen - The string buffer length
|
|
|
|
Returns:
|
|
|
|
|
|
--*/
|
|
{
|
|
IInput (
|
|
gST->ConOut,
|
|
gST->ConIn,
|
|
Prompt,
|
|
InStr,
|
|
StrLen
|
|
);
|
|
}
|
|
|
|
VOID
|
|
ConMoveCursorBackward (
|
|
IN UINTN LineLength,
|
|
IN OUT UINTN *Column,
|
|
IN OUT UINTN *Row
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Move the cursor position one character backward.
|
|
|
|
Arguments:
|
|
LineLength Length of a line. Get it by calling QueryMode
|
|
Column Current column of the cursor position
|
|
Row Current row of the cursor position
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
// ASSERT (Column != NULL);
|
|
// ASSERT (Row != NULL);
|
|
if (!Column || !Row) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If current column is 0, move to the last column of the previous line,
|
|
// otherwise, just decrement column.
|
|
//
|
|
if (*Column == 0) {
|
|
(*Column) = LineLength - 1;
|
|
//
|
|
// if (*Row > 0) {
|
|
//
|
|
(*Row)--;
|
|
//
|
|
// }
|
|
//
|
|
} else {
|
|
(*Column)--;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ConMoveCursorForward (
|
|
IN UINTN LineLength,
|
|
IN UINTN TotalRow,
|
|
IN OUT UINTN *Column,
|
|
IN OUT UINTN *Row
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Move the cursor position one character backward.
|
|
|
|
Arguments:
|
|
LineLength Length of a line. Get it by calling QueryMode
|
|
TotalRow Total row of a screen, get by calling QueryMode
|
|
Column Current column of the cursor position
|
|
Row Current row of the cursor position
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
// ASSERT (Column != NULL);
|
|
// ASSERT (Row != NULL);
|
|
if (!Column || !Row) {
|
|
return;
|
|
}
|
|
//
|
|
// If current column is at line end, move to the first column of the nest
|
|
// line, otherwise, just increment column.
|
|
//
|
|
(*Column)++;
|
|
if (*Column >= LineLength) {
|
|
(*Column) = 0;
|
|
if ((*Row) < TotalRow - 1) {
|
|
(*Row)++;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
IInput (
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * ConOut,
|
|
IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL * ConIn,
|
|
IN CHAR16 *Prompt OPTIONAL,
|
|
OUT CHAR16 *InStr,
|
|
IN UINTN StrLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Input a string at the current cursor location, for StrLength
|
|
|
|
Arguments:
|
|
ConOut Console output protocol
|
|
ConIn Console input protocol
|
|
Prompt Prompt string
|
|
InStr Buffer to hold the input string
|
|
StrLength Length of the buffer
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN Done;
|
|
UINTN Column;
|
|
INTN Row;
|
|
UINTN StartColumn;
|
|
UINTN Update;
|
|
UINTN Delete;
|
|
UINTN Len;
|
|
UINTN StrPos;
|
|
UINTN Index;
|
|
UINTN LineLength;
|
|
UINTN TotalRow;
|
|
UINTN SkipLength;
|
|
UINTN OutputLength;
|
|
UINTN TailRow;
|
|
UINTN TailColumn;
|
|
EFI_INPUT_KEY Key;
|
|
BOOLEAN InsertMode;
|
|
|
|
// ASSERT (ConOut != NULL);
|
|
// ASSERT (ConIn != NULL);
|
|
// ASSERT (InStr != NULL);
|
|
if (!ConOut || !ConIn || !InStr) {
|
|
return;
|
|
}
|
|
|
|
if (Prompt) {
|
|
ConOut->OutputString (ConOut, Prompt);
|
|
}
|
|
//
|
|
// Read a line from the console
|
|
//
|
|
// Len = 0;
|
|
// StrPos = 0;
|
|
OutputLength = 0;
|
|
Update = 0;
|
|
Delete = 0;
|
|
InsertMode = TRUE;
|
|
|
|
//
|
|
// If buffer is not large enough to hold a CHAR16, do nothing.
|
|
//
|
|
if (StrLength < 1) {
|
|
return ;
|
|
}
|
|
//
|
|
// Get the screen setting and the current cursor location
|
|
//
|
|
StartColumn = ConOut->Mode->CursorColumn;
|
|
Column = StartColumn;
|
|
Row = ConOut->Mode->CursorRow;
|
|
ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &LineLength, &TotalRow);
|
|
if (LineLength == 0) {
|
|
return ;
|
|
}
|
|
|
|
// SetMem (InStr, StrLength * sizeof (CHAR16), 0);
|
|
//prepare default string
|
|
Len = StrLen(InStr);
|
|
StrPos = 0;
|
|
OutputLength = Len;
|
|
Print(L"%s", InStr);
|
|
Done = FALSE;
|
|
ConOut->SetCursorPosition (ConOut, Column, Row);
|
|
do {
|
|
//
|
|
// Read a 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
|
|
//
|
|
TailRow = Row + (Len - StrPos + Column) / LineLength;
|
|
TailColumn = (Len - StrPos + Column) % LineLength;
|
|
Done = TRUE;
|
|
break;
|
|
|
|
case CHAR_BACKSPACE:
|
|
if (StrPos) {
|
|
//
|
|
// If not move back beyond string beginning, move all characters behind
|
|
// the current position one character forward
|
|
//
|
|
StrPos -= 1;
|
|
Update = StrPos;
|
|
Delete = 1;
|
|
CopyMem (InStr + StrPos, InStr + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
|
|
|
|
//
|
|
// Adjust the current column and row
|
|
//
|
|
ConMoveCursorBackward (LineLength, &Column, (UINTN *)&Row);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (Key.UnicodeChar >= ' ') {
|
|
//
|
|
// If we are at the buffer's end, drop the key
|
|
//
|
|
if ((Len == StrLength - 1) && (InsertMode || StrPos == Len)) {
|
|
break;
|
|
}
|
|
//
|
|
// If in insert mode, move all characters behind the current position
|
|
// one character backward to make space for this character. Then store
|
|
// the character.
|
|
//
|
|
if (InsertMode) {
|
|
for (Index = Len; Index > StrPos; Index--) {
|
|
InStr[Index] = InStr[Index - 1];
|
|
}
|
|
}
|
|
|
|
InStr[StrPos] = Key.UnicodeChar;
|
|
Update = StrPos;
|
|
|
|
StrPos++;
|
|
OutputLength++;
|
|
}
|
|
break;
|
|
|
|
case 0:
|
|
switch (Key.ScanCode) {
|
|
case SCAN_DELETE:
|
|
//
|
|
// Move characters behind current position one character forward
|
|
//
|
|
if (Len) {
|
|
Update = StrPos;
|
|
Delete = 1;
|
|
CopyMem (InStr + StrPos, InStr + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
|
|
}
|
|
break;
|
|
|
|
case SCAN_LEFT:
|
|
//
|
|
// Adjust current cursor position
|
|
//
|
|
if (StrPos) {
|
|
StrPos -= 1;
|
|
ConMoveCursorBackward (LineLength, &Column, (UINTN *)&Row);
|
|
}
|
|
break;
|
|
|
|
case SCAN_RIGHT:
|
|
//
|
|
// Adjust current cursor position
|
|
//
|
|
if (StrPos < Len) {
|
|
StrPos += 1;
|
|
ConMoveCursorForward (LineLength, TotalRow, &Column, (UINTN *)&Row);
|
|
}
|
|
break;
|
|
|
|
case SCAN_HOME:
|
|
//
|
|
// Move current cursor position to the beginning of the command line
|
|
//
|
|
Row -= (StrPos + StartColumn) / LineLength;
|
|
Column = StartColumn;
|
|
StrPos = 0;
|
|
break;
|
|
|
|
case SCAN_END:
|
|
//
|
|
// Move current cursor position to the end of the command line
|
|
//
|
|
TailRow = Row + (Len - StrPos + Column) / LineLength;
|
|
TailColumn = (Len - StrPos + Column) % LineLength;
|
|
Row = TailRow;
|
|
Column = TailColumn;
|
|
StrPos = Len;
|
|
break;
|
|
|
|
case SCAN_ESC:
|
|
//
|
|
// Prepare to clear the current command line
|
|
//
|
|
InStr[0] = 0;
|
|
Update = 0;
|
|
Delete = Len;
|
|
Row -= (StrPos + StartColumn) / LineLength;
|
|
Column = StartColumn;
|
|
OutputLength = 0;
|
|
break;
|
|
|
|
case SCAN_INSERT:
|
|
//
|
|
// Toggle the SEnvInsertMode flag
|
|
//
|
|
InsertMode = (BOOLEAN)!InsertMode;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Done) {
|
|
break;
|
|
}
|
|
//
|
|
// If we need to update the output do so now
|
|
//
|
|
if (Update != -1) {
|
|
PrintAt (Column, Row, L"%s%.*s", InStr + Update, Delete, L"");
|
|
Len = StrLen (InStr);
|
|
|
|
if (Delete) {
|
|
SetMem (InStr + Len, Delete * sizeof (CHAR16), 0x00);
|
|
}
|
|
|
|
if (StrPos > Len) {
|
|
StrPos = Len;
|
|
}
|
|
|
|
Update = (UINTN) -1;
|
|
|
|
//
|
|
// After using print to reflect newly updates, if we're not using
|
|
// BACKSPACE and DELETE, we need to move the cursor position forward,
|
|
// so adjust row and column here.
|
|
//
|
|
if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {
|
|
//
|
|
// Calulate row and column of the tail of current string
|
|
//
|
|
TailRow = Row + (Len - StrPos + Column + OutputLength) / LineLength;
|
|
TailColumn = (Len - StrPos + Column + OutputLength) % LineLength;
|
|
|
|
//
|
|
// If the tail of string reaches screen end, screen rolls up, so if
|
|
// Row does not equal TailRow, Row should be decremented
|
|
//
|
|
// (if we are recalling commands using UPPER and DOWN key, and if the
|
|
// old command is too long to fit the screen, TailColumn must be 79.
|
|
//
|
|
if (TailColumn == 0 && TailRow >= TotalRow && (UINTN) Row != TailRow) {
|
|
Row--;
|
|
}
|
|
//
|
|
// Calculate the cursor position after current operation. If cursor
|
|
// reaches line end, update both row and column, otherwise, only
|
|
// column will be changed.
|
|
//
|
|
if (Column + OutputLength >= LineLength) {
|
|
SkipLength = OutputLength - (LineLength - Column);
|
|
|
|
Row += SkipLength / LineLength + 1;
|
|
if ((UINTN) Row > TotalRow - 1) {
|
|
Row = TotalRow - 1;
|
|
}
|
|
|
|
Column = SkipLength % LineLength;
|
|
} else {
|
|
Column += OutputLength;
|
|
}
|
|
}
|
|
|
|
Delete = 0;
|
|
}
|
|
//
|
|
// Set the cursor position for this key
|
|
//
|
|
SetCursorPosition (ConOut, Column, Row, LineLength, TotalRow, InStr, StrPos, Len);
|
|
} while (!Done);
|
|
|
|
//
|
|
// Return the data to the caller
|
|
//
|
|
return ;
|
|
}
|
|
|
|
VOID
|
|
SetCursorPosition (
|
|
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
|
|
IN UINTN Column,
|
|
IN INTN Row,
|
|
IN UINTN LineLength,
|
|
IN UINTN TotalRow,
|
|
IN CHAR16 *Str,
|
|
IN UINTN StrPos,
|
|
IN UINTN Len
|
|
)
|
|
{
|
|
CHAR16 Backup;
|
|
|
|
// ASSERT (ConOut != NULL);
|
|
// ASSERT (Str != NULL);
|
|
if (!ConOut || !Str) {
|
|
return;
|
|
}
|
|
|
|
Backup = 0;
|
|
if (Row >= 0) {
|
|
ConOut->SetCursorPosition (ConOut, Column, Row);
|
|
return ;
|
|
}
|
|
|
|
if (Len - StrPos > Column * Row) {
|
|
Backup = *(Str + StrPos + Column * Row);
|
|
*(Str + StrPos + Column * Row) = 0;
|
|
}
|
|
|
|
PrintAt (0, 0, L"%s", Str + StrPos);
|
|
if (Len - StrPos > Column * Row) {
|
|
*(Str + StrPos + Column * Row) = Backup;
|
|
}
|
|
|
|
ConOut->SetCursorPosition (ConOut, 0, 0);
|
|
}
|
|
//
|
|
// //
|
|
/*
|
|
BOOLEAN
|
|
LibGetPrintOmit (
|
|
VOID
|
|
)
|
|
{
|
|
return mPrintMode.OmitPrint;
|
|
}
|
|
|
|
VOID
|
|
LibSetPrintOmit (
|
|
IN BOOLEAN OmitPrint
|
|
)
|
|
{
|
|
EFI_TPL Tpl;
|
|
|
|
Tpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);
|
|
mPrintMode.OmitPrint = OmitPrint;
|
|
gBS->RestoreTPL (Tpl);
|
|
}
|
|
|
|
VOID
|
|
LibEnablePageBreak (
|
|
IN INT32 StartRow,
|
|
IN BOOLEAN AutoWrap
|
|
)
|
|
{
|
|
mPrintMode.PageBreak = TRUE;
|
|
mPrintMode.OmitPrint = FALSE;
|
|
mPrintMode.InitRow = StartRow;
|
|
mPrintMode.AutoWrap = AutoWrap;
|
|
|
|
//
|
|
// Query Mode
|
|
//
|
|
gST->ConOut->QueryMode (
|
|
gST->ConOut,
|
|
gST->ConOut->Mode->Mode,
|
|
(UINTN *)&mPrintMode.MaxColumn,
|
|
(UINTN *)&mPrintMode.MaxRow
|
|
);
|
|
|
|
mPrintMode.Row = StartRow;
|
|
}
|
|
|
|
BOOLEAN
|
|
LibGetPageBreak (
|
|
VOID
|
|
)
|
|
{
|
|
return mPrintMode.PageBreak;
|
|
}
|
|
*/
|
|
//
|
|
VOID LowCase (IN OUT CHAR8 *Str)
|
|
{
|
|
while (*Str) {
|
|
if (IS_UPPER(*Str)) {
|
|
*Str |= 0x20;
|
|
}
|
|
Str++;
|
|
}
|
|
}
|
|
|
|
|
|
UINT8 hexstrtouint8 (CHAR8* buf)
|
|
{
|
|
INT8 i = 0;
|
|
if (IS_DIGIT(buf[0]))
|
|
i = buf[0]-'0';
|
|
else if (IS_HEX(buf[0]))
|
|
i = (buf[0] | 0x20) - 'a' + 10;
|
|
|
|
if (AsciiStrLen(buf) == 1) {
|
|
return i;
|
|
}
|
|
i <<= 4;
|
|
if (IS_DIGIT(buf[1]))
|
|
i += buf[1]-'0';
|
|
else if (IS_HEX(buf[1]))
|
|
i += (buf[1] | 0x20) - 'a' + 10;
|
|
|
|
return i;
|
|
}
|
|
|
|
BOOLEAN IsHexDigit (CHAR8 c) {
|
|
return (IS_DIGIT(c) || (IS_HEX(c)))?TRUE:FALSE;
|
|
}
|
|
|
|
//out value is a number of byte. out = len
|
|
|
|
UINT32 hex2bin(IN CHAR8 *hex, OUT UINT8 *bin, UINT32 len) //assume len = number of UINT8 values
|
|
{
|
|
CHAR8 *p;
|
|
UINT32 i, outlen = 0;
|
|
CHAR8 buf[3];
|
|
|
|
if (hex == NULL || bin == NULL || len <= 0 || AsciiStrLen(hex) < len * 2) {
|
|
// DBG("[ERROR] bin2hex input error\n"); //this is not error, this is empty value
|
|
return FALSE;
|
|
}
|
|
|
|
buf[2] = '\0';
|
|
p = (CHAR8 *) hex;
|
|
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
while ((*p == 0x20) || (*p == ',')) {
|
|
p++; //skip spaces and commas
|
|
}
|
|
if (*p == 0) {
|
|
break;
|
|
}
|
|
if (!IsHexDigit(p[0]) || !IsHexDigit(p[1])) {
|
|
MsgLog("[ERROR] bin2hex '%a' syntax error\n", hex);
|
|
return 0;
|
|
}
|
|
buf[0] = *p++;
|
|
buf[1] = *p++;
|
|
bin[i] = hexstrtouint8(buf);
|
|
outlen++;
|
|
}
|
|
//bin[outlen] = 0;
|
|
return outlen;
|
|
}
|
|
|
|
CHAR8* Bytes2HexStr(UINT8 *data, UINTN len)
|
|
{
|
|
UINTN i, j, b = 0;
|
|
CHAR8 *result = (CHAR8*)AllocateZeroPool((len*2)+1);
|
|
//CHAR8 *buf = (__typeof__(buf))AllocateZeroPool(2);
|
|
|
|
for (i = j = 0; i < len; i++) {
|
|
b = data[i] >> 4;
|
|
result[j++] = (CHAR8) (87 + b + (((b - 10) >> 31) & -39));
|
|
b = data[i] & 0xf;
|
|
result[j++] = (CHAR8) (87 + b + (((b - 10) >> 31) & -39));
|
|
//buf = (CHAR8*)PoolPrint(L"%02x", (UINT8*)data[i]);
|
|
}
|
|
result[j] = '\0';
|
|
//FreePool(buf);
|
|
return result;
|
|
}
|