xref: /netbsd-src/sys/external/bsd/gnu-efi/dist/lib/print.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: print.c,v 1.1.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