548 lines
13 KiB
C
548 lines
13 KiB
C
|
|
#if !defined(__GNU_EFI_INTERNAL_VA_PRINT)
|
|
#define __GNU_EFI_INTERNAL_VA_PRINT
|
|
|
|
#include <efistdarg.h>
|
|
#include "print.h"
|
|
|
|
#if defined(__GNU_EFI_INTERNAL_USE_MS_VA_ABI)
|
|
typedef ms_va_list VA_LIST;
|
|
#define VA_START(a,b) ms_va_start(a,b)
|
|
#define VA_COPY(a,b) ms_va_copy(a,b)
|
|
#define VA_END(a) ms_va_end(a)
|
|
#define VA_ARG(a,b) ms_va_arg(a,b)
|
|
#else
|
|
typedef va_list VA_LIST;
|
|
#define VA_START(a,b) va_start(a,b)
|
|
#define VA_COPY(a,b) va_copy(a,b)
|
|
#define VA_END(a) va_end(a)
|
|
#define VA_ARG(a,b) va_arg(a,b)
|
|
#endif
|
|
|
|
#if defined(__GNU_EFI_INTERNAL_USE_MS_VA_ABI)
|
|
#define FUNCTION_NAME(a) MS_ ## a
|
|
#define CALL_CONV EFIAPI
|
|
#else
|
|
#define FUNCTION_NAME(a) a
|
|
#define CALL_CONV
|
|
#endif
|
|
|
|
//
|
|
// Declare runtime functions
|
|
//
|
|
|
|
#ifdef RUNTIME_CODE
|
|
#ifndef __GNUC__
|
|
|
|
// For debugging..
|
|
|
|
/*
|
|
#pragma RUNTIME_CODE(FUNCTION_NAME(_Print))
|
|
#pragma RUNTIME_CODE(FUNCTION_NAME(PFLUSH))
|
|
#pragma RUNTIME_CODE(FUNCTION_NAME(PSETATTR))
|
|
#pragma RUNTIME_CODE(FUNCTION_NAME(PPUTC))
|
|
#pragma RUNTIME_CODE(FUNCTION_NAME(PITEM))
|
|
*/
|
|
|
|
#endif /* !defined(__GNUC__) */
|
|
#endif
|
|
|
|
typedef struct FUNCTION_NAME(_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 (EFIAPI *Output)(VOID *context, CHAR16 *str);
|
|
INTN (EFIAPI *SetAttr)(VOID *context, UINTN attr);
|
|
VOID *Context;
|
|
|
|
// Current item being formatted
|
|
struct _pitem *Item;
|
|
} FUNCTION_NAME(PRINT_STATE);
|
|
|
|
EFI_INTERNAL
|
|
UINTN
|
|
CALL_CONV
|
|
FUNCTION_NAME(_Print) (
|
|
IN FUNCTION_NAME(PRINT_STATE) *ps
|
|
);
|
|
|
|
UINTN
|
|
CALL_CONV
|
|
FUNCTION_NAME(_IPrint) (
|
|
IN UINTN Column,
|
|
IN UINTN Row,
|
|
IN SIMPLE_TEXT_OUTPUT_INTERFACE *Out,
|
|
IN CONST CHAR16 *fmt,
|
|
IN CONST CHAR8 *fmta,
|
|
IN VA_LIST args
|
|
);
|
|
|
|
EFI_INTERNAL
|
|
VOID
|
|
CALL_CONV
|
|
FUNCTION_NAME(PFLUSH) (
|
|
IN OUT FUNCTION_NAME(PRINT_STATE) *ps
|
|
);
|
|
|
|
EFI_INTERNAL
|
|
VOID
|
|
CALL_CONV
|
|
FUNCTION_NAME(PPUTC) (
|
|
IN OUT FUNCTION_NAME(PRINT_STATE) *ps,
|
|
IN CHAR16 c
|
|
);
|
|
|
|
|
|
EFI_INTERNAL
|
|
VOID
|
|
CALL_CONV
|
|
FUNCTION_NAME(PITEM) (
|
|
IN OUT FUNCTION_NAME(PRINT_STATE) *ps
|
|
);
|
|
|
|
EFI_INTERNAL
|
|
VOID
|
|
CALL_CONV
|
|
FUNCTION_NAME(PSETATTR) (
|
|
IN OUT FUNCTION_NAME(PRINT_STATE) *ps,
|
|
IN UINTN Attr
|
|
);
|
|
|
|
EFI_INTERNAL
|
|
VOID
|
|
CALL_CONV
|
|
FUNCTION_NAME(PFLUSH) (
|
|
IN OUT FUNCTION_NAME(PRINT_STATE) *ps
|
|
)
|
|
{
|
|
*ps->Pos = 0;
|
|
if (IsLocalPrint(ps->Output))
|
|
ps->Output(ps->Context, ps->Buffer);
|
|
else
|
|
uefi_call_wrapper(ps->Output, 2, ps->Context, ps->Buffer);
|
|
ps->Pos = ps->Buffer;
|
|
}
|
|
|
|
EFI_INTERNAL
|
|
VOID
|
|
CALL_CONV
|
|
FUNCTION_NAME(PSETATTR) (
|
|
IN OUT FUNCTION_NAME(PRINT_STATE) *ps,
|
|
IN UINTN Attr
|
|
)
|
|
{
|
|
FUNCTION_NAME(PFLUSH) (ps);
|
|
|
|
ps->RestoreAttr = ps->Attr;
|
|
if (ps->SetAttr) {
|
|
uefi_call_wrapper(ps->SetAttr, 2, ps->Context, Attr);
|
|
}
|
|
|
|
ps->Attr = Attr;
|
|
}
|
|
|
|
EFI_INTERNAL
|
|
VOID
|
|
CALL_CONV
|
|
FUNCTION_NAME(PPUTC) (
|
|
IN OUT FUNCTION_NAME(PRINT_STATE) *ps,
|
|
IN CHAR16 c
|
|
)
|
|
{
|
|
// if this is a newline, add a carriage return
|
|
CHAR16 last_char = (ps->Len > 0) ? *(ps->Pos - 1) : '\0';
|
|
if (c == '\n' && last_char != '\r') {
|
|
FUNCTION_NAME(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) {
|
|
FUNCTION_NAME(PFLUSH)(ps);
|
|
}
|
|
}
|
|
|
|
EFI_INTERNAL
|
|
VOID
|
|
CALL_CONV
|
|
FUNCTION_NAME(PITEM) (
|
|
IN OUT FUNCTION_NAME(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) {
|
|
FUNCTION_NAME(PPUTC) (ps, ' ');
|
|
}
|
|
}
|
|
|
|
// pad item
|
|
for (i=Len; i < Item->Width; i++) {
|
|
FUNCTION_NAME(PPUTC) (ps, Item->Pad);
|
|
}
|
|
|
|
// add the item
|
|
Item->Item.Index=0;
|
|
while (Item->Item.Index < Len) {
|
|
FUNCTION_NAME(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) {
|
|
FUNCTION_NAME(PPUTC) (ps, ' ');
|
|
}
|
|
}
|
|
}
|
|
|
|
EFI_INTERNAL
|
|
UINTN
|
|
CALL_CONV
|
|
FUNCTION_NAME(_Print) (
|
|
IN FUNCTION_NAME(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 signed decimal
|
|
u - value as unsigned decimal
|
|
f - value as floating point
|
|
c - Unicode char
|
|
t - EFI time structure
|
|
g - Pointer to GUID
|
|
r - EFI status code (result code)
|
|
D - pointer to Device Path with normal ending.
|
|
|
|
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 != '%') {
|
|
FUNCTION_NAME(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.Scratch[0] = '%';
|
|
Item.Scratch[1] = 0;
|
|
Item.Item.pw = Item.Scratch;
|
|
break;
|
|
|
|
case ',':
|
|
Item.Comma = TRUE;
|
|
break;
|
|
|
|
case '-':
|
|
Item.PadBefore = FALSE;
|
|
break;
|
|
|
|
case '*':
|
|
*Item.WidthParse = VA_ARG(ps->args, UINTN);
|
|
break;
|
|
|
|
case '.':
|
|
Item.WidthParse = &Item.FieldWidth;
|
|
break;
|
|
|
|
case '0':
|
|
Item.Pad = '0';
|
|
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 = (CHAR8 *)"(null)";
|
|
}
|
|
break;
|
|
|
|
case 'c':
|
|
Item.Scratch[0] = (CHAR16) VA_ARG(ps->args, UINTN);
|
|
Item.Scratch[1] = 0;
|
|
Item.Item.pw = Item.Scratch;
|
|
break;
|
|
|
|
case 'D':
|
|
{
|
|
EFI_DEVICE_PATH *dp = VA_ARG(ps->args, EFI_DEVICE_PATH *);
|
|
CHAR16 *dpstr = DevicePathToStr(dp);
|
|
StrnCpy(Item.Scratch, dpstr, PRINT_ITEM_BUFFER_LEN);
|
|
Item.Scratch[PRINT_ITEM_BUFFER_LEN-1] = u'\0';
|
|
FreePool(dpstr);
|
|
|
|
Item.Item.pw = Item.Scratch;
|
|
break;
|
|
}
|
|
|
|
case 'd':
|
|
ValueToString (
|
|
Item.Scratch,
|
|
Item.Comma,
|
|
Item.Long ? VA_ARG(ps->args, INT64) : VA_ARG(ps->args, INT32)
|
|
);
|
|
Item.Item.pw = Item.Scratch;
|
|
break;
|
|
|
|
case 'E':
|
|
Attr = ps->AttrError;
|
|
break;
|
|
|
|
case 'e':
|
|
FUNCTION_NAME(PSETATTR)(ps, ps->AttrError);
|
|
break;
|
|
|
|
case 'f':
|
|
FloatToString (
|
|
Item.Scratch,
|
|
Item.Comma,
|
|
VA_ARG(ps->args, double)
|
|
);
|
|
Item.Item.pw = Item.Scratch;
|
|
break;
|
|
|
|
case 'g':
|
|
GuidToString (Item.Scratch, VA_ARG(ps->args, EFI_GUID *));
|
|
Item.Item.pw = Item.Scratch;
|
|
break;
|
|
|
|
case 'H':
|
|
Attr = ps->AttrHighlight;
|
|
break;
|
|
|
|
case 'h':
|
|
FUNCTION_NAME(PSETATTR)(ps, ps->AttrHighlight);
|
|
break;
|
|
|
|
case 'l':
|
|
Item.Long = TRUE;
|
|
break;
|
|
|
|
case 'N':
|
|
Attr = ps->AttrNorm;
|
|
break;
|
|
|
|
case 'n':
|
|
FUNCTION_NAME(PSETATTR)(ps, ps->AttrNorm);
|
|
break;
|
|
|
|
case 'p':
|
|
Item.Width = sizeof(void *) == (8 ? 16 : 8) + 2;
|
|
Item.Pad = '0';
|
|
Item.Scratch[0] = ' ';
|
|
Item.Scratch[1] = ' ';
|
|
ValueToHex (
|
|
Item.Scratch+2,
|
|
Item.Long ? VA_ARG(ps->args, UINT64) : VA_ARG(ps->args, UINT32)
|
|
);
|
|
Item.Scratch[0] = '0';
|
|
Item.Scratch[1] = 'x';
|
|
Item.Item.pw = Item.Scratch;
|
|
break;
|
|
|
|
case 'r':
|
|
StatusToString (Item.Scratch, VA_ARG(ps->args, EFI_STATUS));
|
|
Item.Item.pw = Item.Scratch;
|
|
break;
|
|
|
|
case 's':
|
|
Item.Item.pw = VA_ARG(ps->args, CHAR16 *);
|
|
if (!Item.Item.pw) {
|
|
Item.Item.pw = u"(null)";
|
|
}
|
|
break;
|
|
|
|
case 't':
|
|
TimeToString (Item.Scratch, VA_ARG(ps->args, EFI_TIME *));
|
|
Item.Item.pw = Item.Scratch;
|
|
break;
|
|
|
|
case 'u':
|
|
ValueToString (
|
|
Item.Scratch,
|
|
Item.Comma,
|
|
Item.Long ? VA_ARG(ps->args, UINT64) : VA_ARG(ps->args, UINT32)
|
|
);
|
|
Item.Item.pw = Item.Scratch;
|
|
break;
|
|
|
|
case 'X':
|
|
Item.Width = Item.Long ? 16 : 8;
|
|
Item.Pad = '0';
|
|
#if __GNUC__ >= 7
|
|
__attribute__ ((fallthrough));
|
|
#endif
|
|
case 'x':
|
|
ValueToHex (
|
|
Item.Scratch,
|
|
Item.Long ? VA_ARG(ps->args, UINT64) : VA_ARG(ps->args, UINT32)
|
|
);
|
|
Item.Item.pw = Item.Scratch;
|
|
break;
|
|
|
|
default:
|
|
Item.Scratch[0] = '?';
|
|
Item.Scratch[1] = 0;
|
|
Item.Item.pw = Item.Scratch;
|
|
break;
|
|
}
|
|
|
|
// if we have an Item
|
|
if (Item.Item.pw) {
|
|
FUNCTION_NAME(PITEM) (ps);
|
|
break;
|
|
}
|
|
|
|
// if we have an Attr set
|
|
if (Attr) {
|
|
FUNCTION_NAME(PSETATTR)(ps, Attr);
|
|
ps->RestoreAttr = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ps->RestoreAttr) {
|
|
FUNCTION_NAME(PSETATTR)(ps, ps->RestoreAttr);
|
|
}
|
|
}
|
|
|
|
// Flush buffer
|
|
FUNCTION_NAME(PFLUSH) (ps);
|
|
return ps->Len;
|
|
}
|
|
|
|
VOID
|
|
CALL_CONV
|
|
FUNCTION_NAME(_PoolCatPrint) (
|
|
IN CONST CHAR16 *fmt,
|
|
IN VA_LIST args,
|
|
IN OUT POOL_PRINT *spc,
|
|
IN INTN (EFIAPI *Output)(VOID *context, CHAR16 *str)
|
|
);
|
|
|
|
#endif
|