Subversion Repositories HelenOS

Rev

Rev 2726 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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