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