Home | History | Annotate | Download | only in lib
      1 /*++
      2 
      3 Copyright (c) 1998  Intel Corporation
      4 
      5 Module Name:
      6 
      7     print.c
      8 
      9 Abstract:
     10 
     11 
     12 
     13 
     14 Revision History
     15 
     16 --*/
     17 
     18 #include "lib.h"
     19 #include "efistdarg.h"                        // !!!
     20 
     21 //
     22 // Declare runtime functions
     23 //
     24 
     25 #ifdef RUNTIME_CODE
     26 #ifndef __GNUC__
     27 #pragma RUNTIME_CODE(DbgPrint)
     28 
     29 // For debugging..
     30 
     31 /*
     32 #pragma RUNTIME_CODE(_Print)
     33 #pragma RUNTIME_CODE(PFLUSH)
     34 #pragma RUNTIME_CODE(PSETATTR)
     35 #pragma RUNTIME_CODE(PPUTC)
     36 #pragma RUNTIME_CODE(PGETC)
     37 #pragma RUNTIME_CODE(PITEM)
     38 #pragma RUNTIME_CODE(ValueToHex)
     39 #pragma RUNTIME_CODE(ValueToString)
     40 #pragma RUNTIME_CODE(TimeToString)
     41 */
     42 
     43 #endif /* !defined(__GNUC__) */
     44 #endif
     45 
     46 //
     47 //
     48 //
     49 
     50 
     51 #define PRINT_STRING_LEN            200
     52 #define PRINT_ITEM_BUFFER_LEN       100
     53 
     54 typedef struct {
     55     BOOLEAN             Ascii;
     56     UINTN               Index;
     57     union {
     58         CHAR16          *pw;
     59         CHAR8           *pc;
     60     } un;
     61 } POINTER;
     62 
     63 #define pw	un.pw
     64 #define pc	un.pc
     65 
     66 typedef struct _pitem {
     67 
     68     POINTER     Item;
     69     CHAR16      Scratch[PRINT_ITEM_BUFFER_LEN];
     70     UINTN       Width;
     71     UINTN       FieldWidth;
     72     UINTN       *WidthParse;
     73     CHAR16      Pad;
     74     BOOLEAN     PadBefore;
     75     BOOLEAN     Comma;
     76     BOOLEAN     Long;
     77 } PRINT_ITEM;
     78 
     79 
     80 typedef struct _pstate {
     81     // Input
     82     POINTER     fmt;
     83     va_list     args;
     84 
     85     // Output
     86     CHAR16      *Buffer;
     87     CHAR16      *End;
     88     CHAR16      *Pos;
     89     UINTN       Len;
     90 
     91     UINTN       Attr;
     92     UINTN       RestoreAttr;
     93 
     94     UINTN       AttrNorm;
     95     UINTN       AttrHighlight;
     96     UINTN       AttrError;
     97 
     98     INTN EFIAPI       (*Output)(VOID *context, CHAR16 *str);
     99     INTN EFIAPI       (*SetAttr)(VOID *context, UINTN attr);
    100     VOID        *Context;
    101 
    102     // Current item being formatted
    103     struct _pitem  *Item;
    104 } PRINT_STATE;
    105 
    106 //
    107 // Internal fucntions
    108 //
    109 
    110 STATIC
    111 UINTN
    112 _Print (
    113     IN PRINT_STATE     *ps
    114     );
    115 
    116 STATIC
    117 UINTN
    118 _IPrint (
    119     IN UINTN                            Column,
    120     IN UINTN                            Row,
    121     IN SIMPLE_TEXT_OUTPUT_INTERFACE     *Out,
    122     IN CHAR16                           *fmt,
    123     IN CHAR8                            *fmta,
    124     IN va_list                          args
    125     );
    126 
    127 STATIC
    128 INTN EFIAPI
    129 _DbgOut (
    130     IN VOID     *Context,
    131     IN CHAR16   *Buffer
    132     );
    133 
    134 STATIC
    135 VOID
    136 PFLUSH (
    137     IN OUT PRINT_STATE     *ps
    138     );
    139 
    140 STATIC
    141 VOID
    142 PPUTC (
    143     IN OUT PRINT_STATE     *ps,
    144     IN CHAR16              c
    145     );
    146 
    147 STATIC
    148 VOID
    149 PITEM (
    150     IN OUT PRINT_STATE  *ps
    151     );
    152 
    153 STATIC
    154 CHAR16
    155 PGETC (
    156     IN POINTER      *p
    157     );
    158 
    159 STATIC
    160 VOID
    161 PSETATTR (
    162     IN OUT PRINT_STATE  *ps,
    163     IN UINTN             Attr
    164     );
    165 
    166 //
    167 //
    168 //
    169 
    170 INTN EFIAPI
    171 _SPrint (
    172     IN VOID     *Context,
    173     IN CHAR16   *Buffer
    174     );
    175 
    176 INTN EFIAPI
    177 _PoolPrint (
    178     IN VOID     *Context,
    179     IN CHAR16   *Buffer
    180     );
    181 
    182 INTN
    183 DbgPrint (
    184     IN INTN      mask,
    185     IN CHAR8     *fmt,
    186     ...
    187     )
    188 /*++
    189 
    190 Routine Description:
    191 
    192     Prints a formatted unicode string to the default StandardError console
    193 
    194 Arguments:
    195 
    196     mask        - Bit mask of debug string.  If a bit is set in the
    197                   mask that is also set in EFIDebug the string is
    198                   printed; otherwise, the string is not printed
    199 
    200     fmt         - Format string
    201 
    202 Returns:
    203 
    204     Length of string printed to the StandardError console
    205 
    206 --*/
    207 {
    208     SIMPLE_TEXT_OUTPUT_INTERFACE    *DbgOut;
    209     PRINT_STATE     ps;
    210     va_list         args;
    211     UINTN           back;
    212     UINTN           attr;
    213     UINTN           SavedAttribute;
    214 
    215 
    216     if (!(EFIDebug & mask)) {
    217         return 0;
    218     }
    219 
    220     va_start (args, fmt);
    221     ZeroMem (&ps, sizeof(ps));
    222 
    223     ps.Output = _DbgOut;
    224     ps.fmt.Ascii = TRUE;
    225     ps.fmt.pc = fmt;
    226     va_copy(ps.args, args);
    227     ps.Attr = EFI_TEXT_ATTR(EFI_LIGHTGRAY, EFI_RED);
    228 
    229     DbgOut = LibRuntimeDebugOut;
    230 
    231     if (!DbgOut) {
    232         DbgOut = ST->StdErr;
    233     }
    234 
    235     if (DbgOut) {
    236         ps.Attr = DbgOut->Mode->Attribute;
    237         ps.Context = DbgOut;
    238         ps.SetAttr = (INTN EFIAPI (*)(VOID *, UINTN))  DbgOut->SetAttribute;
    239     }
    240 
    241     SavedAttribute = ps.Attr;
    242 
    243     back = (ps.Attr >> 4) & 0xf;
    244     ps.AttrNorm = EFI_TEXT_ATTR(EFI_LIGHTGRAY, back);
    245     ps.AttrHighlight = EFI_TEXT_ATTR(EFI_WHITE, back);
    246     ps.AttrError = EFI_TEXT_ATTR(EFI_YELLOW, back);
    247 
    248     attr = ps.AttrNorm;
    249 
    250     if (mask & D_WARN) {
    251         attr = ps.AttrHighlight;
    252     }
    253 
    254     if (mask & D_ERROR) {
    255         attr = ps.AttrError;
    256     }
    257 
    258     if (ps.SetAttr) {
    259         ps.Attr = attr;
    260         ps.SetAttr (ps.Context, attr);
    261     }
    262 
    263     _Print (&ps);
    264 
    265     va_end (ps.args);
    266     va_end (args);
    267 
    268     //
    269     // Restore original attributes
    270     //
    271 
    272     if (ps.SetAttr) {
    273         ps.SetAttr (ps.Context, SavedAttribute);
    274     }
    275 
    276     return 0;
    277 }
    278 
    279 STATIC
    280 INTN
    281 IsLocalPrint(void *func)
    282 {
    283 	if (func == _DbgOut || func == _SPrint || func == _PoolPrint)
    284 		return 1;
    285 	return 0;
    286 }
    287 
    288 STATIC
    289 INTN EFIAPI
    290 _DbgOut (
    291     IN VOID     *Context,
    292     IN CHAR16   *Buffer
    293     )
    294 // Append string worker for DbgPrint
    295 {
    296     SIMPLE_TEXT_OUTPUT_INTERFACE    *DbgOut;
    297 
    298     DbgOut = Context;
    299 //    if (!DbgOut && ST && ST->ConOut) {
    300 //        DbgOut = ST->ConOut;
    301 //    }
    302 
    303     if (DbgOut) {
    304 	if (IsLocalPrint(DbgOut->OutputString))
    305 		DbgOut->OutputString(DbgOut, Buffer);
    306         else
    307 		uefi_call_wrapper(DbgOut->OutputString, 2, DbgOut, Buffer);
    308     }
    309 
    310     return 0;
    311 }
    312 
    313 INTN EFIAPI
    314 _SPrint (
    315     IN VOID     *Context,
    316     IN CHAR16   *Buffer
    317     )
    318 // Append string worker for SPrint, PoolPrint and CatPrint
    319 {
    320     UINTN           len;
    321     POOL_PRINT      *spc;
    322 
    323     spc = Context;
    324     len = StrLen(Buffer);
    325 
    326     //
    327     // Is the string is over the max truncate it
    328     //
    329 
    330     if (spc->len + len > spc->maxlen) {
    331         len = spc->maxlen - spc->len;
    332     }
    333 
    334     //
    335     // Append the new text
    336     //
    337 
    338     CopyMem (spc->str + spc->len, Buffer, len * sizeof(CHAR16));
    339     spc->len += len;
    340 
    341     //
    342     // Null terminate it
    343     //
    344 
    345     if (spc->len < spc->maxlen) {
    346         spc->str[spc->len] = 0;
    347     } else if (spc->maxlen) {
    348         spc->str[spc->maxlen-1] = 0;
    349     }
    350 
    351     return 0;
    352 }
    353 
    354 
    355 INTN EFIAPI
    356 _PoolPrint (
    357     IN VOID     *Context,
    358     IN CHAR16   *Buffer
    359     )
    360 // Append string worker for PoolPrint and CatPrint
    361 {
    362     UINTN           newlen;
    363     POOL_PRINT      *spc;
    364 
    365     spc = Context;
    366     newlen = spc->len + StrLen(Buffer) + 1;
    367 
    368     //
    369     // Is the string is over the max, grow the buffer
    370     //
    371 
    372     if (newlen > spc->maxlen) {
    373 
    374         //
    375         // Grow the pool buffer
    376         //
    377 
    378         newlen += PRINT_STRING_LEN;
    379         spc->maxlen = newlen;
    380         spc->str = ReallocatePool (
    381                         spc->str,
    382                         spc->len * sizeof(CHAR16),
    383                         spc->maxlen * sizeof(CHAR16)
    384                         );
    385 
    386         if (!spc->str) {
    387             spc->len = 0;
    388             spc->maxlen = 0;
    389         }
    390     }
    391 
    392     //
    393     // Append the new text
    394     //
    395 
    396     return _SPrint (Context, Buffer);
    397 }
    398 
    399 
    400 
    401 VOID
    402 _PoolCatPrint (
    403     IN CHAR16           *fmt,
    404     IN va_list          args,
    405     IN OUT POOL_PRINT   *spc,
    406     IN INTN EFIAPI      (*Output)(VOID *context, CHAR16 *str)
    407     )
    408 // Dispath function for SPrint, PoolPrint, and CatPrint
    409 {
    410     PRINT_STATE         ps;
    411 
    412     ZeroMem (&ps, sizeof(ps));
    413     ps.Output  = Output;
    414     ps.Context = spc;
    415     ps.fmt.pw = fmt;
    416     va_copy(ps.args, args);
    417     _Print (&ps);
    418     va_end(ps.args);
    419 }
    420 
    421 
    422 
    423 UINTN
    424 VSPrint (
    425     OUT CHAR16  *Str,
    426     IN UINTN    StrSize,
    427     IN CHAR16   *fmt,
    428     va_list     args
    429     )
    430 /*++
    431 
    432 Routine Description:
    433 
    434     Prints a formatted unicode string to a buffer using a va_list
    435 
    436 Arguments:
    437 
    438     Str         - Output buffer to print the formatted string into
    439 
    440     StrSize     - Size of Str.  String is truncated to this size.
    441                   A size of 0 means there is no limit
    442 
    443     fmt         - The format string
    444 
    445     args        - va_list
    446 
    447 
    448 Returns:
    449 
    450     String length returned in buffer
    451 
    452 --*/
    453 {
    454     POOL_PRINT          spc;
    455 
    456     spc.str    = Str;
    457     spc.maxlen = StrSize / sizeof(CHAR16) - 1;
    458     spc.len    = 0;
    459 
    460     _PoolCatPrint (fmt, args, &spc, _SPrint);
    461 
    462     return spc.len;
    463 }
    464 
    465 UINTN
    466 SPrint (
    467     OUT CHAR16  *Str,
    468     IN UINTN    StrSize,
    469     IN CHAR16   *fmt,
    470     ...
    471     )
    472 /*++
    473 
    474 Routine Description:
    475 
    476     Prints a formatted unicode string to a buffer
    477 
    478 Arguments:
    479 
    480     Str         - Output buffer to print the formatted string into
    481 
    482     StrSize     - Size of Str.  String is truncated to this size.
    483                   A size of 0 means there is no limit
    484 
    485     fmt         - The format string
    486 
    487 Returns:
    488 
    489     String length returned in buffer
    490 
    491 --*/
    492 {
    493     va_list          args;
    494     UINTN            len;
    495 
    496     va_start (args, fmt);
    497     len = VSPrint(Str, StrSize, fmt, args);
    498     va_end (args);
    499 
    500     return len;
    501 }
    502 
    503 
    504 CHAR16 *
    505 PoolPrint (
    506     IN CHAR16           *fmt,
    507     ...
    508     )
    509 /*++
    510 
    511 Routine Description:
    512 
    513     Prints a formatted unicode string to allocated pool.  The caller
    514     must free the resulting buffer.
    515 
    516 Arguments:
    517 
    518     fmt         - The format string
    519 
    520 Returns:
    521 
    522     Allocated buffer with the formatted string printed in it.
    523     The caller must free the allocated buffer.   The buffer
    524     allocation is not packed.
    525 
    526 --*/
    527 {
    528     POOL_PRINT          spc;
    529     va_list             args;
    530 
    531     ZeroMem (&spc, sizeof(spc));
    532     va_start (args, fmt);
    533     _PoolCatPrint (fmt, args, &spc, _PoolPrint);
    534     va_end (args);
    535     return spc.str;
    536 }
    537 
    538 
    539 
    540 CHAR16 *
    541 CatPrint (
    542     IN OUT POOL_PRINT   *Str,
    543     IN CHAR16           *fmt,
    544     ...
    545     )
    546 /*++
    547 
    548 Routine Description:
    549 
    550     Concatenates a formatted unicode string to allocated pool.
    551     The caller must free the resulting buffer.
    552 
    553 Arguments:
    554 
    555     Str         - Tracks the allocated pool, size in use, and
    556                   amount of pool allocated.
    557 
    558     fmt         - The format string
    559 
    560 Returns:
    561 
    562     Allocated buffer with the formatted string printed in it.
    563     The caller must free the allocated buffer.   The buffer
    564     allocation is not packed.
    565 
    566 --*/
    567 {
    568     va_list             args;
    569 
    570     va_start (args, fmt);
    571     _PoolCatPrint (fmt, args, Str, _PoolPrint);
    572     va_end (args);
    573     return Str->str;
    574 }
    575 
    576 
    577 
    578 UINTN
    579 Print (
    580     IN CHAR16   *fmt,
    581     ...
    582     )
    583 /*++
    584 
    585 Routine Description:
    586 
    587     Prints a formatted unicode string to the default console
    588 
    589 Arguments:
    590 
    591     fmt         - Format string
    592 
    593 Returns:
    594 
    595     Length of string printed to the console
    596 
    597 --*/
    598 {
    599     va_list     args;
    600     UINTN       back;
    601 
    602     va_start (args, fmt);
    603     back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
    604     va_end (args);
    605     return back;
    606 }
    607 
    608 UINTN
    609 VPrint (
    610     IN CHAR16   *fmt,
    611     va_list     args
    612     )
    613 /*++
    614 
    615 Routine Description:
    616 
    617     Prints a formatted unicode string to the default console using a va_list
    618 
    619 Arguments:
    620 
    621     fmt         - Format string
    622     args        - va_list
    623 Returns:
    624 
    625     Length of string printed to the console
    626 
    627 --*/
    628 {
    629     return _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
    630 }
    631 
    632 
    633 UINTN
    634 PrintAt (
    635     IN UINTN     Column,
    636     IN UINTN     Row,
    637     IN CHAR16    *fmt,
    638     ...
    639     )
    640 /*++
    641 
    642 Routine Description:
    643 
    644     Prints a formatted unicode string to the default console, at
    645     the supplied cursor position
    646 
    647 Arguments:
    648 
    649     Column, Row - The cursor position to print the string at
    650 
    651     fmt         - Format string
    652 
    653 Returns:
    654 
    655     Length of string printed to the console
    656 
    657 --*/
    658 {
    659     va_list     args;
    660     UINTN       back;
    661 
    662     va_start (args, fmt);
    663     back = _IPrint (Column, Row, ST->ConOut, fmt, NULL, args);
    664     va_end (args);
    665     return back;
    666 }
    667 
    668 
    669 UINTN
    670 IPrint (
    671     IN SIMPLE_TEXT_OUTPUT_INTERFACE    *Out,
    672     IN CHAR16                          *fmt,
    673     ...
    674     )
    675 /*++
    676 
    677 Routine Description:
    678 
    679     Prints a formatted unicode string to the specified console
    680 
    681 Arguments:
    682 
    683     Out         - The console to print the string too
    684 
    685     fmt         - Format string
    686 
    687 Returns:
    688 
    689     Length of string printed to the console
    690 
    691 --*/
    692 {
    693     va_list     args;
    694     UINTN       back;
    695 
    696     va_start (args, fmt);
    697     back = _IPrint ((UINTN) -1, (UINTN) -1, Out, fmt, NULL, args);
    698     va_end (args);
    699     return back;
    700 }
    701 
    702 
    703 UINTN
    704 IPrintAt (
    705     IN SIMPLE_TEXT_OUTPUT_INTERFACE     *Out,
    706     IN UINTN                            Column,
    707     IN UINTN                            Row,
    708     IN CHAR16                           *fmt,
    709     ...
    710     )
    711 /*++
    712 
    713 Routine Description:
    714 
    715     Prints a formatted unicode string to the specified console, at
    716     the supplied cursor position
    717 
    718 Arguments:
    719 
    720     Out         - The console to print the string too
    721 
    722     Column, Row - The cursor position to print the string at
    723 
    724     fmt         - Format string
    725 
    726 Returns:
    727 
    728     Length of string printed to the console
    729 
    730 --*/
    731 {
    732     va_list     args;
    733     UINTN       back;
    734 
    735     va_start (args, fmt);
    736     back = _IPrint (Column, Row, ST->ConOut, fmt, NULL, args);
    737     va_end (args);
    738     return back;
    739 }
    740 
    741 
    742 UINTN
    743 _IPrint (
    744     IN UINTN                            Column,
    745     IN UINTN                            Row,
    746     IN SIMPLE_TEXT_OUTPUT_INTERFACE     *Out,
    747     IN CHAR16                           *fmt,
    748     IN CHAR8                            *fmta,
    749     IN va_list                          args
    750     )
    751 // Display string worker for: Print, PrintAt, IPrint, IPrintAt
    752 {
    753     PRINT_STATE     ps;
    754     UINTN            back;
    755 
    756     ZeroMem (&ps, sizeof(ps));
    757     ps.Context = Out;
    758     ps.Output  = (INTN EFIAPI (*)(VOID *, CHAR16 *)) Out->OutputString;
    759     ps.SetAttr = (INTN EFIAPI (*)(VOID *, UINTN))  Out->SetAttribute;
    760     ps.Attr = Out->Mode->Attribute;
    761 
    762     back = (ps.Attr >> 4) & 0xF;
    763     ps.AttrNorm = EFI_TEXT_ATTR(EFI_LIGHTGRAY, back);
    764     ps.AttrHighlight = EFI_TEXT_ATTR(EFI_WHITE, back);
    765     ps.AttrError = EFI_TEXT_ATTR(EFI_YELLOW, back);
    766 
    767     if (fmt) {
    768         ps.fmt.pw = fmt;
    769     } else {
    770         ps.fmt.Ascii = TRUE;
    771         ps.fmt.pc = fmta;
    772     }
    773 
    774     va_copy(ps.args, args);
    775 
    776     if (Column != (UINTN) -1) {
    777         uefi_call_wrapper(Out->SetCursorPosition, 3, Out, Column, Row);
    778     }
    779 
    780     back = _Print (&ps);
    781     va_end(ps.args);
    782     return back;
    783 }
    784 
    785 
    786 UINTN
    787 APrint (
    788     IN CHAR8    *fmt,
    789     ...
    790     )
    791 /*++
    792 
    793 Routine Description:
    794 
    795     For those whom really can't deal with unicode, a print
    796     function that takes an ascii format string
    797 
    798 Arguments:
    799 
    800     fmt         - ascii format string
    801 
    802 Returns:
    803 
    804     Length of string printed to the console
    805 
    806 --*/
    807 
    808 {
    809     va_list     args;
    810     UINTN       back;
    811 
    812     va_start (args, fmt);
    813     back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, NULL, fmt, args);
    814     va_end (args);
    815     return back;
    816 }
    817 
    818 
    819 STATIC
    820 VOID
    821 PFLUSH (
    822     IN OUT PRINT_STATE     *ps
    823     )
    824 {
    825     *ps->Pos = 0;
    826     if (IsLocalPrint(ps->Output))
    827 	ps->Output(ps->Context, ps->Buffer);
    828     else
    829     	uefi_call_wrapper(ps->Output, 2, ps->Context, ps->Buffer);
    830     ps->Pos = ps->Buffer;
    831 }
    832 
    833 STATIC
    834 VOID
    835 PSETATTR (
    836     IN OUT PRINT_STATE  *ps,
    837     IN UINTN             Attr
    838     )
    839 {
    840    PFLUSH (ps);
    841 
    842    ps->RestoreAttr = ps->Attr;
    843    if (ps->SetAttr) {
    844 	uefi_call_wrapper(ps->SetAttr, 2, ps->Context, Attr);
    845    }
    846 
    847    ps->Attr = Attr;
    848 }
    849 
    850 STATIC
    851 VOID
    852 PPUTC (
    853     IN OUT PRINT_STATE     *ps,
    854     IN CHAR16              c
    855     )
    856 {
    857     // if this is a newline, add a carraige return
    858     if (c == '\n') {
    859         PPUTC (ps, '\r');
    860     }
    861 
    862     *ps->Pos = c;
    863     ps->Pos += 1;
    864     ps->Len += 1;
    865 
    866     // if at the end of the buffer, flush it
    867     if (ps->Pos >= ps->End) {
    868         PFLUSH(ps);
    869     }
    870 }
    871 
    872 
    873 STATIC
    874 CHAR16
    875 PGETC (
    876     IN POINTER      *p
    877     )
    878 {
    879     CHAR16      c;
    880 
    881     c = p->Ascii ? p->pc[p->Index] : p->pw[p->Index];
    882     p->Index += 1;
    883 
    884     return  c;
    885 }
    886 
    887 
    888 STATIC
    889 VOID
    890 PITEM (
    891     IN OUT PRINT_STATE  *ps
    892     )
    893 {
    894     UINTN               Len, i;
    895     PRINT_ITEM          *Item;
    896     CHAR16              c;
    897 
    898     // Get the length of the item
    899     Item = ps->Item;
    900     Item->Item.Index = 0;
    901     while (Item->Item.Index < Item->FieldWidth) {
    902         c = PGETC(&Item->Item);
    903         if (!c) {
    904             Item->Item.Index -= 1;
    905             break;
    906         }
    907     }
    908     Len = Item->Item.Index;
    909 
    910     // if there is no item field width, use the items width
    911     if (Item->FieldWidth == (UINTN) -1) {
    912         Item->FieldWidth = Len;
    913     }
    914 
    915     // if item is larger then width, update width
    916     if (Len > Item->Width) {
    917         Item->Width = Len;
    918     }
    919 
    920 
    921     // if pad field before, add pad char
    922     if (Item->PadBefore) {
    923         for (i=Item->Width; i < Item->FieldWidth; i+=1) {
    924             PPUTC (ps, ' ');
    925         }
    926     }
    927 
    928     // pad item
    929     for (i=Len; i < Item->Width; i++) {
    930         PPUTC (ps, Item->Pad);
    931     }
    932 
    933     // add the item
    934     Item->Item.Index=0;
    935     while (Item->Item.Index < Len) {
    936         PPUTC (ps, PGETC(&Item->Item));
    937     }
    938 
    939     // If pad at the end, add pad char
    940     if (!Item->PadBefore) {
    941         for (i=Item->Width; i < Item->FieldWidth; i+=1) {
    942             PPUTC (ps, ' ');
    943         }
    944     }
    945 }
    946 
    947 
    948 STATIC
    949 UINTN
    950 _Print (
    951     IN PRINT_STATE     *ps
    952     )
    953 /*++
    954 
    955 Routine Description:
    956 
    957     %w.lF   -   w = width
    958                 l = field width
    959                 F = format of arg
    960 
    961   Args F:
    962     0       -   pad with zeros
    963     -       -   justify on left (default is on right)
    964     ,       -   add comma's to field
    965     *       -   width provided on stack
    966     n       -   Set output attribute to normal (for this field only)
    967     h       -   Set output attribute to highlight (for this field only)
    968     e       -   Set output attribute to error (for this field only)
    969     l       -   Value is 64 bits
    970 
    971     a       -   ascii string
    972     s       -   unicode string
    973     X       -   fixed 8 byte value in hex
    974     x       -   hex value
    975     d       -   value as decimal
    976     c       -   Unicode char
    977     t       -   EFI time structure
    978     g       -   Pointer to GUID
    979     r       -   EFI status code (result code)
    980 
    981     N       -   Set output attribute to normal
    982     H       -   Set output attribute to highlight
    983     E       -   Set output attribute to error
    984     %       -   Print a %
    985 
    986 Arguments:
    987 
    988     SystemTable     - The system table
    989 
    990 Returns:
    991 
    992     Number of charactors written
    993 
    994 --*/
    995 {
    996     CHAR16          c;
    997     UINTN           Attr;
    998     PRINT_ITEM      Item;
    999     CHAR16          Buffer[PRINT_STRING_LEN];
   1000 
   1001     ps->Len = 0;
   1002     ps->Buffer = Buffer;
   1003     ps->Pos = Buffer;
   1004     ps->End = Buffer + PRINT_STRING_LEN - 1;
   1005     ps->Item = &Item;
   1006 
   1007     ps->fmt.Index = 0;
   1008     while ((c = PGETC(&ps->fmt))) {
   1009 
   1010         if (c != '%') {
   1011             PPUTC ( ps, c );
   1012             continue;
   1013         }
   1014 
   1015         // setup for new item
   1016         Item.FieldWidth = (UINTN) -1;
   1017         Item.Width = 0;
   1018         Item.WidthParse = &Item.Width;
   1019         Item.Pad = ' ';
   1020         Item.PadBefore = TRUE;
   1021         Item.Comma = FALSE;
   1022         Item.Long = FALSE;
   1023         Item.Item.Ascii = FALSE;
   1024         Item.Item.pw = NULL;
   1025         ps->RestoreAttr = 0;
   1026         Attr = 0;
   1027 
   1028         while ((c = PGETC(&ps->fmt))) {
   1029 
   1030             switch (c) {
   1031 
   1032             case '%':
   1033                 //
   1034                 // %% -> %
   1035                 //
   1036                 Item.Item.pw = Item.Scratch;
   1037                 Item.Item.pw[0] = '%';
   1038                 Item.Item.pw[1] = 0;
   1039                 break;
   1040 
   1041             case '0':
   1042                 Item.Pad = '0';
   1043                 break;
   1044 
   1045             case '-':
   1046                 Item.PadBefore = FALSE;
   1047                 break;
   1048 
   1049             case ',':
   1050                 Item.Comma = TRUE;
   1051                 break;
   1052 
   1053             case '.':
   1054                 Item.WidthParse = &Item.FieldWidth;
   1055                 break;
   1056 
   1057             case '*':
   1058                 *Item.WidthParse = va_arg(ps->args, UINTN);
   1059                 break;
   1060 
   1061             case '1':
   1062             case '2':
   1063             case '3':
   1064             case '4':
   1065             case '5':
   1066             case '6':
   1067             case '7':
   1068             case '8':
   1069             case '9':
   1070                 *Item.WidthParse = 0;
   1071                 do {
   1072                     *Item.WidthParse = *Item.WidthParse * 10 + c - '0';
   1073                     c = PGETC(&ps->fmt);
   1074                 } while (c >= '0'  &&  c <= '9') ;
   1075                 ps->fmt.Index -= 1;
   1076                 break;
   1077 
   1078             case 'a':
   1079                 Item.Item.pc = va_arg(ps->args, CHAR8 *);
   1080                 Item.Item.Ascii = TRUE;
   1081                 if (!Item.Item.pc) {
   1082                     Item.Item.pc = (CHAR8 *)"(null)";
   1083                 }
   1084                 break;
   1085 
   1086             case 's':
   1087                 Item.Item.pw = va_arg(ps->args, CHAR16 *);
   1088                 if (!Item.Item.pw) {
   1089                     Item.Item.pw = L"(null)";
   1090                 }
   1091                 break;
   1092 
   1093             case 'c':
   1094                 Item.Item.pw = Item.Scratch;
   1095                 Item.Item.pw[0] = (CHAR16) va_arg(ps->args, UINTN);
   1096                 Item.Item.pw[1] = 0;
   1097                 break;
   1098 
   1099             case 'l':
   1100                 Item.Long = TRUE;
   1101                 break;
   1102 
   1103             case 'X':
   1104                 Item.Width = Item.Long ? 16 : 8;
   1105                 Item.Pad = '0';
   1106             case 'x':
   1107                 Item.Item.pw = Item.Scratch;
   1108                 ValueToHex (
   1109                     Item.Item.pw,
   1110                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
   1111                     );
   1112 
   1113                 break;
   1114 
   1115 
   1116             case 'g':
   1117                 Item.Item.pw = Item.Scratch;
   1118                 GuidToString (Item.Item.pw, va_arg(ps->args, EFI_GUID *));
   1119                 break;
   1120 
   1121             case 'd':
   1122                 Item.Item.pw = Item.Scratch;
   1123                 ValueToString (
   1124                     Item.Item.pw,
   1125                     Item.Comma,
   1126                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
   1127                     );
   1128                 break
   1129                     ;
   1130             case 't':
   1131                 Item.Item.pw = Item.Scratch;
   1132                 TimeToString (Item.Item.pw, va_arg(ps->args, EFI_TIME *));
   1133                 break;
   1134 
   1135             case 'r':
   1136                 Item.Item.pw = Item.Scratch;
   1137                 StatusToString (Item.Item.pw, va_arg(ps->args, EFI_STATUS));
   1138                 break;
   1139 
   1140             case 'n':
   1141                 PSETATTR(ps, ps->AttrNorm);
   1142                 break;
   1143 
   1144             case 'h':
   1145                 PSETATTR(ps, ps->AttrHighlight);
   1146                 break;
   1147 
   1148             case 'e':
   1149                 PSETATTR(ps, ps->AttrError);
   1150                 break;
   1151 
   1152             case 'N':
   1153                 Attr = ps->AttrNorm;
   1154                 break;
   1155 
   1156             case 'H':
   1157                 Attr = ps->AttrHighlight;
   1158                 break;
   1159 
   1160             case 'E':
   1161                 Attr = ps->AttrError;
   1162                 break;
   1163 
   1164             default:
   1165                 Item.Item.pw = Item.Scratch;
   1166                 Item.Item.pw[0] = '?';
   1167                 Item.Item.pw[1] = 0;
   1168                 break;
   1169             }
   1170 
   1171             // if we have an Item
   1172             if (Item.Item.pw) {
   1173                 PITEM (ps);
   1174                 break;
   1175             }
   1176 
   1177             // if we have an Attr set
   1178             if (Attr) {
   1179                 PSETATTR(ps, Attr);
   1180                 ps->RestoreAttr = 0;
   1181                 break;
   1182             }
   1183         }
   1184 
   1185         if (ps->RestoreAttr) {
   1186             PSETATTR(ps, ps->RestoreAttr);
   1187         }
   1188     }
   1189 
   1190     // Flush buffer
   1191     PFLUSH (ps);
   1192     return ps->Len;
   1193 }
   1194 
   1195 STATIC CHAR8 Hex[] = {'0','1','2','3','4','5','6','7',
   1196                       '8','9','A','B','C','D','E','F'};
   1197 
   1198 VOID
   1199 ValueToHex (
   1200     IN CHAR16   *Buffer,
   1201     IN UINT64   v
   1202     )
   1203 {
   1204     CHAR8           str[30], *p1;
   1205     CHAR16          *p2;
   1206 
   1207     if (!v) {
   1208         Buffer[0] = '0';
   1209         Buffer[1] = 0;
   1210         return ;
   1211     }
   1212 
   1213     p1 = str;
   1214     p2 = Buffer;
   1215 
   1216     while (v) {
   1217         *(p1++) = Hex[v & 0xf];
   1218         v = RShiftU64 (v, 4);
   1219     }
   1220 
   1221     while (p1 != str) {
   1222         *(p2++) = *(--p1);
   1223     }
   1224     *p2 = 0;
   1225 }
   1226 
   1227 
   1228 VOID
   1229 ValueToString (
   1230     IN CHAR16   *Buffer,
   1231     IN BOOLEAN  Comma,
   1232     IN INT64    v
   1233     )
   1234 {
   1235     STATIC CHAR8 ca[] = {  3, 1, 2 };
   1236     CHAR8        str[40], *p1;
   1237     CHAR16       *p2;
   1238     UINTN        c, r;
   1239 
   1240     if (!v) {
   1241         Buffer[0] = '0';
   1242         Buffer[1] = 0;
   1243         return ;
   1244     }
   1245 
   1246     p1 = str;
   1247     p2 = Buffer;
   1248 
   1249     if (v < 0) {
   1250         *(p2++) = '-';
   1251         v = -v;
   1252     }
   1253 
   1254     while (v) {
   1255         v = (INT64)DivU64x32 ((UINT64)v, 10, &r);
   1256         *(p1++) = (CHAR8)r + '0';
   1257     }
   1258 
   1259     c = (Comma ? ca[(p1 - str) % 3] : 999) + 1;
   1260     while (p1 != str) {
   1261 
   1262         c -= 1;
   1263         if (!c) {
   1264             *(p2++) = ',';
   1265             c = 3;
   1266         }
   1267 
   1268         *(p2++) = *(--p1);
   1269     }
   1270     *p2 = 0;
   1271 }
   1272 
   1273 VOID
   1274 TimeToString (
   1275     OUT CHAR16      *Buffer,
   1276     IN EFI_TIME     *Time
   1277     )
   1278 {
   1279     UINTN       Hour, Year;
   1280     CHAR16      AmPm;
   1281 
   1282     AmPm = 'a';
   1283     Hour = Time->Hour;
   1284     if (Time->Hour == 0) {
   1285         Hour = 12;
   1286     } else if (Time->Hour >= 12) {
   1287         AmPm = 'p';
   1288         if (Time->Hour >= 13) {
   1289             Hour -= 12;
   1290         }
   1291     }
   1292 
   1293     Year = Time->Year % 100;
   1294 
   1295     // bugbug: for now just print it any old way
   1296     SPrint (Buffer, 0, L"%02d/%02d/%02d  %02d:%02d%c",
   1297         Time->Month,
   1298         Time->Day,
   1299         Year,
   1300         Hour,
   1301         Time->Minute,
   1302         AmPm
   1303         );
   1304 }
   1305 
   1306 
   1307 
   1308 
   1309 VOID
   1310 DumpHex (
   1311     IN UINTN        Indent,
   1312     IN UINTN        Offset,
   1313     IN UINTN        DataSize,
   1314     IN VOID         *UserData
   1315     )
   1316 {
   1317     CHAR8           *Data, Val[50], Str[20], c;
   1318     UINTN           Size, Index;
   1319 
   1320     UINTN           ScreenCount;
   1321     UINTN           TempColumn;
   1322     UINTN           ScreenSize;
   1323     CHAR16          ReturnStr[1];
   1324 
   1325 
   1326     uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &TempColumn, &ScreenSize);
   1327     ScreenCount = 0;
   1328     ScreenSize -= 2;
   1329 
   1330     Data = UserData;
   1331     while (DataSize) {
   1332         Size = 16;
   1333         if (Size > DataSize) {
   1334             Size = DataSize;
   1335         }
   1336 
   1337         for (Index=0; Index < Size; Index += 1) {
   1338             c = Data[Index];
   1339             Val[Index*3+0] = Hex[c>>4];
   1340             Val[Index*3+1] = Hex[c&0xF];
   1341             Val[Index*3+2] = (Index == 7)?'-':' ';
   1342             Str[Index] = (c < ' ' || c > 'z') ? '.' : c;
   1343         }
   1344 
   1345         Val[Index*3] = 0;
   1346         Str[Index] = 0;
   1347         Print (L"%*a%X: %-.48a *%a*\n", Indent, "", Offset, Val, Str);
   1348 
   1349         Data += Size;
   1350         Offset += Size;
   1351         DataSize -= Size;
   1352 
   1353         ScreenCount++;
   1354         if (ScreenCount >= ScreenSize && ScreenSize != 0) {
   1355             //
   1356             // If ScreenSize == 0 we have the console redirected so don't
   1357             //  block updates
   1358             //
   1359             ScreenCount = 0;
   1360             Print (L"Press Enter to continue :");
   1361             Input (L"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16));
   1362             Print (L"\n");
   1363         }
   1364 
   1365     }
   1366 }
   1367