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