Home | History | Annotate | Line # | Download | only in lib
print.c revision 1.1
      1 /*	$NetBSD: print.c,v 1.1 2014/04/01 16:16:06 jakllsch 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         CHAR16          *pw;
     61         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 CHAR16                           *fmt,
    125     IN 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 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         ps.SetAttr (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         ps.SetAttr (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-1] = 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 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 SPrint (
    427     OUT CHAR16  *Str,
    428     IN UINTN    StrSize,
    429     IN CHAR16   *fmt,
    430     ...
    431     )
    432 /*++
    433 
    434 Routine Description:
    435 
    436     Prints a formatted unicode string to a buffer
    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 Returns:
    448 
    449     String length returned in buffer
    450 
    451 --*/
    452 {
    453     POOL_PRINT          spc;
    454     va_list             args;
    455 
    456 
    457     va_start (args, fmt);
    458     spc.str    = Str;
    459     spc.maxlen = StrSize / sizeof(CHAR16) - 1;
    460     spc.len    = 0;
    461 
    462     _PoolCatPrint (fmt, args, &spc, _SPrint);
    463     va_end (args);
    464     return spc.len;
    465 }
    466 
    467 
    468 CHAR16 *
    469 PoolPrint (
    470     IN CHAR16           *fmt,
    471     ...
    472     )
    473 /*++
    474 
    475 Routine Description:
    476 
    477     Prints a formatted unicode string to allocated pool.  The caller
    478     must free the resulting buffer.
    479 
    480 Arguments:
    481 
    482     fmt         - The format string
    483 
    484 Returns:
    485 
    486     Allocated buffer with the formatted string printed in it.
    487     The caller must free the allocated buffer.   The buffer
    488     allocation is not packed.
    489 
    490 --*/
    491 {
    492     POOL_PRINT          spc;
    493     va_list             args;
    494 
    495     ZeroMem (&spc, sizeof(spc));
    496     va_start (args, fmt);
    497     _PoolCatPrint (fmt, args, &spc, _PoolPrint);
    498     va_end (args);
    499     return spc.str;
    500 }
    501 
    502 
    503 
    504 CHAR16 *
    505 CatPrint (
    506     IN OUT POOL_PRINT   *Str,
    507     IN CHAR16           *fmt,
    508     ...
    509     )
    510 /*++
    511 
    512 Routine Description:
    513 
    514     Concatenates a formatted unicode string to allocated pool.
    515     The caller must free the resulting buffer.
    516 
    517 Arguments:
    518 
    519     Str         - Tracks the allocated pool, size in use, and
    520                   amount of pool allocated.
    521 
    522     fmt         - The format string
    523 
    524 Returns:
    525 
    526     Allocated buffer with the formatted string printed in it.
    527     The caller must free the allocated buffer.   The buffer
    528     allocation is not packed.
    529 
    530 --*/
    531 {
    532     va_list             args;
    533 
    534     va_start (args, fmt);
    535     _PoolCatPrint (fmt, args, Str, _PoolPrint);
    536     va_end (args);
    537     return Str->str;
    538 }
    539 
    540 
    541 
    542 UINTN
    543 Print (
    544     IN CHAR16   *fmt,
    545     ...
    546     )
    547 /*++
    548 
    549 Routine Description:
    550 
    551     Prints a formatted unicode string to the default console
    552 
    553 Arguments:
    554 
    555     fmt         - Format string
    556 
    557 Returns:
    558 
    559     Length of string printed to the console
    560 
    561 --*/
    562 {
    563     va_list     args;
    564     UINTN       back;
    565 
    566     va_start (args, fmt);
    567     back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
    568     va_end (args);
    569     return back;
    570 }
    571 
    572 UINTN
    573 VPrint (
    574     IN CHAR16   *fmt,
    575     va_list     args
    576     )
    577 /*++
    578 
    579 Routine Description:
    580 
    581     Prints a formatted unicode string to the default console using a va_list
    582 
    583 Arguments:
    584 
    585     fmt         - Format string
    586     args        - va_list
    587 Returns:
    588 
    589     Length of string printed to the console
    590 
    591 --*/
    592 {
    593     return _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
    594 }
    595 
    596 
    597 UINTN
    598 PrintAt (
    599     IN UINTN     Column,
    600     IN UINTN     Row,
    601     IN CHAR16    *fmt,
    602     ...
    603     )
    604 /*++
    605 
    606 Routine Description:
    607 
    608     Prints a formatted unicode string to the default console, at
    609     the supplied cursor position
    610 
    611 Arguments:
    612 
    613     Column, Row - The cursor position to print the string at
    614 
    615     fmt         - Format string
    616 
    617 Returns:
    618 
    619     Length of string printed to the console
    620 
    621 --*/
    622 {
    623     va_list     args;
    624     UINTN       back;
    625 
    626     va_start (args, fmt);
    627     back = _IPrint (Column, Row, ST->ConOut, fmt, NULL, args);
    628     va_end (args);
    629     return back;
    630 }
    631 
    632 
    633 UINTN
    634 IPrint (
    635     IN SIMPLE_TEXT_OUTPUT_INTERFACE    *Out,
    636     IN CHAR16                          *fmt,
    637     ...
    638     )
    639 /*++
    640 
    641 Routine Description:
    642 
    643     Prints a formatted unicode string to the specified console
    644 
    645 Arguments:
    646 
    647     Out         - The console to print the string too
    648 
    649     fmt         - Format string
    650 
    651 Returns:
    652 
    653     Length of string printed to the console
    654 
    655 --*/
    656 {
    657     va_list     args;
    658     UINTN       back;
    659 
    660     va_start (args, fmt);
    661     back = _IPrint ((UINTN) -1, (UINTN) -1, Out, fmt, NULL, args);
    662     va_end (args);
    663     return back;
    664 }
    665 
    666 
    667 UINTN
    668 IPrintAt (
    669     IN SIMPLE_TEXT_OUTPUT_INTERFACE     *Out,
    670     IN UINTN                            Column,
    671     IN UINTN                            Row,
    672     IN CHAR16                           *fmt,
    673     ...
    674     )
    675 /*++
    676 
    677 Routine Description:
    678 
    679     Prints a formatted unicode string to the specified console, at
    680     the supplied cursor position
    681 
    682 Arguments:
    683 
    684     Out         - The console to print the string too
    685 
    686     Column, Row - The cursor position to print the string at
    687 
    688     fmt         - Format string
    689 
    690 Returns:
    691 
    692     Length of string printed to the console
    693 
    694 --*/
    695 {
    696     va_list     args;
    697     UINTN       back;
    698 
    699     va_start (args, fmt);
    700     back = _IPrint (Column, Row, ST->ConOut, fmt, NULL, args);
    701     va_end (args);
    702     return back;
    703 }
    704 
    705 
    706 UINTN
    707 _IPrint (
    708     IN UINTN                            Column,
    709     IN UINTN                            Row,
    710     IN SIMPLE_TEXT_OUTPUT_INTERFACE     *Out,
    711     IN CHAR16                           *fmt,
    712     IN CHAR8                            *fmta,
    713     IN va_list                          args
    714     )
    715 // Display string worker for: Print, PrintAt, IPrint, IPrintAt
    716 {
    717     PRINT_STATE     ps;
    718     UINTN            back;
    719 
    720     ZeroMem (&ps, sizeof(ps));
    721     ps.Context = Out;
    722     ps.Output  = (INTN EFIAPI (*)(VOID *, CHAR16 *)) Out->OutputString;
    723     ps.SetAttr = (INTN EFIAPI (*)(VOID *, UINTN))  Out->SetAttribute;
    724     ps.Attr = Out->Mode->Attribute;
    725 
    726     back = (ps.Attr >> 4) & 0xF;
    727     ps.AttrNorm = EFI_TEXT_ATTR(EFI_LIGHTGRAY, back);
    728     ps.AttrHighlight = EFI_TEXT_ATTR(EFI_WHITE, back);
    729     ps.AttrError = EFI_TEXT_ATTR(EFI_YELLOW, back);
    730 
    731     if (fmt) {
    732         ps.fmt.pw = fmt;
    733     } else {
    734         ps.fmt.Ascii = TRUE;
    735         ps.fmt.pc = fmta;
    736     }
    737 
    738     va_copy(ps.args, args);
    739 
    740     if (Column != (UINTN) -1) {
    741         uefi_call_wrapper(Out->SetCursorPosition, 3, Out, Column, Row);
    742     }
    743 
    744     back = _Print (&ps);
    745     va_end(ps.args);
    746     return back;
    747 }
    748 
    749 
    750 UINTN
    751 APrint (
    752     IN CHAR8    *fmt,
    753     ...
    754     )
    755 /*++
    756 
    757 Routine Description:
    758 
    759     For those whom really can't deal with unicode, a print
    760     function that takes an ascii format string
    761 
    762 Arguments:
    763 
    764     fmt         - ascii format string
    765 
    766 Returns:
    767 
    768     Length of string printed to the console
    769 
    770 --*/
    771 
    772 {
    773     va_list     args;
    774     UINTN       back;
    775 
    776     va_start (args, fmt);
    777     back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, NULL, fmt, args);
    778     va_end (args);
    779     return back;
    780 }
    781 
    782 
    783 STATIC
    784 VOID
    785 PFLUSH (
    786     IN OUT PRINT_STATE     *ps
    787     )
    788 {
    789     *ps->Pos = 0;
    790     if (IsLocalPrint(ps->Output))
    791 	ps->Output(ps->Context, ps->Buffer);
    792     else
    793     	uefi_call_wrapper(ps->Output, 2, ps->Context, ps->Buffer);
    794     ps->Pos = ps->Buffer;
    795 }
    796 
    797 STATIC
    798 VOID
    799 PSETATTR (
    800     IN OUT PRINT_STATE  *ps,
    801     IN UINTN             Attr
    802     )
    803 {
    804    PFLUSH (ps);
    805 
    806    ps->RestoreAttr = ps->Attr;
    807    if (ps->SetAttr) {
    808 	uefi_call_wrapper(ps->SetAttr, 2, ps->Context, Attr);
    809    }
    810 
    811    ps->Attr = Attr;
    812 }
    813 
    814 STATIC
    815 VOID
    816 PPUTC (
    817     IN OUT PRINT_STATE     *ps,
    818     IN CHAR16              c
    819     )
    820 {
    821     // if this is a newline, add a carraige return
    822     if (c == '\n') {
    823         PPUTC (ps, '\r');
    824     }
    825 
    826     *ps->Pos = c;
    827     ps->Pos += 1;
    828     ps->Len += 1;
    829 
    830     // if at the end of the buffer, flush it
    831     if (ps->Pos >= ps->End) {
    832         PFLUSH(ps);
    833     }
    834 }
    835 
    836 
    837 STATIC
    838 CHAR16
    839 PGETC (
    840     IN POINTER      *p
    841     )
    842 {
    843     CHAR16      c;
    844 
    845     c = p->Ascii ? p->pc[p->Index] : p->pw[p->Index];
    846     p->Index += 1;
    847 
    848     return  c;
    849 }
    850 
    851 
    852 STATIC
    853 VOID
    854 PITEM (
    855     IN OUT PRINT_STATE  *ps
    856     )
    857 {
    858     UINTN               Len, i;
    859     PRINT_ITEM          *Item;
    860     CHAR16              c;
    861 
    862     // Get the length of the item
    863     Item = ps->Item;
    864     Item->Item.Index = 0;
    865     while (Item->Item.Index < Item->FieldWidth) {
    866         c = PGETC(&Item->Item);
    867         if (!c) {
    868             Item->Item.Index -= 1;
    869             break;
    870         }
    871     }
    872     Len = Item->Item.Index;
    873 
    874     // if there is no item field width, use the items width
    875     if (Item->FieldWidth == (UINTN) -1) {
    876         Item->FieldWidth = Len;
    877     }
    878 
    879     // if item is larger then width, update width
    880     if (Len > Item->Width) {
    881         Item->Width = Len;
    882     }
    883 
    884 
    885     // if pad field before, add pad char
    886     if (Item->PadBefore) {
    887         for (i=Item->Width; i < Item->FieldWidth; i+=1) {
    888             PPUTC (ps, ' ');
    889         }
    890     }
    891 
    892     // pad item
    893     for (i=Len; i < Item->Width; i++) {
    894         PPUTC (ps, Item->Pad);
    895     }
    896 
    897     // add the item
    898     Item->Item.Index=0;
    899     while (Item->Item.Index < Len) {
    900         PPUTC (ps, PGETC(&Item->Item));
    901     }
    902 
    903     // If pad at the end, add pad char
    904     if (!Item->PadBefore) {
    905         for (i=Item->Width; i < Item->FieldWidth; i+=1) {
    906             PPUTC (ps, ' ');
    907         }
    908     }
    909 }
    910 
    911 
    912 STATIC
    913 UINTN
    914 _Print (
    915     IN PRINT_STATE     *ps
    916     )
    917 /*++
    918 
    919 Routine Description:
    920 
    921     %w.lF   -   w = width
    922                 l = field width
    923                 F = format of arg
    924 
    925   Args F:
    926     0       -   pad with zeros
    927     -       -   justify on left (default is on right)
    928     ,       -   add comma's to field
    929     *       -   width provided on stack
    930     n       -   Set output attribute to normal (for this field only)
    931     h       -   Set output attribute to highlight (for this field only)
    932     e       -   Set output attribute to error (for this field only)
    933     l       -   Value is 64 bits
    934 
    935     a       -   ascii string
    936     s       -   unicode string
    937     X       -   fixed 8 byte value in hex
    938     x       -   hex value
    939     d       -   value as decimal
    940     c       -   Unicode char
    941     t       -   EFI time structure
    942     g       -   Pointer to GUID
    943     r       -   EFI status code (result code)
    944 
    945     N       -   Set output attribute to normal
    946     H       -   Set output attribute to highlight
    947     E       -   Set output attribute to error
    948     %       -   Print a %
    949 
    950 Arguments:
    951 
    952     SystemTable     - The system table
    953 
    954 Returns:
    955 
    956     Number of charactors written
    957 
    958 --*/
    959 {
    960     CHAR16          c;
    961     UINTN           Attr;
    962     PRINT_ITEM      Item;
    963     CHAR16          Buffer[PRINT_STRING_LEN];
    964 
    965     ps->Len = 0;
    966     ps->Buffer = Buffer;
    967     ps->Pos = Buffer;
    968     ps->End = Buffer + PRINT_STRING_LEN - 1;
    969     ps->Item = &Item;
    970 
    971     ps->fmt.Index = 0;
    972     while ((c = PGETC(&ps->fmt))) {
    973 
    974         if (c != '%') {
    975             PPUTC ( ps, c );
    976             continue;
    977         }
    978 
    979         // setup for new item
    980         Item.FieldWidth = (UINTN) -1;
    981         Item.Width = 0;
    982         Item.WidthParse = &Item.Width;
    983         Item.Pad = ' ';
    984         Item.PadBefore = TRUE;
    985         Item.Comma = FALSE;
    986         Item.Long = FALSE;
    987         Item.Item.Ascii = FALSE;
    988         Item.Item.pw = NULL;
    989         ps->RestoreAttr = 0;
    990         Attr = 0;
    991 
    992         while ((c = PGETC(&ps->fmt))) {
    993 
    994             switch (c) {
    995 
    996             case '%':
    997                 //
    998                 // %% -> %
    999                 //
   1000                 Item.Item.pw = Item.Scratch;
   1001                 Item.Item.pw[0] = '%';
   1002                 Item.Item.pw[1] = 0;
   1003                 break;
   1004 
   1005             case '0':
   1006                 Item.Pad = '0';
   1007                 break;
   1008 
   1009             case '-':
   1010                 Item.PadBefore = FALSE;
   1011                 break;
   1012 
   1013             case ',':
   1014                 Item.Comma = TRUE;
   1015                 break;
   1016 
   1017             case '.':
   1018                 Item.WidthParse = &Item.FieldWidth;
   1019                 break;
   1020 
   1021             case '*':
   1022                 *Item.WidthParse = va_arg(ps->args, UINTN);
   1023                 break;
   1024 
   1025             case '1':
   1026             case '2':
   1027             case '3':
   1028             case '4':
   1029             case '5':
   1030             case '6':
   1031             case '7':
   1032             case '8':
   1033             case '9':
   1034                 *Item.WidthParse = 0;
   1035                 do {
   1036                     *Item.WidthParse = *Item.WidthParse * 10 + c - '0';
   1037                     c = PGETC(&ps->fmt);
   1038                 } while (c >= '0'  &&  c <= '9') ;
   1039                 ps->fmt.Index -= 1;
   1040                 break;
   1041 
   1042             case 'a':
   1043                 Item.Item.pc = va_arg(ps->args, CHAR8 *);
   1044                 Item.Item.Ascii = TRUE;
   1045                 if (!Item.Item.pc) {
   1046                     Item.Item.pc = (CHAR8 *)"(null)";
   1047                 }
   1048                 break;
   1049 
   1050             case 's':
   1051                 Item.Item.pw = va_arg(ps->args, CHAR16 *);
   1052                 if (!Item.Item.pw) {
   1053                     Item.Item.pw = L"(null)";
   1054                 }
   1055                 break;
   1056 
   1057             case 'c':
   1058                 Item.Item.pw = Item.Scratch;
   1059                 Item.Item.pw[0] = (CHAR16) va_arg(ps->args, UINTN);
   1060                 Item.Item.pw[1] = 0;
   1061                 break;
   1062 
   1063             case 'l':
   1064                 Item.Long = TRUE;
   1065                 break;
   1066 
   1067             case 'X':
   1068                 Item.Width = Item.Long ? 16 : 8;
   1069                 Item.Pad = '0';
   1070             case 'x':
   1071                 Item.Item.pw = Item.Scratch;
   1072                 ValueToHex (
   1073                     Item.Item.pw,
   1074                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
   1075                     );
   1076 
   1077                 break;
   1078 
   1079 
   1080             case 'g':
   1081                 Item.Item.pw = Item.Scratch;
   1082                 GuidToString (Item.Item.pw, va_arg(ps->args, EFI_GUID *));
   1083                 break;
   1084 
   1085             case 'd':
   1086                 Item.Item.pw = Item.Scratch;
   1087                 ValueToString (
   1088                     Item.Item.pw,
   1089                     Item.Comma,
   1090                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
   1091                     );
   1092                 break
   1093                     ;
   1094             case 't':
   1095                 Item.Item.pw = Item.Scratch;
   1096                 TimeToString (Item.Item.pw, va_arg(ps->args, EFI_TIME *));
   1097                 break;
   1098 
   1099             case 'r':
   1100                 Item.Item.pw = Item.Scratch;
   1101                 StatusToString (Item.Item.pw, va_arg(ps->args, EFI_STATUS));
   1102                 break;
   1103 
   1104             case 'n':
   1105                 PSETATTR(ps, ps->AttrNorm);
   1106                 break;
   1107 
   1108             case 'h':
   1109                 PSETATTR(ps, ps->AttrHighlight);
   1110                 break;
   1111 
   1112             case 'e':
   1113                 PSETATTR(ps, ps->AttrError);
   1114                 break;
   1115 
   1116             case 'N':
   1117                 Attr = ps->AttrNorm;
   1118                 break;
   1119 
   1120             case 'H':
   1121                 Attr = ps->AttrHighlight;
   1122                 break;
   1123 
   1124             case 'E':
   1125                 Attr = ps->AttrError;
   1126                 break;
   1127 
   1128             default:
   1129                 Item.Item.pw = Item.Scratch;
   1130                 Item.Item.pw[0] = '?';
   1131                 Item.Item.pw[1] = 0;
   1132                 break;
   1133             }
   1134 
   1135             // if we have an Item
   1136             if (Item.Item.pw) {
   1137                 PITEM (ps);
   1138                 break;
   1139             }
   1140 
   1141             // if we have an Attr set
   1142             if (Attr) {
   1143                 PSETATTR(ps, Attr);
   1144                 ps->RestoreAttr = 0;
   1145                 break;
   1146             }
   1147         }
   1148 
   1149         if (ps->RestoreAttr) {
   1150             PSETATTR(ps, ps->RestoreAttr);
   1151         }
   1152     }
   1153 
   1154     // Flush buffer
   1155     PFLUSH (ps);
   1156     return ps->Len;
   1157 }
   1158 
   1159 STATIC CHAR8 Hex[] = {'0','1','2','3','4','5','6','7',
   1160                       '8','9','A','B','C','D','E','F'};
   1161 
   1162 VOID
   1163 ValueToHex (
   1164     IN CHAR16   *Buffer,
   1165     IN UINT64   v
   1166     )
   1167 {
   1168     CHAR8           str[30], *p1;
   1169     CHAR16          *p2;
   1170 
   1171     if (!v) {
   1172         Buffer[0] = '0';
   1173         Buffer[1] = 0;
   1174         return ;
   1175     }
   1176 
   1177     p1 = str;
   1178     p2 = Buffer;
   1179 
   1180     while (v) {
   1181         *(p1++) = Hex[v & 0xf];
   1182         v = RShiftU64 (v, 4);
   1183     }
   1184 
   1185     while (p1 != str) {
   1186         *(p2++) = *(--p1);
   1187     }
   1188     *p2 = 0;
   1189 }
   1190 
   1191 
   1192 VOID
   1193 ValueToString (
   1194     IN CHAR16   *Buffer,
   1195     IN BOOLEAN  Comma,
   1196     IN INT64    v
   1197     )
   1198 {
   1199     STATIC CHAR8 ca[] = {  3, 1, 2 };
   1200     CHAR8        str[40], *p1;
   1201     CHAR16       *p2;
   1202     UINTN        c, r;
   1203 
   1204     if (!v) {
   1205         Buffer[0] = '0';
   1206         Buffer[1] = 0;
   1207         return ;
   1208     }
   1209 
   1210     p1 = str;
   1211     p2 = Buffer;
   1212 
   1213     if (v < 0) {
   1214         *(p2++) = '-';
   1215         v = -v;
   1216     }
   1217 
   1218     while (v) {
   1219         v = (INT64)DivU64x32 ((UINT64)v, 10, &r);
   1220         *(p1++) = (CHAR8)r + '0';
   1221     }
   1222 
   1223     c = (Comma ? ca[(p1 - str) % 3] : 999) + 1;
   1224     while (p1 != str) {
   1225 
   1226         c -= 1;
   1227         if (!c) {
   1228             *(p2++) = ',';
   1229             c = 3;
   1230         }
   1231 
   1232         *(p2++) = *(--p1);
   1233     }
   1234     *p2 = 0;
   1235 }
   1236 
   1237 VOID
   1238 TimeToString (
   1239     OUT CHAR16      *Buffer,
   1240     IN EFI_TIME     *Time
   1241     )
   1242 {
   1243     UINTN       Hour, Year;
   1244     CHAR16      AmPm;
   1245 
   1246     AmPm = 'a';
   1247     Hour = Time->Hour;
   1248     if (Time->Hour == 0) {
   1249         Hour = 12;
   1250     } else if (Time->Hour >= 12) {
   1251         AmPm = 'p';
   1252         if (Time->Hour >= 13) {
   1253             Hour -= 12;
   1254         }
   1255     }
   1256 
   1257     Year = Time->Year % 100;
   1258 
   1259     // bugbug: for now just print it any old way
   1260     SPrint (Buffer, 0, L"%02d/%02d/%02d  %02d:%02d%c",
   1261         Time->Month,
   1262         Time->Day,
   1263         Year,
   1264         Hour,
   1265         Time->Minute,
   1266         AmPm
   1267         );
   1268 }
   1269 
   1270 
   1271 
   1272 
   1273 VOID
   1274 DumpHex (
   1275     IN UINTN        Indent,
   1276     IN UINTN        Offset,
   1277     IN UINTN        DataSize,
   1278     IN VOID         *UserData
   1279     )
   1280 {
   1281     CHAR8           *Data, Val[50], Str[20], c;
   1282     UINTN           Size, Index;
   1283 
   1284     UINTN           ScreenCount;
   1285     UINTN           TempColumn;
   1286     UINTN           ScreenSize;
   1287     CHAR16          ReturnStr[1];
   1288 
   1289 
   1290     uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &TempColumn, &ScreenSize);
   1291     ScreenCount = 0;
   1292     ScreenSize -= 2;
   1293 
   1294     Data = UserData;
   1295     while (DataSize) {
   1296         Size = 16;
   1297         if (Size > DataSize) {
   1298             Size = DataSize;
   1299         }
   1300 
   1301         for (Index=0; Index < Size; Index += 1) {
   1302             c = Data[Index];
   1303             Val[Index*3+0] = Hex[c>>4];
   1304             Val[Index*3+1] = Hex[c&0xF];
   1305             Val[Index*3+2] = (Index == 7)?'-':' ';
   1306             Str[Index] = (c < ' ' || c > 'z') ? '.' : c;
   1307         }
   1308 
   1309         Val[Index*3] = 0;
   1310         Str[Index] = 0;
   1311         Print (L"%*a%X: %-.48a *%a*\n", Indent, "", Offset, Val, Str);
   1312 
   1313         Data += Size;
   1314         Offset += Size;
   1315         DataSize -= Size;
   1316 
   1317         ScreenCount++;
   1318         if (ScreenCount >= ScreenSize && ScreenSize != 0) {
   1319             //
   1320             // If ScreenSize == 0 we have the console redirected so don't
   1321             //  block updates
   1322             //
   1323             ScreenCount = 0;
   1324             Print (L"Press Enter to continue :");
   1325             Input (L"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16));
   1326             Print (L"\n");
   1327         }
   1328 
   1329     }
   1330 }
   1331