1251 lines
24 KiB
C
1251 lines
24 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1998 Intel Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
print.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
Revision History
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "lib.h"
|
||
|
#include "efistdarg.h" /* !!! */
|
||
|
|
||
|
/*
|
||
|
* Declare runtime functions
|
||
|
*/
|
||
|
|
||
|
#ifdef RUNTIME_CODE
|
||
|
#pragma RUNTIME_CODE(DbgPrint)
|
||
|
|
||
|
/* For debugging.. */
|
||
|
|
||
|
/*
|
||
|
#pragma RUNTIME_CODE(_Print)
|
||
|
#pragma RUNTIME_CODE(PFLUSH)
|
||
|
#pragma RUNTIME_CODE(PSETATTR)
|
||
|
#pragma RUNTIME_CODE(PPUTC)
|
||
|
#pragma RUNTIME_CODE(PGETC)
|
||
|
#pragma RUNTIME_CODE(PITEM)
|
||
|
#pragma RUNTIME_CODE(ValueToHex)
|
||
|
#pragma RUNTIME_CODE(ValueToString)
|
||
|
#pragma RUNTIME_CODE(TimeToString)
|
||
|
*/
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
|
||
|
#define PRINT_STRING_LEN 200
|
||
|
#define PRINT_ITEM_BUFFER_LEN 100
|
||
|
|
||
|
typedef struct {
|
||
|
BOOLEAN Ascii;
|
||
|
UINTN Index;
|
||
|
union {
|
||
|
CHAR16 *pw;
|
||
|
CHAR8 *pc;
|
||
|
} ;
|
||
|
} POINTER;
|
||
|
|
||
|
|
||
|
typedef struct _pitem {
|
||
|
|
||
|
POINTER Item;
|
||
|
CHAR16 Scratch[PRINT_ITEM_BUFFER_LEN];
|
||
|
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;
|
||
|
|
||
|
INTN (*Output)(VOID *context, CHAR16 *str);
|
||
|
INTN (*SetAttr)(VOID *context, UINTN attr);
|
||
|
VOID *Context;
|
||
|
|
||
|
/* Current item being formatted */
|
||
|
struct _pitem *Item;
|
||
|
} PRINT_STATE;
|
||
|
|
||
|
/*
|
||
|
* Internal fucntions
|
||
|
*/
|
||
|
|
||
|
STATIC
|
||
|
UINTN
|
||
|
_Print (
|
||
|
IN PRINT_STATE *ps
|
||
|
);
|
||
|
|
||
|
STATIC
|
||
|
UINTN
|
||
|
_IPrint (
|
||
|
IN UINTN Column,
|
||
|
IN UINTN Row,
|
||
|
IN SIMPLE_TEXT_OUTPUT_INTERFACE *Out,
|
||
|
IN CHAR16 *fmt,
|
||
|
IN CHAR8 *fmta,
|
||
|
IN va_list args
|
||
|
);
|
||
|
|
||
|
STATIC
|
||
|
INTN
|
||
|
_DbgOut (
|
||
|
IN VOID *Context,
|
||
|
IN CHAR16 *Buffer
|
||
|
);
|
||
|
|
||
|
STATIC
|
||
|
VOID
|
||
|
PFLUSH (
|
||
|
IN OUT PRINT_STATE *ps
|
||
|
);
|
||
|
|
||
|
STATIC
|
||
|
VOID
|
||
|
PPUTC (
|
||
|
IN OUT PRINT_STATE *ps,
|
||
|
IN CHAR16 c
|
||
|
);
|
||
|
|
||
|
STATIC
|
||
|
VOID
|
||
|
PITEM (
|
||
|
IN OUT PRINT_STATE *ps
|
||
|
);
|
||
|
|
||
|
STATIC
|
||
|
CHAR16
|
||
|
PGETC (
|
||
|
IN POINTER *p
|
||
|
);
|
||
|
|
||
|
STATIC
|
||
|
VOID
|
||
|
PSETATTR (
|
||
|
IN OUT PRINT_STATE *ps,
|
||
|
IN UINTN Attr
|
||
|
);
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
INTN
|
||
|
DbgPrint (
|
||
|
IN INTN mask,
|
||
|
IN CHAR8 *fmt,
|
||
|
...
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Prints a formatted unicode string to the default StandardError console
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
mask - Bit mask of debug string. If a bit is set in the
|
||
|
mask that is also set in EFIDebug the string is
|
||
|
printed; otherwise, the string is not printed
|
||
|
|
||
|
fmt - Format string
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Length of string printed to the StandardError console
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
SIMPLE_TEXT_OUTPUT_INTERFACE *DbgOut;
|
||
|
PRINT_STATE ps;
|
||
|
va_list args;
|
||
|
UINTN back;
|
||
|
UINTN attr;
|
||
|
UINTN SavedAttribute;
|
||
|
|
||
|
|
||
|
if (!(EFIDebug & mask)) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
va_start (args, fmt);
|
||
|
ZeroMem (&ps, sizeof(ps));
|
||
|
|
||
|
ps.Output = _DbgOut;
|
||
|
ps.fmt.Ascii = TRUE;
|
||
|
ps.fmt.pc = fmt;
|
||
|
ps.args = args;
|
||
|
ps.Attr = EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_RED);
|
||
|
|
||
|
DbgOut = LibRuntimeDebugOut;
|
||
|
|
||
|
if (!DbgOut) {
|
||
|
DbgOut = ST->StdErr;
|
||
|
}
|
||
|
|
||
|
if (DbgOut) {
|
||
|
ps.Attr = DbgOut->Mode->Attribute;
|
||
|
ps.Context = DbgOut;
|
||
|
ps.SetAttr = (INTN (*)(VOID *, UINTN)) DbgOut->SetAttribute;
|
||
|
}
|
||
|
|
||
|
SavedAttribute = ps.Attr;
|
||
|
|
||
|
back = (ps.Attr >> 4) & 0xf;
|
||
|
ps.AttrNorm = EFI_TEXT_ATTR(EFI_LIGHTGRAY, back);
|
||
|
ps.AttrHighlight = EFI_TEXT_ATTR(EFI_WHITE, back);
|
||
|
ps.AttrError = EFI_TEXT_ATTR(EFI_YELLOW, back);
|
||
|
|
||
|
attr = ps.AttrNorm;
|
||
|
|
||
|
if (mask & D_WARN) {
|
||
|
attr = ps.AttrHighlight;
|
||
|
}
|
||
|
|
||
|
if (mask & D_ERROR) {
|
||
|
attr = ps.AttrError;
|
||
|
}
|
||
|
|
||
|
if (ps.SetAttr) {
|
||
|
ps.Attr = attr;
|
||
|
ps.SetAttr (ps.Context, attr);
|
||
|
}
|
||
|
|
||
|
_Print (&ps);
|
||
|
|
||
|
/*
|
||
|
* Restore original attributes
|
||
|
*/
|
||
|
|
||
|
if (ps.SetAttr) {
|
||
|
ps.SetAttr (ps.Context, SavedAttribute);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
STATIC
|
||
|
INTN
|
||
|
_DbgOut (
|
||
|
IN VOID *Context,
|
||
|
IN CHAR16 *Buffer
|
||
|
)
|
||
|
/* Append string worker for DbgPrint */
|
||
|
{
|
||
|
SIMPLE_TEXT_OUTPUT_INTERFACE *DbgOut;
|
||
|
|
||
|
DbgOut = Context;
|
||
|
/* if (!DbgOut && ST && ST->ConOut) {
|
||
|
* DbgOut = ST->ConOut;
|
||
|
* } */
|
||
|
|
||
|
if (DbgOut) {
|
||
|
DbgOut->OutputString (DbgOut, Buffer);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
INTN
|
||
|
_SPrint (
|
||
|
IN VOID *Context,
|
||
|
IN CHAR16 *Buffer
|
||
|
)
|
||
|
/* Append string worker for SPrint, PoolPrint and CatPrint */
|
||
|
{
|
||
|
UINTN len;
|
||
|
POOL_PRINT *spc;
|
||
|
|
||
|
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-1] = 0;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
INTN
|
||
|
_PoolPrint (
|
||
|
IN VOID *Context,
|
||
|
IN CHAR16 *Buffer
|
||
|
)
|
||
|
/* Append string worker for PoolPrint and CatPrint */
|
||
|
{
|
||
|
UINTN newlen;
|
||
|
POOL_PRINT *spc;
|
||
|
|
||
|
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 = ReallocatePool (
|
||
|
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
|
||
|
_PoolCatPrint (
|
||
|
IN CHAR16 *fmt,
|
||
|
IN va_list args,
|
||
|
IN OUT POOL_PRINT *spc,
|
||
|
IN INTN (*Output)(VOID *context, CHAR16 *str)
|
||
|
)
|
||
|
/* Dispath function for SPrint, PoolPrint, and CatPrint */
|
||
|
{
|
||
|
PRINT_STATE ps;
|
||
|
|
||
|
ZeroMem (&ps, sizeof(ps));
|
||
|
ps.Output = Output;
|
||
|
ps.Context = spc;
|
||
|
ps.fmt.pw = fmt;
|
||
|
ps.args = args;
|
||
|
_Print (&ps);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
UINTN
|
||
|
SPrint (
|
||
|
OUT CHAR16 *Str,
|
||
|
IN UINTN StrSize,
|
||
|
IN CHAR16 *fmt,
|
||
|
...
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Prints a formatted unicode string to a buffer
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Str - Output buffer to print the formatted string into
|
||
|
|
||
|
StrSize - Size of Str. String is truncated to this size.
|
||
|
A size of 0 means there is no limit
|
||
|
|
||
|
fmt - The format string
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
String length returned in buffer
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
POOL_PRINT spc;
|
||
|
va_list args;
|
||
|
|
||
|
|
||
|
va_start (args, fmt);
|
||
|
spc.str = Str;
|
||
|
spc.maxlen = StrSize / sizeof(CHAR16) - 1;
|
||
|
spc.len = 0;
|
||
|
|
||
|
_PoolCatPrint (fmt, args, &spc, _SPrint);
|
||
|
return spc.len;
|
||
|
}
|
||
|
|
||
|
|
||
|
CHAR16 *
|
||
|
PoolPrint (
|
||
|
IN 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);
|
||
|
return spc.str;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
CHAR16 *
|
||
|
CatPrint (
|
||
|
IN OUT POOL_PRINT *Str,
|
||
|
IN CHAR16 *fmt,
|
||
|
...
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Concatenates a formatted unicode string to allocated pool.
|
||
|
The caller must free the resulting buffer.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Str - Tracks the allocated pool, size in use, and
|
||
|
amount of pool allocated.
|
||
|
|
||
|
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.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
va_list args;
|
||
|
|
||
|
va_start (args, fmt);
|
||
|
_PoolCatPrint (fmt, args, Str, _PoolPrint);
|
||
|
return Str->str;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
UINTN
|
||
|
Print (
|
||
|
IN CHAR16 *fmt,
|
||
|
...
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Prints a formatted unicode string to the default console
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
fmt - Format string
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Length of string printed to the console
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
va_list args;
|
||
|
|
||
|
va_start (args, fmt);
|
||
|
return _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
|
||
|
}
|
||
|
|
||
|
UINTN
|
||
|
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:
|
||
|
|
||
|
Column, Row - The cursor position to print the string at
|
||
|
|
||
|
fmt - Format string
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Length of string printed to the console
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
va_list args;
|
||
|
|
||
|
va_start (args, fmt);
|
||
|
return _IPrint (Column, Row, ST->ConOut, fmt, NULL, args);
|
||
|
}
|
||
|
|
||
|
|
||
|
UINTN
|
||
|
IPrint (
|
||
|
IN SIMPLE_TEXT_OUTPUT_INTERFACE *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;
|
||
|
|
||
|
va_start (args, fmt);
|
||
|
return _IPrint ((UINTN) -1, (UINTN) -1, Out, fmt, NULL, args);
|
||
|
}
|
||
|
|
||
|
|
||
|
UINTN
|
||
|
IPrintAt (
|
||
|
IN SIMPLE_TEXT_OUTPUT_INTERFACE *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;
|
||
|
|
||
|
va_start (args, fmt);
|
||
|
return _IPrint (Column, Row, ST->ConOut, fmt, NULL, args);
|
||
|
}
|
||
|
|
||
|
|
||
|
UINTN
|
||
|
_IPrint (
|
||
|
IN UINTN Column,
|
||
|
IN UINTN Row,
|
||
|
IN SIMPLE_TEXT_OUTPUT_INTERFACE *Out,
|
||
|
IN CHAR16 *fmt,
|
||
|
IN CHAR8 *fmta,
|
||
|
IN va_list args
|
||
|
)
|
||
|
/* Display string worker for: Print, PrintAt, IPrint, IPrintAt */
|
||
|
{
|
||
|
PRINT_STATE ps;
|
||
|
UINTN back;
|
||
|
|
||
|
ZeroMem (&ps, sizeof(ps));
|
||
|
ps.Context = Out;
|
||
|
ps.Output = (INTN (*)(VOID *, CHAR16 *)) Out->OutputString;
|
||
|
ps.SetAttr = (INTN (*)(VOID *, UINTN)) Out->SetAttribute;
|
||
|
ps.Attr = Out->Mode->Attribute;
|
||
|
|
||
|
back = (ps.Attr >> 4) & 0xF;
|
||
|
ps.AttrNorm = EFI_TEXT_ATTR(EFI_LIGHTGRAY, back);
|
||
|
ps.AttrHighlight = EFI_TEXT_ATTR(EFI_WHITE, back);
|
||
|
ps.AttrError = EFI_TEXT_ATTR(EFI_YELLOW, back);
|
||
|
|
||
|
if (fmt) {
|
||
|
ps.fmt.pw = fmt;
|
||
|
} else {
|
||
|
ps.fmt.Ascii = TRUE;
|
||
|
ps.fmt.pc = fmta;
|
||
|
}
|
||
|
|
||
|
ps.args = args;
|
||
|
|
||
|
if (Column != (UINTN) -1) {
|
||
|
Out->SetCursorPosition(Out, Column, Row);
|
||
|
}
|
||
|
|
||
|
return _Print (&ps);
|
||
|
}
|
||
|
|
||
|
|
||
|
UINTN
|
||
|
APrint (
|
||
|
IN CHAR8 *fmt,
|
||
|
...
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
For those whom really can't deal with unicode, a print
|
||
|
function that takes an ascii format string
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
fmt - ascii format string
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Length of string printed to the console
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
va_list args;
|
||
|
|
||
|
va_start (args, fmt);
|
||
|
return _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, NULL, fmt, args);
|
||
|
}
|
||
|
|
||
|
|
||
|
STATIC
|
||
|
VOID
|
||
|
PFLUSH (
|
||
|
IN OUT PRINT_STATE *ps
|
||
|
)
|
||
|
{
|
||
|
*ps->Pos = 0;
|
||
|
ps->Output(ps->Context, ps->Buffer);
|
||
|
ps->Pos = ps->Buffer;
|
||
|
}
|
||
|
|
||
|
STATIC
|
||
|
VOID
|
||
|
PSETATTR (
|
||
|
IN OUT PRINT_STATE *ps,
|
||
|
IN UINTN Attr
|
||
|
)
|
||
|
{
|
||
|
PFLUSH (ps);
|
||
|
|
||
|
ps->RestoreAttr = ps->Attr;
|
||
|
if (ps->SetAttr) {
|
||
|
ps->SetAttr (ps->Context, Attr);
|
||
|
}
|
||
|
|
||
|
ps->Attr = Attr;
|
||
|
}
|
||
|
|
||
|
STATIC
|
||
|
VOID
|
||
|
PPUTC (
|
||
|
IN OUT PRINT_STATE *ps,
|
||
|
IN CHAR16 c
|
||
|
)
|
||
|
{
|
||
|
/* if this is a newline, add a carraige return */
|
||
|
if (c == '\n') {
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
STATIC
|
||
|
CHAR16
|
||
|
PGETC (
|
||
|
IN POINTER *p
|
||
|
)
|
||
|
{
|
||
|
CHAR16 c;
|
||
|
|
||
|
c = p->Ascii ? p->pc[p->Index] : p->pw[p->Index];
|
||
|
p->Index += 1;
|
||
|
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
|
||
|
STATIC
|
||
|
VOID
|
||
|
PITEM (
|
||
|
IN OUT PRINT_STATE *ps
|
||
|
)
|
||
|
{
|
||
|
UINTN Len, i;
|
||
|
PRINT_ITEM *Item;
|
||
|
CHAR16 c;
|
||
|
|
||
|
/* 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, ' ');
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
STATIC
|
||
|
UINTN
|
||
|
_Print (
|
||
|
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)
|
||
|
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
|
||
|
% - Print a %
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
SystemTable - The system table
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Number of charactors written
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
CHAR16 c;
|
||
|
UINTN Attr;
|
||
|
PRINT_ITEM Item;
|
||
|
CHAR16 Buffer[PRINT_STRING_LEN];
|
||
|
|
||
|
ps->Len = 0;
|
||
|
ps->Buffer = Buffer;
|
||
|
ps->Pos = Buffer;
|
||
|
ps->End = Buffer + PRINT_STRING_LEN - 1;
|
||
|
ps->Item = &Item;
|
||
|
|
||
|
ps->fmt.Index = 0;
|
||
|
while (c = PGETC(&ps->fmt)) {
|
||
|
|
||
|
if (c != '%') {
|
||
|
PPUTC ( ps, c );
|
||
|
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.pw = NULL;
|
||
|
ps->RestoreAttr = 0;
|
||
|
Attr = 0;
|
||
|
|
||
|
while (c = PGETC(&ps->fmt)) {
|
||
|
|
||
|
switch (c) {
|
||
|
|
||
|
case '%':
|
||
|
/*
|
||
|
* %% -> %
|
||
|
*/
|
||
|
Item.Item.pw = Item.Scratch;
|
||
|
Item.Item.pw[0] = '%';
|
||
|
Item.Item.pw[1] = 0;
|
||
|
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.pc = va_arg(ps->args, CHAR8 *);
|
||
|
Item.Item.Ascii = TRUE;
|
||
|
if (!Item.Item.pc) {
|
||
|
Item.Item.pc = "(null)";
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 's':
|
||
|
Item.Item.pw = va_arg(ps->args, CHAR16 *);
|
||
|
if (!Item.Item.pw) {
|
||
|
Item.Item.pw = L"(null)";
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'c':
|
||
|
Item.Item.pw = Item.Scratch;
|
||
|
Item.Item.pw[0] = (CHAR16) va_arg(ps->args, UINTN);
|
||
|
Item.Item.pw[1] = 0;
|
||
|
break;
|
||
|
|
||
|
case 'l':
|
||
|
Item.Long = TRUE;
|
||
|
break;
|
||
|
|
||
|
case 'X':
|
||
|
Item.Width = Item.Long ? 16 : 8;
|
||
|
Item.Pad = '0';
|
||
|
case 'x':
|
||
|
Item.Item.pw = Item.Scratch;
|
||
|
ValueToHex (
|
||
|
Item.Item.pw,
|
||
|
Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINTN)
|
||
|
);
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
case 'g':
|
||
|
Item.Item.pw = Item.Scratch;
|
||
|
GuidToString (Item.Item.pw, va_arg(ps->args, EFI_GUID *));
|
||
|
break;
|
||
|
|
||
|
case 'd':
|
||
|
Item.Item.pw = Item.Scratch;
|
||
|
ValueToString (
|
||
|
Item.Item.pw,
|
||
|
Item.Comma,
|
||
|
Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINTN)
|
||
|
);
|
||
|
break
|
||
|
;
|
||
|
case 't':
|
||
|
Item.Item.pw = Item.Scratch;
|
||
|
TimeToString (Item.Item.pw, va_arg(ps->args, EFI_TIME *));
|
||
|
break;
|
||
|
|
||
|
case 'r':
|
||
|
Item.Item.pw = Item.Scratch;
|
||
|
StatusToString (Item.Item.pw, va_arg(ps->args, EFI_STATUS));
|
||
|
break;
|
||
|
|
||
|
case 'n':
|
||
|
PSETATTR(ps, ps->AttrNorm);
|
||
|
break;
|
||
|
|
||
|
case 'h':
|
||
|
PSETATTR(ps, ps->AttrHighlight);
|
||
|
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;
|
||
|
|
||
|
default:
|
||
|
Item.Item.pw = Item.Scratch;
|
||
|
Item.Item.pw[0] = '?';
|
||
|
Item.Item.pw[1] = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* if we have an Item */
|
||
|
if (Item.Item.pw) {
|
||
|
PITEM (ps);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* if we have an Attr set */
|
||
|
if (Attr) {
|
||
|
PSETATTR(ps, Attr);
|
||
|
ps->RestoreAttr = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ps->RestoreAttr) {
|
||
|
PSETATTR(ps, ps->RestoreAttr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Flush buffer */
|
||
|
PFLUSH (ps);
|
||
|
return ps->Len;
|
||
|
}
|
||
|
|
||
|
STATIC CHAR8 Hex[] = {'0','1','2','3','4','5','6','7',
|
||
|
'8','9','A','B','C','D','E','F'};
|
||
|
|
||
|
VOID
|
||
|
ValueToHex (
|
||
|
IN CHAR16 *Buffer,
|
||
|
IN UINT64 v
|
||
|
)
|
||
|
{
|
||
|
CHAR8 str[30], *p1;
|
||
|
CHAR16 *p2;
|
||
|
|
||
|
if (!v) {
|
||
|
Buffer[0] = '0';
|
||
|
Buffer[1] = 0;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
p1 = str;
|
||
|
p2 = Buffer;
|
||
|
|
||
|
while (v) {
|
||
|
*(p1++) = Hex[v & 0xf];
|
||
|
v = RShiftU64 (v, 4);
|
||
|
}
|
||
|
|
||
|
while (p1 != str) {
|
||
|
*(p2++) = *(--p1);
|
||
|
}
|
||
|
*p2 = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
ValueToString (
|
||
|
IN CHAR16 *Buffer,
|
||
|
IN BOOLEAN Comma,
|
||
|
IN INT64 v
|
||
|
)
|
||
|
{
|
||
|
STATIC CHAR8 ca[] = { 3, 1, 2 };
|
||
|
CHAR8 str[40], *p1;
|
||
|
CHAR16 *p2;
|
||
|
UINTN c, r;
|
||
|
|
||
|
if (!v) {
|
||
|
Buffer[0] = '0';
|
||
|
Buffer[1] = 0;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
p1 = str;
|
||
|
p2 = Buffer;
|
||
|
|
||
|
if (v < 0) {
|
||
|
*(p2++) = '-';
|
||
|
v = -v;
|
||
|
}
|
||
|
|
||
|
while (v) {
|
||
|
v = (INT64)DivU64x32 ((UINT64)v, 10, &r);
|
||
|
*(p1++) = (CHAR8)r + '0';
|
||
|
}
|
||
|
|
||
|
c = (Comma ? ca[(p1 - str) % 3] : 999) + 1;
|
||
|
while (p1 != str) {
|
||
|
|
||
|
c -= 1;
|
||
|
if (!c) {
|
||
|
*(p2++) = ',';
|
||
|
c = 3;
|
||
|
}
|
||
|
|
||
|
*(p2++) = *(--p1);
|
||
|
}
|
||
|
*p2 = 0;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
TimeToString (
|
||
|
OUT CHAR16 *Buffer,
|
||
|
IN EFI_TIME *Time
|
||
|
)
|
||
|
{
|
||
|
UINTN Hour, Year;
|
||
|
CHAR16 AmPm;
|
||
|
|
||
|
AmPm = 'a';
|
||
|
Hour = Time->Hour;
|
||
|
if (Time->Hour == 0) {
|
||
|
Hour = 12;
|
||
|
} else if (Time->Hour >= 12) {
|
||
|
AmPm = 'p';
|
||
|
if (Time->Hour >= 13) {
|
||
|
Hour -= 12;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Year = Time->Year % 100;
|
||
|
|
||
|
/* bugbug: for now just print it any old way */
|
||
|
SPrint (Buffer, 0, L"%02d/%02d/%02d %02d:%02d%c",
|
||
|
Time->Month,
|
||
|
Time->Day,
|
||
|
Year,
|
||
|
Hour,
|
||
|
Time->Minute,
|
||
|
AmPm
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
DumpHex (
|
||
|
IN UINTN Indent,
|
||
|
IN UINTN Offset,
|
||
|
IN UINTN DataSize,
|
||
|
IN VOID *UserData
|
||
|
)
|
||
|
{
|
||
|
CHAR8 *Data, Val[50], Str[20], c;
|
||
|
UINTN Size, Index;
|
||
|
|
||
|
UINTN ScreenCount;
|
||
|
UINTN TempColumn;
|
||
|
UINTN ScreenSize;
|
||
|
CHAR16 ReturnStr[1];
|
||
|
|
||
|
|
||
|
ST->ConOut->QueryMode (ST->ConOut, ST->ConOut->Mode->Mode, &TempColumn, &ScreenSize);
|
||
|
ScreenCount = 0;
|
||
|
ScreenSize -= 2;
|
||
|
|
||
|
Data = UserData;
|
||
|
while (DataSize) {
|
||
|
Size = 16;
|
||
|
if (Size > DataSize) {
|
||
|
Size = DataSize;
|
||
|
}
|
||
|
|
||
|
for (Index=0; Index < Size; Index += 1) {
|
||
|
c = Data[Index];
|
||
|
Val[Index*3+0] = Hex[c>>4];
|
||
|
Val[Index*3+1] = Hex[c&0xF];
|
||
|
Val[Index*3+2] = (Index == 7)?'-':' ';
|
||
|
Str[Index] = (c < ' ' || c > 'z') ? '.' : c;
|
||
|
}
|
||
|
|
||
|
Val[Index*3] = 0;
|
||
|
Str[Index] = 0;
|
||
|
Print (L"%*a%X: %-.48a *%a*\n", Indent, "", Offset, Val, Str);
|
||
|
|
||
|
Data += Size;
|
||
|
Offset += Size;
|
||
|
DataSize -= Size;
|
||
|
|
||
|
ScreenCount++;
|
||
|
if (ScreenCount >= ScreenSize && ScreenSize != 0) {
|
||
|
/*
|
||
|
* If ScreenSize == 0 we have the console redirected so don't
|
||
|
* block updates
|
||
|
*/
|
||
|
ScreenCount = 0;
|
||
|
Print (L"Press Return to contiue :");
|
||
|
Input (L"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16));
|
||
|
Print (L"\n");
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|