| /*++ |
| |
| Copyright (c) 1998 Intel Corporation |
| |
| Module Name: |
| |
| print.c |
| |
| Abstract: |
| |
| |
| |
| |
| Revision History |
| |
| --*/ |
| |
| #include "lib.h" |
| #include "efistdarg.h" // !!! |
| |
| // |
| // Declare runtime functions |
| // |
| |
| #ifdef RUNTIME_CODE |
| #ifndef __GNUC__ |
| #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 /* !defined(__GNUC__) */ |
| #endif |
| |
| // |
| // |
| // |
| |
| |
| #define PRINT_STRING_LEN 200 |
| #define PRINT_ITEM_BUFFER_LEN 100 |
| |
| typedef struct { |
| BOOLEAN Ascii; |
| UINTN Index; |
| union { |
| CHAR16 *pw; |
| CHAR8 *pc; |
| } un; |
| } POINTER; |
| |
| #define pw un.pw |
| #define pc un.pc |
| |
| 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 EFIAPI (*Output)(VOID *context, CHAR16 *str); |
| INTN EFIAPI (*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 EFIAPI |
| _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 EFIAPI |
| _SPrint ( |
| IN VOID *Context, |
| IN CHAR16 *Buffer |
| ); |
| |
| INTN EFIAPI |
| _PoolPrint ( |
| IN VOID *Context, |
| IN CHAR16 *Buffer |
| ); |
| |
| 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; |
| va_copy(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 EFIAPI (*)(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); |
| |
| va_end (ps.args); |
| va_end (args); |
| |
| // |
| // Restore original attributes |
| // |
| |
| if (ps.SetAttr) { |
| ps.SetAttr (ps.Context, SavedAttribute); |
| } |
| |
| return 0; |
| } |
| |
| STATIC |
| INTN |
| IsLocalPrint(void *func) |
| { |
| if (func == _DbgOut || func == _SPrint || func == _PoolPrint) |
| return 1; |
| return 0; |
| } |
| |
| STATIC |
| INTN EFIAPI |
| _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) { |
| if (IsLocalPrint(DbgOut->OutputString)) |
| DbgOut->OutputString(DbgOut, Buffer); |
| else |
| uefi_call_wrapper(DbgOut->OutputString, 2, DbgOut, Buffer); |
| } |
| |
| return 0; |
| } |
| |
| INTN EFIAPI |
| _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 EFIAPI |
| _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 EFIAPI (*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; |
| va_copy(ps.args, args); |
| _Print (&ps); |
| va_end(ps.args); |
| } |
| |
| |
| |
| UINTN |
| VSPrint ( |
| OUT CHAR16 *Str, |
| IN UINTN StrSize, |
| IN CHAR16 *fmt, |
| va_list args |
| ) |
| /*++ |
| |
| Routine Description: |
| |
| Prints a formatted unicode string to a buffer using a va_list |
| |
| 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 |
| |
| args - va_list |
| |
| |
| Returns: |
| |
| String length returned in buffer |
| |
| --*/ |
| { |
| POOL_PRINT spc; |
| |
| spc.str = Str; |
| spc.maxlen = StrSize / sizeof(CHAR16) - 1; |
| spc.len = 0; |
| |
| _PoolCatPrint (fmt, args, &spc, _SPrint); |
| |
| return spc.len; |
| } |
| |
| 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 |
| |
| --*/ |
| { |
| va_list args; |
| UINTN len; |
| |
| va_start (args, fmt); |
| len = VSPrint(Str, StrSize, fmt, args); |
| va_end (args); |
| |
| return 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); |
| va_end (args); |
| 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); |
| va_end (args); |
| 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; |
| UINTN back; |
| |
| va_start (args, fmt); |
| back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args); |
| va_end (args); |
| return back; |
| } |
| |
| UINTN |
| VPrint ( |
| IN CHAR16 *fmt, |
| va_list args |
| ) |
| /*++ |
| |
| Routine Description: |
| |
| Prints a formatted unicode string to the default console using a va_list |
| |
| Arguments: |
| |
| fmt - Format string |
| args - va_list |
| Returns: |
| |
| Length of string printed to the console |
| |
| --*/ |
| { |
| 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; |
| UINTN back; |
| |
| va_start (args, fmt); |
| back = _IPrint (Column, Row, ST->ConOut, fmt, NULL, args); |
| va_end (args); |
| return back; |
| } |
| |
| |
| 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; |
| UINTN back; |
| |
| va_start (args, fmt); |
| back = _IPrint ((UINTN) -1, (UINTN) -1, Out, fmt, NULL, args); |
| va_end (args); |
| return back; |
| } |
| |
| |
| 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; |
| UINTN back; |
| |
| va_start (args, fmt); |
| back = _IPrint (Column, Row, ST->ConOut, fmt, NULL, args); |
| va_end (args); |
| return back; |
| } |
| |
| |
| 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 EFIAPI (*)(VOID *, CHAR16 *)) Out->OutputString; |
| ps.SetAttr = (INTN EFIAPI (*)(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; |
| } |
| |
| va_copy(ps.args, args); |
| |
| if (Column != (UINTN) -1) { |
| uefi_call_wrapper(Out->SetCursorPosition, 3, Out, Column, Row); |
| } |
| |
| back = _Print (&ps); |
| va_end(ps.args); |
| return back; |
| } |
| |
| |
| 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; |
| UINTN back; |
| |
| va_start (args, fmt); |
| back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, NULL, fmt, args); |
| va_end (args); |
| return back; |
| } |
| |
| |
| STATIC |
| VOID |
| PFLUSH ( |
| IN OUT 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; |
| } |
| |
| STATIC |
| VOID |
| PSETATTR ( |
| IN OUT PRINT_STATE *ps, |
| IN UINTN Attr |
| ) |
| { |
| PFLUSH (ps); |
| |
| ps->RestoreAttr = ps->Attr; |
| if (ps->SetAttr) { |
| uefi_call_wrapper(ps->SetAttr, 2, 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 = (CHAR8 *)"(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, UINT32) |
| ); |
| |
| 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, UINT32) |
| ); |
| 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]; |
| |
| |
| uefi_call_wrapper(ST->ConOut->QueryMode, 4, 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 Enter to continue :"); |
| Input (L"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16)); |
| Print (L"\n"); |
| } |
| |
| } |
| } |