xref: /DragonStub/lib/print.c (revision 4f8b339facb471192e021fffd5db545a0fbddbc3)
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         CONST CHAR16    *pw;
59         CONST 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 CONST CHAR16                     *fmt,
123     IN CONST 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 CONST 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 UnicodeSPrint, 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 CONST CHAR16     *fmt,
404     IN va_list          args,
405     IN OUT POOL_PRINT   *spc,
406     IN INTN             (EFIAPI *Output)(VOID *context, CHAR16 *str)
407     )
408 // Dispatch function for UnicodeSPrint, 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 UnicodeVSPrint (
425     OUT CHAR16        *Str,
426     IN UINTN          StrSize,
427     IN CONST 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 UnicodeSPrint (
467     OUT CHAR16        *Str,
468     IN UINTN          StrSize,
469     IN CONST 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 = UnicodeVSPrint(Str, StrSize, fmt, args);
498     va_end (args);
499 
500     return len;
501 }
502 
503 CHAR16 *
504 VPoolPrint (
505     IN CONST 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 CONST 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 CONST 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 CONST 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 CONST 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 CONST 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 CONST 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 CONST 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 CONST CHAR16                     *fmt,
774     IN CONST 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 AsciiPrint (
814     IN CONST 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 UINTN
846 AsciiVSPrint (
847     OUT CHAR8         *Str,
848     IN UINTN          StrSize,
849     IN CONST CHAR8    *fmt,
850     va_list           args
851 )
852 /*++
853 
854 Routine Description:
855 
856     Prints a formatted ascii string to a buffer using a va_list
857 
858 Arguments:
859 
860     Str         - Output buffer to print the formatted string into
861 
862     StrSize     - Size of Str.  String is truncated to this size.
863                   A size of 0 means there is no limit
864 
865     fmt         - The format string
866 
867     args        - va_list
868 
869 
870 Returns:
871 
872     String length returned in buffer
873 
874 --*/
875 // Use UnicodeVSPrint() and convert back to ASCII
876 {
877     CHAR16 *UnicodeStr, *UnicodeFmt;
878     UINTN i, Len;
879 
880     UnicodeStr = AllocatePool(StrSize * sizeof(CHAR16));
881     if (!UnicodeStr)
882         return 0;
883 
884     UnicodeFmt = PoolPrint(L"%a", fmt);
885     if (!UnicodeFmt) {
886         FreePool(UnicodeStr);
887         return 0;
888     }
889 
890     Len = UnicodeVSPrint(UnicodeStr, StrSize, UnicodeFmt, args);
891     FreePool(UnicodeFmt);
892 
893     // The strings are ASCII so just do a plain Unicode conversion
894     for (i = 0; i < Len; i++)
895         Str[i] = (CHAR8)UnicodeStr[i];
896     Str[Len] = 0;
897     FreePool(UnicodeStr);
898 
899     return Len;
900 }
901 
902 
903 STATIC
904 VOID
905 PFLUSH (
906     IN OUT PRINT_STATE     *ps
907     )
908 {
909     *ps->Pos = 0;
910     if (IsLocalPrint(ps->Output))
911 	ps->Output(ps->Context, ps->Buffer);
912     else
913     	uefi_call_wrapper(ps->Output, 2, ps->Context, ps->Buffer);
914     ps->Pos = ps->Buffer;
915 }
916 
917 STATIC
918 VOID
919 PSETATTR (
920     IN OUT PRINT_STATE  *ps,
921     IN UINTN             Attr
922     )
923 {
924    PFLUSH (ps);
925 
926    ps->RestoreAttr = ps->Attr;
927    if (ps->SetAttr) {
928 	uefi_call_wrapper(ps->SetAttr, 2, ps->Context, Attr);
929    }
930 
931    ps->Attr = Attr;
932 }
933 
934 STATIC
935 VOID
936 PPUTC (
937     IN OUT PRINT_STATE     *ps,
938     IN CHAR16              c
939     )
940 {
941     // if this is a newline, add a carraige return
942     if (c == '\n') {
943         PPUTC (ps, '\r');
944     }
945 
946     *ps->Pos = c;
947     ps->Pos += 1;
948     ps->Len += 1;
949 
950     // if at the end of the buffer, flush it
951     if (ps->Pos >= ps->End) {
952         PFLUSH(ps);
953     }
954 }
955 
956 
957 STATIC
958 CHAR16
959 PGETC (
960     IN POINTER      *p
961     )
962 {
963     CHAR16      c;
964 
965     c = p->Ascii ? p->pc[p->Index] : p->pw[p->Index];
966     p->Index += 1;
967 
968     return  c;
969 }
970 
971 
972 STATIC
973 VOID
974 PITEM (
975     IN OUT PRINT_STATE  *ps
976     )
977 {
978     UINTN               Len, i;
979     PRINT_ITEM          *Item;
980     CHAR16              c;
981 
982     // Get the length of the item
983     Item = ps->Item;
984     Item->Item.Index = 0;
985     while (Item->Item.Index < Item->FieldWidth) {
986         c = PGETC(&Item->Item);
987         if (!c) {
988             Item->Item.Index -= 1;
989             break;
990         }
991     }
992     Len = Item->Item.Index;
993 
994     // if there is no item field width, use the items width
995     if (Item->FieldWidth == (UINTN) -1) {
996         Item->FieldWidth = Len;
997     }
998 
999     // if item is larger then width, update width
1000     if (Len > Item->Width) {
1001         Item->Width = Len;
1002     }
1003 
1004 
1005     // if pad field before, add pad char
1006     if (Item->PadBefore) {
1007         for (i=Item->Width; i < Item->FieldWidth; i+=1) {
1008             PPUTC (ps, ' ');
1009         }
1010     }
1011 
1012     // pad item
1013     for (i=Len; i < Item->Width; i++) {
1014         PPUTC (ps, Item->Pad);
1015     }
1016 
1017     // add the item
1018     Item->Item.Index=0;
1019     while (Item->Item.Index < Len) {
1020         PPUTC (ps, PGETC(&Item->Item));
1021     }
1022 
1023     // If pad at the end, add pad char
1024     if (!Item->PadBefore) {
1025         for (i=Item->Width; i < Item->FieldWidth; i+=1) {
1026             PPUTC (ps, ' ');
1027         }
1028     }
1029 }
1030 
1031 
1032 STATIC
1033 UINTN
1034 _Print (
1035     IN PRINT_STATE     *ps
1036     )
1037 /*++
1038 
1039 Routine Description:
1040 
1041     %w.lF   -   w = width
1042                 l = field width
1043                 F = format of arg
1044 
1045   Args F:
1046     0       -   pad with zeros
1047     -       -   justify on left (default is on right)
1048     ,       -   add comma's to field
1049     *       -   width provided on stack
1050     n       -   Set output attribute to normal (for this field only)
1051     h       -   Set output attribute to highlight (for this field only)
1052     e       -   Set output attribute to error (for this field only)
1053     l       -   Value is 64 bits
1054 
1055     a       -   ascii string
1056     s       -   unicode string
1057     X       -   fixed 8 byte value in hex
1058     x       -   hex value
1059     d       -   value as signed decimal
1060     u       -   value as unsigned decimal
1061     f       -   value as floating point
1062     c       -   Unicode char
1063     t       -   EFI time structure
1064     g       -   Pointer to GUID
1065     r       -   EFI status code (result code)
1066     D       -   pointer to Device Path with normal ending.
1067 
1068     N       -   Set output attribute to normal
1069     H       -   Set output attribute to highlight
1070     E       -   Set output attribute to error
1071     %       -   Print a %
1072 
1073 Arguments:
1074 
1075     SystemTable     - The system table
1076 
1077 Returns:
1078 
1079     Number of charactors written
1080 
1081 --*/
1082 {
1083     CHAR16          c;
1084     UINTN           Attr;
1085     PRINT_ITEM      Item;
1086     CHAR16          Buffer[PRINT_STRING_LEN];
1087 
1088     ps->Len = 0;
1089     ps->Buffer = Buffer;
1090     ps->Pos = Buffer;
1091     ps->End = Buffer + PRINT_STRING_LEN - 1;
1092     ps->Item = &Item;
1093 
1094     ps->fmt.Index = 0;
1095     while ((c = PGETC(&ps->fmt))) {
1096 
1097         if (c != '%') {
1098             PPUTC ( ps, c );
1099             continue;
1100         }
1101 
1102         // setup for new item
1103         Item.FieldWidth = (UINTN) -1;
1104         Item.Width = 0;
1105         Item.WidthParse = &Item.Width;
1106         Item.Pad = ' ';
1107         Item.PadBefore = TRUE;
1108         Item.Comma = FALSE;
1109         Item.Long = FALSE;
1110         Item.Item.Ascii = FALSE;
1111         Item.Item.pw = NULL;
1112         ps->RestoreAttr = 0;
1113         Attr = 0;
1114 
1115         while ((c = PGETC(&ps->fmt))) {
1116 
1117             switch (c) {
1118 
1119             case '%':
1120                 //
1121                 // %% -> %
1122                 //
1123                 Item.Scratch[0] = '%';
1124                 Item.Scratch[1] = 0;
1125                 Item.Item.pw = Item.Scratch;
1126                 break;
1127 
1128             case ',':
1129                 Item.Comma = TRUE;
1130                 break;
1131 
1132             case '-':
1133                 Item.PadBefore = FALSE;
1134                 break;
1135 
1136             case '*':
1137                 *Item.WidthParse = va_arg(ps->args, UINTN);
1138                 break;
1139 
1140             case '.':
1141                 Item.WidthParse = &Item.FieldWidth;
1142                 break;
1143 
1144             case '0':
1145                 Item.Pad = '0';
1146                 break;
1147 
1148             case '1':
1149             case '2':
1150             case '3':
1151             case '4':
1152             case '5':
1153             case '6':
1154             case '7':
1155             case '8':
1156             case '9':
1157                 *Item.WidthParse = 0;
1158                 do {
1159                     *Item.WidthParse = *Item.WidthParse * 10 + c - '0';
1160                     c = PGETC(&ps->fmt);
1161                 } while (c >= '0'  &&  c <= '9') ;
1162                 ps->fmt.Index -= 1;
1163                 break;
1164 
1165             case 'a':
1166                 Item.Item.pc = va_arg(ps->args, CHAR8 *);
1167                 Item.Item.Ascii = TRUE;
1168                 if (!Item.Item.pc) {
1169                     Item.Item.pc = (CHAR8 *)"(null)";
1170                 }
1171                 break;
1172 
1173             case 'c':
1174                 Item.Scratch[0] = (CHAR16) va_arg(ps->args, UINTN);
1175                 Item.Scratch[1] = 0;
1176                 Item.Item.pw = Item.Scratch;
1177                 break;
1178 
1179             case 'D':
1180             {
1181                 EFI_DEVICE_PATH *dp = va_arg(ps->args, EFI_DEVICE_PATH *);
1182                 CHAR16 *dpstr = DevicePathToStr(dp);
1183                 StrnCpy(Item.Scratch, dpstr, PRINT_ITEM_BUFFER_LEN);
1184                 Item.Scratch[PRINT_ITEM_BUFFER_LEN-1] = L'\0';
1185                 FreePool(dpstr);
1186 
1187                 Item.Item.pw = Item.Scratch;
1188                 break;
1189             }
1190 
1191             case 'd':
1192                 ValueToString (
1193                     Item.Scratch,
1194                     Item.Comma,
1195                     Item.Long ? va_arg(ps->args, INT64) : va_arg(ps->args, INT32)
1196                     );
1197                 Item.Item.pw = Item.Scratch;
1198                 break;
1199 
1200             case 'E':
1201                 Attr = ps->AttrError;
1202                 break;
1203 
1204             case 'e':
1205                 PSETATTR(ps, ps->AttrError);
1206                 break;
1207 
1208             case 'f':
1209                 FloatToString (
1210                     Item.Scratch,
1211                     Item.Comma,
1212                     va_arg(ps->args, double)
1213                     );
1214                 Item.Item.pw = Item.Scratch;
1215                 break;
1216 
1217             case 'g':
1218                 GuidToString (Item.Scratch, va_arg(ps->args, EFI_GUID *));
1219                 Item.Item.pw = Item.Scratch;
1220                 break;
1221 
1222             case 'H':
1223                 Attr = ps->AttrHighlight;
1224                 break;
1225 
1226             case 'h':
1227                 PSETATTR(ps, ps->AttrHighlight);
1228                 break;
1229 
1230             case 'l':
1231                 Item.Long = TRUE;
1232                 break;
1233 
1234             case 'N':
1235                 Attr = ps->AttrNorm;
1236                 break;
1237 
1238             case 'n':
1239                 PSETATTR(ps, ps->AttrNorm);
1240                 break;
1241 
1242             case 'r':
1243                 StatusToString (Item.Scratch, va_arg(ps->args, EFI_STATUS));
1244                 Item.Item.pw = Item.Scratch;
1245                 break;
1246 
1247             case 's':
1248                 Item.Item.pw = va_arg(ps->args, CHAR16 *);
1249                 if (!Item.Item.pw) {
1250                     Item.Item.pw = L"(null)";
1251                 }
1252                 break;
1253 
1254             case 't':
1255                 TimeToString (Item.Scratch, va_arg(ps->args, EFI_TIME *));
1256                 Item.Item.pw = Item.Scratch;
1257                 break;
1258 
1259             case 'u':
1260                 ValueToString (
1261                     Item.Scratch,
1262                     Item.Comma,
1263                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
1264                     );
1265                 Item.Item.pw = Item.Scratch;
1266                 break;
1267 
1268             case 'X':
1269                 Item.Width = Item.Long ? 16 : 8;
1270                 Item.Pad = '0';
1271 #if __GNUC__ >= 7
1272 		__attribute__ ((fallthrough));
1273 #endif
1274             case 'x':
1275                 ValueToHex (
1276                     Item.Scratch,
1277                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
1278                     );
1279                 Item.Item.pw = Item.Scratch;
1280                 break;
1281 
1282             default:
1283                 Item.Scratch[0] = '?';
1284                 Item.Scratch[1] = 0;
1285                 Item.Item.pw = Item.Scratch;
1286                 break;
1287             }
1288 
1289             // if we have an Item
1290             if (Item.Item.pw) {
1291                 PITEM (ps);
1292                 break;
1293             }
1294 
1295             // if we have an Attr set
1296             if (Attr) {
1297                 PSETATTR(ps, Attr);
1298                 ps->RestoreAttr = 0;
1299                 break;
1300             }
1301         }
1302 
1303         if (ps->RestoreAttr) {
1304             PSETATTR(ps, ps->RestoreAttr);
1305         }
1306     }
1307 
1308     // Flush buffer
1309     PFLUSH (ps);
1310     return ps->Len;
1311 }
1312 
1313 STATIC CHAR8 Hex[] = {'0','1','2','3','4','5','6','7',
1314                       '8','9','A','B','C','D','E','F'};
1315 
1316 VOID
1317 ValueToHex (
1318     IN CHAR16   *Buffer,
1319     IN UINT64   v
1320     )
1321 {
1322     CHAR8           str[30], *p1;
1323     CHAR16          *p2;
1324 
1325     if (!v) {
1326         Buffer[0] = '0';
1327         Buffer[1] = 0;
1328         return ;
1329     }
1330 
1331     p1 = str;
1332     p2 = Buffer;
1333 
1334     while (v) {
1335         // Without the cast, the MSVC compiler may insert a reference to __allmull
1336         *(p1++) = Hex[(UINTN)(v & 0xf)];
1337         v = RShiftU64 (v, 4);
1338     }
1339 
1340     while (p1 != str) {
1341         *(p2++) = *(--p1);
1342     }
1343     *p2 = 0;
1344 }
1345 
1346 
1347 VOID
1348 ValueToString (
1349     IN CHAR16   *Buffer,
1350     IN BOOLEAN  Comma,
1351     IN INT64    v
1352     )
1353 {
1354     STATIC CHAR8 ca[] = {  3, 1, 2 };
1355     CHAR8        str[40], *p1;
1356     CHAR16       *p2;
1357     UINTN        c, r;
1358 
1359     if (!v) {
1360         Buffer[0] = '0';
1361         Buffer[1] = 0;
1362         return ;
1363     }
1364 
1365     p1 = str;
1366     p2 = Buffer;
1367 
1368     if (v < 0) {
1369         *(p2++) = '-';
1370         v = -v;
1371     }
1372 
1373     while (v) {
1374         v = (INT64)DivU64x32 ((UINT64)v, 10, &r);
1375         *(p1++) = (CHAR8)r + '0';
1376     }
1377 
1378     c = (UINTN) (Comma ? ca[(p1 - str) % 3] : 999) + 1;
1379     while (p1 != str) {
1380 
1381         c -= 1;
1382         if (!c) {
1383             *(p2++) = ',';
1384             c = 3;
1385         }
1386 
1387         *(p2++) = *(--p1);
1388     }
1389     *p2 = 0;
1390 }
1391 
1392 VOID
1393 FloatToString (
1394     IN CHAR16   *Buffer,
1395     IN BOOLEAN  Comma,
1396     IN double   v
1397     )
1398 {
1399     /*
1400      * Integer part.
1401      */
1402     INTN i = (INTN)v;
1403     ValueToString(Buffer, Comma, i);
1404 
1405 
1406     /*
1407      * Decimal point.
1408      */
1409     UINTN x = StrLen(Buffer);
1410     Buffer[x] = L'.';
1411     x++;
1412 
1413 
1414     /*
1415      * Keep fractional part.
1416      */
1417     float f = (float)(v - i);
1418     if (f < 0) f = -f;
1419 
1420 
1421     /*
1422      * Leading fractional zeroes.
1423      */
1424     f *= 10.0;
1425     while (   (f != 0)
1426            && ((INTN)f == 0))
1427     {
1428       Buffer[x] = L'0';
1429       x++;
1430       f *= 10.0;
1431     }
1432 
1433 
1434     /*
1435      * Fractional digits.
1436      */
1437     while ((float)(INTN)f != f)
1438     {
1439       f *= 10;
1440     }
1441     ValueToString(Buffer + x, FALSE, (INTN)f);
1442     return;
1443 }
1444 
1445 VOID
1446 TimeToString (
1447     OUT CHAR16      *Buffer,
1448     IN EFI_TIME     *Time
1449     )
1450 {
1451     UINTN       Hour, Year;
1452     CHAR16      AmPm;
1453 
1454     AmPm = 'a';
1455     Hour = Time->Hour;
1456     if (Time->Hour == 0) {
1457         Hour = 12;
1458     } else if (Time->Hour >= 12) {
1459         AmPm = 'p';
1460         if (Time->Hour >= 13) {
1461             Hour -= 12;
1462         }
1463     }
1464 
1465     Year = Time->Year % 100;
1466 
1467     // bugbug: for now just print it any old way
1468     UnicodeSPrint (Buffer, 0, L"%02d/%02d/%02d  %02d:%02d%c",
1469         Time->Month,
1470         Time->Day,
1471         Year,
1472         Hour,
1473         Time->Minute,
1474         AmPm
1475         );
1476 }
1477 
1478 
1479 
1480 
1481 VOID
1482 DumpHex (
1483     IN UINTN        Indent,
1484     IN UINTN        Offset,
1485     IN UINTN        DataSize,
1486     IN VOID         *UserData
1487     )
1488 {
1489     CHAR8           *Data, Val[50], Str[20], c;
1490     UINTN           Size, Index;
1491 
1492     UINTN           ScreenCount;
1493     UINTN           TempColumn;
1494     UINTN           ScreenSize;
1495     CHAR16          ReturnStr[1];
1496 
1497 
1498     uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &TempColumn, &ScreenSize);
1499     ScreenCount = 0;
1500     ScreenSize -= 2;
1501 
1502     Data = UserData;
1503     while (DataSize) {
1504         Size = 16;
1505         if (Size > DataSize) {
1506             Size = DataSize;
1507         }
1508 
1509         for (Index=0; Index < Size; Index += 1) {
1510             c = Data[Index];
1511             Val[Index*3+0] = Hex[c>>4];
1512             Val[Index*3+1] = Hex[c&0xF];
1513             Val[Index*3+2] = (Index == 7)?'-':' ';
1514             Str[Index] = (c < ' ' || c > 'z') ? '.' : c;
1515         }
1516 
1517         Val[Index*3] = 0;
1518         Str[Index] = 0;
1519         Print (L"%*a%X: %-.48a *%a*\n", Indent, "", Offset, Val, Str);
1520 
1521         Data += Size;
1522         Offset += Size;
1523         DataSize -= Size;
1524 
1525         ScreenCount++;
1526         if (ScreenCount >= ScreenSize && ScreenSize != 0) {
1527             //
1528             // If ScreenSize == 0 we have the console redirected so don't
1529             //  block updates
1530             //
1531             ScreenCount = 0;
1532             Print (L"Press Enter to continue :");
1533             Input (L"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16));
1534             Print (L"\n");
1535         }
1536 
1537     }
1538 }
1539