Home | History | Annotate | Line # | Download | only in lib
print.c revision 1.3
      1 /*	$NetBSD: print.c,v 1.3 2019/01/27 02:08:43 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 >>>>>>> 1.1.1.1.34.1
    536 
    537 CHAR16 *
    538 PoolPrint (
    539     IN CONST CHAR16     *fmt,
    540     ...
    541     )
    542 /*++
    543 
    544 Routine Description:
    545 
    546     Prints a formatted unicode string to allocated pool.  The caller
    547     must free the resulting buffer.
    548 
    549 Arguments:
    550 
    551     fmt         - The format string
    552 
    553 Returns:
    554 
    555     Allocated buffer with the formatted string printed in it.
    556     The caller must free the allocated buffer.   The buffer
    557     allocation is not packed.
    558 
    559 --*/
    560 {
    561     va_list args;
    562     CHAR16 *pool;
    563     va_start (args, fmt);
    564     pool = VPoolPrint(fmt, args);
    565     va_end (args);
    566     return pool;
    567 }
    568 
    569 CHAR16 *
    570 CatPrint (
    571     IN OUT POOL_PRINT   *Str,
    572     IN CONST CHAR16     *fmt,
    573     ...
    574     )
    575 /*++
    576 
    577 Routine Description:
    578 
    579     Concatenates a formatted unicode string to allocated pool.
    580     The caller must free the resulting buffer.
    581 
    582 Arguments:
    583 
    584     Str         - Tracks the allocated pool, size in use, and
    585                   amount of pool allocated.
    586 
    587     fmt         - The format string
    588 
    589 Returns:
    590 
    591     Allocated buffer with the formatted string printed in it.
    592     The caller must free the allocated buffer.   The buffer
    593     allocation is not packed.
    594 
    595 --*/
    596 {
    597     va_list             args;
    598 
    599     va_start (args, fmt);
    600     _PoolCatPrint (fmt, args, Str, _PoolPrint);
    601     va_end (args);
    602     return Str->str;
    603 }
    604 
    605 
    606 
    607 UINTN
    608 Print (
    609     IN CONST CHAR16   *fmt,
    610     ...
    611     )
    612 /*++
    613 
    614 Routine Description:
    615 
    616     Prints a formatted unicode string to the default console
    617 
    618 Arguments:
    619 
    620     fmt         - Format string
    621 
    622 Returns:
    623 
    624     Length of string printed to the console
    625 
    626 --*/
    627 {
    628     va_list     args;
    629     UINTN       back;
    630 
    631     va_start (args, fmt);
    632     back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
    633     va_end (args);
    634     return back;
    635 }
    636 
    637 UINTN
    638 VPrint (
    639     IN CONST CHAR16   *fmt,
    640     va_list           args
    641     )
    642 /*++
    643 
    644 Routine Description:
    645 
    646     Prints a formatted unicode string to the default console using a va_list
    647 
    648 Arguments:
    649 
    650     fmt         - Format string
    651     args        - va_list
    652 Returns:
    653 
    654     Length of string printed to the console
    655 
    656 --*/
    657 {
    658     return _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
    659 }
    660 
    661 
    662 UINTN
    663 PrintAt (
    664     IN UINTN          Column,
    665     IN UINTN          Row,
    666     IN CONST CHAR16   *fmt,
    667     ...
    668     )
    669 /*++
    670 
    671 Routine Description:
    672 
    673     Prints a formatted unicode string to the default console, at
    674     the supplied cursor position
    675 
    676 Arguments:
    677 
    678     Column, Row - The cursor position to print the string at
    679 
    680     fmt         - Format string
    681 
    682 Returns:
    683 
    684     Length of string printed to the console
    685 
    686 --*/
    687 {
    688     va_list     args;
    689     UINTN       back;
    690 
    691     va_start (args, fmt);
    692     back = _IPrint (Column, Row, ST->ConOut, fmt, NULL, args);
    693     va_end (args);
    694     return back;
    695 }
    696 
    697 
    698 UINTN
    699 IPrint (
    700     IN SIMPLE_TEXT_OUTPUT_INTERFACE    *Out,
    701     IN CONST CHAR16                    *fmt,
    702     ...
    703     )
    704 /*++
    705 
    706 Routine Description:
    707 
    708     Prints a formatted unicode string to the specified console
    709 
    710 Arguments:
    711 
    712     Out         - The console to print the string too
    713 
    714     fmt         - Format string
    715 
    716 Returns:
    717 
    718     Length of string printed to the console
    719 
    720 --*/
    721 {
    722     va_list     args;
    723     UINTN       back;
    724 
    725     va_start (args, fmt);
    726     back = _IPrint ((UINTN) -1, (UINTN) -1, Out, fmt, NULL, args);
    727     va_end (args);
    728     return back;
    729 }
    730 
    731 
    732 UINTN
    733 IPrintAt (
    734     IN SIMPLE_TEXT_OUTPUT_INTERFACE     *Out,
    735     IN UINTN                            Column,
    736     IN UINTN                            Row,
    737     IN CONST CHAR16                     *fmt,
    738     ...
    739     )
    740 /*++
    741 
    742 Routine Description:
    743 
    744     Prints a formatted unicode string to the specified console, at
    745     the supplied cursor position
    746 
    747 Arguments:
    748 
    749     Out         - The console to print the string to
    750 
    751     Column, Row - The cursor position to print the string at
    752 
    753     fmt         - Format string
    754 
    755 Returns:
    756 
    757     Length of string printed to the console
    758 
    759 --*/
    760 {
    761     va_list     args;
    762     UINTN       back;
    763 
    764     va_start (args, fmt);
    765     back = _IPrint (Column, Row, Out, fmt, NULL, args);
    766     va_end (args);
    767     return back;
    768 }
    769 
    770 
    771 UINTN
    772 _IPrint (
    773     IN UINTN                            Column,
    774     IN UINTN                            Row,
    775     IN SIMPLE_TEXT_OUTPUT_INTERFACE     *Out,
    776     IN CONST CHAR16                     *fmt,
    777     IN CONST CHAR8                      *fmta,
    778     IN va_list                          args
    779     )
    780 // Display string worker for: Print, PrintAt, IPrint, IPrintAt
    781 {
    782     PRINT_STATE     ps;
    783     UINTN            back;
    784 
    785     ZeroMem (&ps, sizeof(ps));
    786     ps.Context = Out;
    787     ps.Output  = (INTN (EFIAPI *)(VOID *, CHAR16 *)) Out->OutputString;
    788     ps.SetAttr = (INTN (EFIAPI *)(VOID *, UINTN))  Out->SetAttribute;
    789     ps.Attr = Out->Mode->Attribute;
    790 
    791     back = (ps.Attr >> 4) & 0xF;
    792     ps.AttrNorm = EFI_TEXT_ATTR(EFI_LIGHTGRAY, back);
    793     ps.AttrHighlight = EFI_TEXT_ATTR(EFI_WHITE, back);
    794     ps.AttrError = EFI_TEXT_ATTR(EFI_YELLOW, back);
    795 
    796     if (fmt) {
    797         ps.fmt.pw = fmt;
    798     } else {
    799         ps.fmt.Ascii = TRUE;
    800         ps.fmt.pc = fmta;
    801     }
    802 
    803     va_copy(ps.args, args);
    804 
    805     if (Column != (UINTN) -1) {
    806         uefi_call_wrapper(Out->SetCursorPosition, 3, Out, Column, Row);
    807     }
    808 
    809     back = _Print (&ps);
    810     va_end(ps.args);
    811     return back;
    812 }
    813 
    814 
    815 UINTN
    816 APrint (
    817     IN CONST CHAR8    *fmt,
    818     ...
    819     )
    820 /*++
    821 
    822 Routine Description:
    823 
    824     For those whom really can't deal with unicode, a print
    825     function that takes an ascii format string
    826 
    827 Arguments:
    828 
    829     fmt         - ascii format string
    830 
    831 Returns:
    832 
    833     Length of string printed to the console
    834 
    835 --*/
    836 
    837 {
    838     va_list     args;
    839     UINTN       back;
    840 
    841     va_start (args, fmt);
    842     back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, NULL, fmt, args);
    843     va_end (args);
    844     return back;
    845 }
    846 
    847 
    848 STATIC
    849 VOID
    850 PFLUSH (
    851     IN OUT PRINT_STATE     *ps
    852     )
    853 {
    854     *ps->Pos = 0;
    855     if (IsLocalPrint(ps->Output))
    856 	ps->Output(ps->Context, ps->Buffer);
    857     else
    858     	uefi_call_wrapper(ps->Output, 2, ps->Context, ps->Buffer);
    859     ps->Pos = ps->Buffer;
    860 }
    861 
    862 STATIC
    863 VOID
    864 PSETATTR (
    865     IN OUT PRINT_STATE  *ps,
    866     IN UINTN             Attr
    867     )
    868 {
    869    PFLUSH (ps);
    870 
    871    ps->RestoreAttr = ps->Attr;
    872    if (ps->SetAttr) {
    873 	uefi_call_wrapper(ps->SetAttr, 2, ps->Context, Attr);
    874    }
    875 
    876    ps->Attr = Attr;
    877 }
    878 
    879 STATIC
    880 VOID
    881 PPUTC (
    882     IN OUT PRINT_STATE     *ps,
    883     IN CHAR16              c
    884     )
    885 {
    886     // if this is a newline, add a carraige return
    887     if (c == '\n') {
    888         PPUTC (ps, '\r');
    889     }
    890 
    891     *ps->Pos = c;
    892     ps->Pos += 1;
    893     ps->Len += 1;
    894 
    895     // if at the end of the buffer, flush it
    896     if (ps->Pos >= ps->End) {
    897         PFLUSH(ps);
    898     }
    899 }
    900 
    901 
    902 STATIC
    903 CHAR16
    904 PGETC (
    905     IN POINTER      *p
    906     )
    907 {
    908     CHAR16      c;
    909 
    910     c = p->Ascii ? p->pc[p->Index] : p->pw[p->Index];
    911     p->Index += 1;
    912 
    913     return  c;
    914 }
    915 
    916 
    917 STATIC
    918 VOID
    919 PITEM (
    920     IN OUT PRINT_STATE  *ps
    921     )
    922 {
    923     UINTN               Len, i;
    924     PRINT_ITEM          *Item;
    925     CHAR16              c;
    926 
    927     // Get the length of the item
    928     Item = ps->Item;
    929     Item->Item.Index = 0;
    930     while (Item->Item.Index < Item->FieldWidth) {
    931         c = PGETC(&Item->Item);
    932         if (!c) {
    933             Item->Item.Index -= 1;
    934             break;
    935         }
    936     }
    937     Len = Item->Item.Index;
    938 
    939     // if there is no item field width, use the items width
    940     if (Item->FieldWidth == (UINTN) -1) {
    941         Item->FieldWidth = Len;
    942     }
    943 
    944     // if item is larger then width, update width
    945     if (Len > Item->Width) {
    946         Item->Width = Len;
    947     }
    948 
    949 
    950     // if pad field before, add pad char
    951     if (Item->PadBefore) {
    952         for (i=Item->Width; i < Item->FieldWidth; i+=1) {
    953             PPUTC (ps, ' ');
    954         }
    955     }
    956 
    957     // pad item
    958     for (i=Len; i < Item->Width; i++) {
    959         PPUTC (ps, Item->Pad);
    960     }
    961 
    962     // add the item
    963     Item->Item.Index=0;
    964     while (Item->Item.Index < Len) {
    965         PPUTC (ps, PGETC(&Item->Item));
    966     }
    967 
    968     // If pad at the end, add pad char
    969     if (!Item->PadBefore) {
    970         for (i=Item->Width; i < Item->FieldWidth; i+=1) {
    971             PPUTC (ps, ' ');
    972         }
    973     }
    974 }
    975 
    976 
    977 STATIC
    978 UINTN
    979 _Print (
    980     IN PRINT_STATE     *ps
    981     )
    982 /*++
    983 
    984 Routine Description:
    985 
    986     %w.lF   -   w = width
    987                 l = field width
    988                 F = format of arg
    989 
    990   Args F:
    991     0       -   pad with zeros
    992     -       -   justify on left (default is on right)
    993     ,       -   add comma's to field
    994     *       -   width provided on stack
    995     n       -   Set output attribute to normal (for this field only)
    996     h       -   Set output attribute to highlight (for this field only)
    997     e       -   Set output attribute to error (for this field only)
    998     l       -   Value is 64 bits
    999 
   1000     a       -   ascii string
   1001     s       -   unicode string
   1002     X       -   fixed 8 byte value in hex
   1003     x       -   hex value
   1004     d       -   value as signed decimal
   1005     u       -   value as unsigned decimal
   1006     f       -   value as floating point
   1007     c       -   Unicode char
   1008     t       -   EFI time structure
   1009     g       -   Pointer to GUID
   1010     r       -   EFI status code (result code)
   1011     D       -   pointer to Device Path with normal ending.
   1012 
   1013     N       -   Set output attribute to normal
   1014     H       -   Set output attribute to highlight
   1015     E       -   Set output attribute to error
   1016     %       -   Print a %
   1017 
   1018 Arguments:
   1019 
   1020     SystemTable     - The system table
   1021 
   1022 Returns:
   1023 
   1024     Number of charactors written
   1025 
   1026 --*/
   1027 {
   1028     CHAR16          c;
   1029     UINTN           Attr;
   1030     PRINT_ITEM      Item;
   1031     CHAR16          Buffer[PRINT_STRING_LEN];
   1032 
   1033     ps->Len = 0;
   1034     ps->Buffer = Buffer;
   1035     ps->Pos = Buffer;
   1036     ps->End = Buffer + PRINT_STRING_LEN - 1;
   1037     ps->Item = &Item;
   1038 
   1039     ps->fmt.Index = 0;
   1040     while ((c = PGETC(&ps->fmt))) {
   1041 
   1042         if (c != '%') {
   1043             PPUTC ( ps, c );
   1044             continue;
   1045         }
   1046 
   1047         // setup for new item
   1048         Item.FieldWidth = (UINTN) -1;
   1049         Item.Width = 0;
   1050         Item.WidthParse = &Item.Width;
   1051         Item.Pad = ' ';
   1052         Item.PadBefore = TRUE;
   1053         Item.Comma = FALSE;
   1054         Item.Long = FALSE;
   1055         Item.Item.Ascii = FALSE;
   1056         Item.Item.pw = NULL;
   1057         ps->RestoreAttr = 0;
   1058         Attr = 0;
   1059 
   1060         while ((c = PGETC(&ps->fmt))) {
   1061 
   1062             switch (c) {
   1063 
   1064             case '%':
   1065                 //
   1066                 // %% -> %
   1067                 //
   1068                 Item.Scratch[0] = '%';
   1069                 Item.Scratch[1] = 0;
   1070                 Item.Item.pw = Item.Scratch;
   1071                 break;
   1072 
   1073             case '0':
   1074                 Item.Pad = '0';
   1075                 break;
   1076 
   1077             case '-':
   1078                 Item.PadBefore = FALSE;
   1079                 break;
   1080 
   1081             case ',':
   1082                 Item.Comma = TRUE;
   1083                 break;
   1084 
   1085             case '.':
   1086                 Item.WidthParse = &Item.FieldWidth;
   1087                 break;
   1088 
   1089             case '*':
   1090                 *Item.WidthParse = va_arg(ps->args, UINTN);
   1091                 break;
   1092 
   1093             case '1':
   1094             case '2':
   1095             case '3':
   1096             case '4':
   1097             case '5':
   1098             case '6':
   1099             case '7':
   1100             case '8':
   1101             case '9':
   1102                 *Item.WidthParse = 0;
   1103                 do {
   1104                     *Item.WidthParse = *Item.WidthParse * 10 + c - '0';
   1105                     c = PGETC(&ps->fmt);
   1106                 } while (c >= '0'  &&  c <= '9') ;
   1107                 ps->fmt.Index -= 1;
   1108                 break;
   1109 
   1110             case 'a':
   1111                 Item.Item.pc = va_arg(ps->args, CHAR8 *);
   1112                 Item.Item.Ascii = TRUE;
   1113                 if (!Item.Item.pc) {
   1114                     Item.Item.pc = (CHAR8 *)"(null)";
   1115                 }
   1116                 break;
   1117 
   1118             case 's':
   1119                 Item.Item.pw = va_arg(ps->args, CHAR16 *);
   1120                 if (!Item.Item.pw) {
   1121                     Item.Item.pw = L"(null)";
   1122                 }
   1123                 break;
   1124 
   1125             case 'c':
   1126                 Item.Scratch[0] = (CHAR16) va_arg(ps->args, UINTN);
   1127                 Item.Scratch[1] = 0;
   1128                 Item.Item.pw = Item.Scratch;
   1129                 break;
   1130 
   1131             case 'l':
   1132                 Item.Long = TRUE;
   1133                 break;
   1134 
   1135             case 'X':
   1136                 Item.Width = Item.Long ? 16 : 8;
   1137                 Item.Pad = '0';
   1138 #if __GNUC__ >= 7
   1139 		__attribute__ ((fallthrough));
   1140 #endif
   1141             case 'x':
   1142                 ValueToHex (
   1143                     Item.Scratch,
   1144                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
   1145                     );
   1146                 Item.Item.pw = Item.Scratch;
   1147 
   1148                 break;
   1149 
   1150 
   1151             case 'g':
   1152                 GuidToString (Item.Scratch, va_arg(ps->args, EFI_GUID *));
   1153                 Item.Item.pw = Item.Scratch;
   1154                 break;
   1155 
   1156             case 'u':
   1157                 ValueToString (
   1158                     Item.Scratch,
   1159                     Item.Comma,
   1160                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
   1161                     );
   1162                 Item.Item.pw = Item.Scratch;
   1163                 break;
   1164 
   1165             case 'd':
   1166                 ValueToString (
   1167                     Item.Scratch,
   1168                     Item.Comma,
   1169                     Item.Long ? va_arg(ps->args, INT64) : va_arg(ps->args, INT32)
   1170                     );
   1171                 Item.Item.pw = Item.Scratch;
   1172                 break;
   1173 
   1174             case 'D':
   1175             {
   1176                 EFI_DEVICE_PATH *dp = va_arg(ps->args, EFI_DEVICE_PATH *);
   1177                 CHAR16 *dpstr = DevicePathToStr(dp);
   1178                 StrnCpy(Item.Scratch, dpstr, PRINT_ITEM_BUFFER_LEN);
   1179                 Item.Scratch[PRINT_ITEM_BUFFER_LEN-1] = L'\0';
   1180                 FreePool(dpstr);
   1181 
   1182                 Item.Item.pw = Item.Scratch;
   1183                 break;
   1184             }
   1185 
   1186 #ifndef __NetBSD__
   1187             case 'f':
   1188                 FloatToString (
   1189                     Item.Scratch,
   1190                     Item.Comma,
   1191                     va_arg(ps->args, double)
   1192                     );
   1193                 Item.Item.pw = Item.Scratch;
   1194                 break;
   1195 #endif
   1196 
   1197             case 't':
   1198                 TimeToString (Item.Scratch, va_arg(ps->args, EFI_TIME *));
   1199                 Item.Item.pw = Item.Scratch;
   1200                 break;
   1201 
   1202             case 'r':
   1203                 StatusToString (Item.Scratch, va_arg(ps->args, EFI_STATUS));
   1204                 Item.Item.pw = Item.Scratch;
   1205                 break;
   1206 
   1207             case 'n':
   1208                 PSETATTR(ps, ps->AttrNorm);
   1209                 break;
   1210 
   1211             case 'h':
   1212                 PSETATTR(ps, ps->AttrHighlight);
   1213                 break;
   1214 
   1215             case 'e':
   1216                 PSETATTR(ps, ps->AttrError);
   1217                 break;
   1218 
   1219             case 'N':
   1220                 Attr = ps->AttrNorm;
   1221                 break;
   1222 
   1223             case 'H':
   1224                 Attr = ps->AttrHighlight;
   1225                 break;
   1226 
   1227             case 'E':
   1228                 Attr = ps->AttrError;
   1229                 break;
   1230 
   1231             default:
   1232                 Item.Scratch[0] = '?';
   1233                 Item.Scratch[1] = 0;
   1234                 Item.Item.pw = Item.Scratch;
   1235                 break;
   1236             }
   1237 
   1238             // if we have an Item
   1239             if (Item.Item.pw) {
   1240                 PITEM (ps);
   1241                 break;
   1242             }
   1243 
   1244             // if we have an Attr set
   1245             if (Attr) {
   1246                 PSETATTR(ps, Attr);
   1247                 ps->RestoreAttr = 0;
   1248                 break;
   1249             }
   1250         }
   1251 
   1252         if (ps->RestoreAttr) {
   1253             PSETATTR(ps, ps->RestoreAttr);
   1254         }
   1255     }
   1256 
   1257     // Flush buffer
   1258     PFLUSH (ps);
   1259     return ps->Len;
   1260 }
   1261 
   1262 STATIC CHAR8 Hex[] = {'0','1','2','3','4','5','6','7',
   1263                       '8','9','A','B','C','D','E','F'};
   1264 
   1265 VOID
   1266 ValueToHex (
   1267     IN CHAR16   *Buffer,
   1268     IN UINT64   v
   1269     )
   1270 {
   1271     CHAR8           str[30], *p1;
   1272     CHAR16          *p2;
   1273 
   1274     if (!v) {
   1275         Buffer[0] = '0';
   1276         Buffer[1] = 0;
   1277         return ;
   1278     }
   1279 
   1280     p1 = str;
   1281     p2 = Buffer;
   1282 
   1283     while (v) {
   1284         // Without the cast, the MSVC compiler may insert a reference to __allmull
   1285         *(p1++) = Hex[(UINTN)(v & 0xf)];
   1286         v = RShiftU64 (v, 4);
   1287     }
   1288 
   1289     while (p1 != str) {
   1290         *(p2++) = *(--p1);
   1291     }
   1292     *p2 = 0;
   1293 }
   1294 
   1295 
   1296 VOID
   1297 ValueToString (
   1298     IN CHAR16   *Buffer,
   1299     IN BOOLEAN  Comma,
   1300     IN INT64    v
   1301     )
   1302 {
   1303     STATIC CHAR8 ca[] = {  3, 1, 2 };
   1304     CHAR8        str[40], *p1;
   1305     CHAR16       *p2;
   1306     UINTN        c, r;
   1307 
   1308     if (!v) {
   1309         Buffer[0] = '0';
   1310         Buffer[1] = 0;
   1311         return ;
   1312     }
   1313 
   1314     p1 = str;
   1315     p2 = Buffer;
   1316 
   1317     if (v < 0) {
   1318         *(p2++) = '-';
   1319         v = -v;
   1320     }
   1321 
   1322     while (v) {
   1323         v = (INT64)DivU64x32 ((UINT64)v, 10, &r);
   1324         *(p1++) = (CHAR8)r + '0';
   1325     }
   1326 
   1327     c = (Comma ? ca[(p1 - str) % 3] : 999) + 1;
   1328     while (p1 != str) {
   1329 
   1330         c -= 1;
   1331         if (!c) {
   1332             *(p2++) = ',';
   1333             c = 3;
   1334         }
   1335 
   1336         *(p2++) = *(--p1);
   1337     }
   1338     *p2 = 0;
   1339 }
   1340 
   1341 #ifndef __NetBSD__
   1342 VOID
   1343 FloatToString (
   1344     IN CHAR16   *Buffer,
   1345     IN BOOLEAN  Comma,
   1346     IN double   v
   1347     )
   1348 {
   1349     /*
   1350      * Integer part.
   1351      */
   1352     INTN i = (INTN)v;
   1353     ValueToString(Buffer, Comma, i);
   1354 
   1355 
   1356     /*
   1357      * Decimal point.
   1358      */
   1359     UINTN x = StrLen(Buffer);
   1360     Buffer[x] = L'.';
   1361     x++;
   1362 
   1363 
   1364     /*
   1365      * Keep fractional part.
   1366      */
   1367     float f = (float)(v - i);
   1368     if (f < 0) f = -f;
   1369 
   1370 
   1371     /*
   1372      * Leading fractional zeroes.
   1373      */
   1374     f *= 10.0;
   1375     while (   (f != 0)
   1376            && ((INTN)f == 0))
   1377     {
   1378       Buffer[x] = L'0';
   1379       x++;
   1380       f *= 10.0;
   1381     }
   1382 
   1383 
   1384     /*
   1385      * Fractional digits.
   1386      */
   1387     while ((float)(INTN)f != f)
   1388     {
   1389       f *= 10;
   1390     }
   1391     ValueToString(Buffer + x, FALSE, (INTN)f);
   1392     return;
   1393 }
   1394 #endif
   1395 
   1396 VOID
   1397 TimeToString (
   1398     OUT CHAR16      *Buffer,
   1399     IN EFI_TIME     *Time
   1400     )
   1401 {
   1402     UINTN       Hour, Year;
   1403     CHAR16      AmPm;
   1404 
   1405     AmPm = 'a';
   1406     Hour = Time->Hour;
   1407     if (Time->Hour == 0) {
   1408         Hour = 12;
   1409     } else if (Time->Hour >= 12) {
   1410         AmPm = 'p';
   1411         if (Time->Hour >= 13) {
   1412             Hour -= 12;
   1413         }
   1414     }
   1415 
   1416     Year = Time->Year % 100;
   1417 
   1418     // bugbug: for now just print it any old way
   1419     SPrint (Buffer, 0, L"%02d/%02d/%02d  %02d:%02d%c",
   1420         Time->Month,
   1421         Time->Day,
   1422         Year,
   1423         Hour,
   1424         Time->Minute,
   1425         AmPm
   1426         );
   1427 }
   1428 
   1429 
   1430 
   1431 
   1432 VOID
   1433 DumpHex (
   1434     IN UINTN        Indent,
   1435     IN UINTN        Offset,
   1436     IN UINTN        DataSize,
   1437     IN VOID         *UserData
   1438     )
   1439 {
   1440     CHAR8           *Data, Val[50], Str[20], c;
   1441     UINTN           Size, Index;
   1442 
   1443     UINTN           ScreenCount;
   1444     UINTN           TempColumn;
   1445     UINTN           ScreenSize;
   1446     CHAR16          ReturnStr[1];
   1447 
   1448 
   1449     uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &TempColumn, &ScreenSize);
   1450     ScreenCount = 0;
   1451     ScreenSize -= 2;
   1452 
   1453     Data = UserData;
   1454     while (DataSize) {
   1455         Size = 16;
   1456         if (Size > DataSize) {
   1457             Size = DataSize;
   1458         }
   1459 
   1460         for (Index=0; Index < Size; Index += 1) {
   1461             c = Data[Index];
   1462             Val[Index*3+0] = Hex[c>>4];
   1463             Val[Index*3+1] = Hex[c&0xF];
   1464             Val[Index*3+2] = (Index == 7)?'-':' ';
   1465             Str[Index] = (c < ' ' || c > 'z') ? '.' : c;
   1466         }
   1467 
   1468         Val[Index*3] = 0;
   1469         Str[Index] = 0;
   1470         Print (L"%*a%X: %-.48a *%a*\n", Indent, "", Offset, Val, Str);
   1471 
   1472         Data += Size;
   1473         Offset += Size;
   1474         DataSize -= Size;
   1475 
   1476         ScreenCount++;
   1477         if (ScreenCount >= ScreenSize && ScreenSize != 0) {
   1478             //
   1479             // If ScreenSize == 0 we have the console redirected so don't
   1480             //  block updates
   1481             //
   1482             ScreenCount = 0;
   1483             Print (L"Press Enter to continue :");
   1484             Input (L"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16));
   1485             Print (L"\n");
   1486         }
   1487 
   1488     }
   1489 }
   1490