|
|
/*++
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"); }
} }
|