xref: /DragonStub/lib/print.c (revision 93ef26559cc0c4bc17f26c93857594195c77b82d)
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     f       -   value as floating point
1004     c       -   Unicode char
1005     t       -   EFI time structure
1006     g       -   Pointer to GUID
1007     r       -   EFI status code (result code)
1008 
1009     N       -   Set output attribute to normal
1010     H       -   Set output attribute to highlight
1011     E       -   Set output attribute to error
1012     %       -   Print a %
1013 
1014 Arguments:
1015 
1016     SystemTable     - The system table
1017 
1018 Returns:
1019 
1020     Number of charactors written
1021 
1022 --*/
1023 {
1024     CHAR16          c;
1025     UINTN           Attr;
1026     PRINT_ITEM      Item;
1027     CHAR16          Buffer[PRINT_STRING_LEN];
1028 
1029     ps->Len = 0;
1030     ps->Buffer = Buffer;
1031     ps->Pos = Buffer;
1032     ps->End = Buffer + PRINT_STRING_LEN - 1;
1033     ps->Item = &Item;
1034 
1035     ps->fmt.Index = 0;
1036     while ((c = PGETC(&ps->fmt))) {
1037 
1038         if (c != '%') {
1039             PPUTC ( ps, c );
1040             continue;
1041         }
1042 
1043         // setup for new item
1044         Item.FieldWidth = (UINTN) -1;
1045         Item.Width = 0;
1046         Item.WidthParse = &Item.Width;
1047         Item.Pad = ' ';
1048         Item.PadBefore = TRUE;
1049         Item.Comma = FALSE;
1050         Item.Long = FALSE;
1051         Item.Item.Ascii = FALSE;
1052         Item.Item.pw = NULL;
1053         ps->RestoreAttr = 0;
1054         Attr = 0;
1055 
1056         while ((c = PGETC(&ps->fmt))) {
1057 
1058             switch (c) {
1059 
1060             case '%':
1061                 //
1062                 // %% -> %
1063                 //
1064                 Item.Item.pw = Item.Scratch;
1065                 Item.Item.pw[0] = '%';
1066                 Item.Item.pw[1] = 0;
1067                 break;
1068 
1069             case '0':
1070                 Item.Pad = '0';
1071                 break;
1072 
1073             case '-':
1074                 Item.PadBefore = FALSE;
1075                 break;
1076 
1077             case ',':
1078                 Item.Comma = TRUE;
1079                 break;
1080 
1081             case '.':
1082                 Item.WidthParse = &Item.FieldWidth;
1083                 break;
1084 
1085             case '*':
1086                 *Item.WidthParse = va_arg(ps->args, UINTN);
1087                 break;
1088 
1089             case '1':
1090             case '2':
1091             case '3':
1092             case '4':
1093             case '5':
1094             case '6':
1095             case '7':
1096             case '8':
1097             case '9':
1098                 *Item.WidthParse = 0;
1099                 do {
1100                     *Item.WidthParse = *Item.WidthParse * 10 + c - '0';
1101                     c = PGETC(&ps->fmt);
1102                 } while (c >= '0'  &&  c <= '9') ;
1103                 ps->fmt.Index -= 1;
1104                 break;
1105 
1106             case 'a':
1107                 Item.Item.pc = va_arg(ps->args, CHAR8 *);
1108                 Item.Item.Ascii = TRUE;
1109                 if (!Item.Item.pc) {
1110                     Item.Item.pc = (CHAR8 *)"(null)";
1111                 }
1112                 break;
1113 
1114             case 's':
1115                 Item.Item.pw = va_arg(ps->args, CHAR16 *);
1116                 if (!Item.Item.pw) {
1117                     Item.Item.pw = L"(null)";
1118                 }
1119                 break;
1120 
1121             case 'c':
1122                 Item.Item.pw = Item.Scratch;
1123                 Item.Item.pw[0] = (CHAR16) va_arg(ps->args, UINTN);
1124                 Item.Item.pw[1] = 0;
1125                 break;
1126 
1127             case 'l':
1128                 Item.Long = TRUE;
1129                 break;
1130 
1131             case 'X':
1132                 Item.Width = Item.Long ? 16 : 8;
1133                 Item.Pad = '0';
1134             case 'x':
1135                 Item.Item.pw = Item.Scratch;
1136                 ValueToHex (
1137                     Item.Item.pw,
1138                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
1139                     );
1140 
1141                 break;
1142 
1143 
1144             case 'g':
1145                 Item.Item.pw = Item.Scratch;
1146                 GuidToString (Item.Item.pw, va_arg(ps->args, EFI_GUID *));
1147                 break;
1148 
1149             case 'u':
1150                 Item.Item.pw = Item.Scratch;
1151                 ValueToString (
1152                     Item.Item.pw,
1153                     Item.Comma,
1154                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
1155                     );
1156                 break;
1157 
1158             case 'd':
1159                 Item.Item.pw = Item.Scratch;
1160                 ValueToString (
1161                     Item.Item.pw,
1162                     Item.Comma,
1163                     Item.Long ? va_arg(ps->args, INT64) : va_arg(ps->args, INT32)
1164                     );
1165                 break;
1166 
1167             case 'f':
1168                 Item.Item.pw = Item.Scratch;
1169                 FloatToString (
1170                     Item.Item.pw,
1171                     Item.Comma,
1172                     va_arg(ps->args, double)
1173                     );
1174                 break;
1175 
1176             case 't':
1177                 Item.Item.pw = Item.Scratch;
1178                 TimeToString (Item.Item.pw, va_arg(ps->args, EFI_TIME *));
1179                 break;
1180 
1181             case 'r':
1182                 Item.Item.pw = Item.Scratch;
1183                 StatusToString (Item.Item.pw, va_arg(ps->args, EFI_STATUS));
1184                 break;
1185 
1186             case 'n':
1187                 PSETATTR(ps, ps->AttrNorm);
1188                 break;
1189 
1190             case 'h':
1191                 PSETATTR(ps, ps->AttrHighlight);
1192                 break;
1193 
1194             case 'e':
1195                 PSETATTR(ps, ps->AttrError);
1196                 break;
1197 
1198             case 'N':
1199                 Attr = ps->AttrNorm;
1200                 break;
1201 
1202             case 'H':
1203                 Attr = ps->AttrHighlight;
1204                 break;
1205 
1206             case 'E':
1207                 Attr = ps->AttrError;
1208                 break;
1209 
1210             default:
1211                 Item.Item.pw = Item.Scratch;
1212                 Item.Item.pw[0] = '?';
1213                 Item.Item.pw[1] = 0;
1214                 break;
1215             }
1216 
1217             // if we have an Item
1218             if (Item.Item.pw) {
1219                 PITEM (ps);
1220                 break;
1221             }
1222 
1223             // if we have an Attr set
1224             if (Attr) {
1225                 PSETATTR(ps, Attr);
1226                 ps->RestoreAttr = 0;
1227                 break;
1228             }
1229         }
1230 
1231         if (ps->RestoreAttr) {
1232             PSETATTR(ps, ps->RestoreAttr);
1233         }
1234     }
1235 
1236     // Flush buffer
1237     PFLUSH (ps);
1238     return ps->Len;
1239 }
1240 
1241 STATIC CHAR8 Hex[] = {'0','1','2','3','4','5','6','7',
1242                       '8','9','A','B','C','D','E','F'};
1243 
1244 VOID
1245 ValueToHex (
1246     IN CHAR16   *Buffer,
1247     IN UINT64   v
1248     )
1249 {
1250     CHAR8           str[30], *p1;
1251     CHAR16          *p2;
1252 
1253     if (!v) {
1254         Buffer[0] = '0';
1255         Buffer[1] = 0;
1256         return ;
1257     }
1258 
1259     p1 = str;
1260     p2 = Buffer;
1261 
1262     while (v) {
1263         // Without the cast, the MSVC compiler may insert a reference to __allmull
1264         *(p1++) = Hex[(UINTN)(v & 0xf)];
1265         v = RShiftU64 (v, 4);
1266     }
1267 
1268     while (p1 != str) {
1269         *(p2++) = *(--p1);
1270     }
1271     *p2 = 0;
1272 }
1273 
1274 
1275 VOID
1276 ValueToString (
1277     IN CHAR16   *Buffer,
1278     IN BOOLEAN  Comma,
1279     IN INT64    v
1280     )
1281 {
1282     STATIC CHAR8 ca[] = {  3, 1, 2 };
1283     CHAR8        str[40], *p1;
1284     CHAR16       *p2;
1285     UINTN        c, r;
1286 
1287     if (!v) {
1288         Buffer[0] = '0';
1289         Buffer[1] = 0;
1290         return ;
1291     }
1292 
1293     p1 = str;
1294     p2 = Buffer;
1295 
1296     if (v < 0) {
1297         *(p2++) = '-';
1298         v = -v;
1299     }
1300 
1301     while (v) {
1302         v = (INT64)DivU64x32 ((UINT64)v, 10, &r);
1303         *(p1++) = (CHAR8)r + '0';
1304     }
1305 
1306     c = (Comma ? ca[(p1 - str) % 3] : 999) + 1;
1307     while (p1 != str) {
1308 
1309         c -= 1;
1310         if (!c) {
1311             *(p2++) = ',';
1312             c = 3;
1313         }
1314 
1315         *(p2++) = *(--p1);
1316     }
1317     *p2 = 0;
1318 }
1319 
1320 VOID
1321 FloatToString (
1322     IN CHAR16   *Buffer,
1323     IN BOOLEAN  Comma,
1324     IN double   v
1325     )
1326 {
1327     /*
1328      * Integer part.
1329      */
1330     INTN i = (INTN)v;
1331     ValueToString(Buffer, Comma, i);
1332 
1333 
1334     /*
1335      * Decimal point.
1336      */
1337     UINTN x = StrLen(Buffer);
1338     Buffer[x] = L'.';
1339     x++;
1340 
1341 
1342     /*
1343      * Keep fractional part.
1344      */
1345     float f = (float)(v - i);
1346     if (f < 0) f = -f;
1347 
1348 
1349     /*
1350      * Leading fractional zeroes.
1351      */
1352     f *= 10.0;
1353     while (   (f != 0)
1354            && ((INTN)f == 0))
1355     {
1356       Buffer[x] = L'0';
1357       x++;
1358       f *= 10.0;
1359     }
1360 
1361 
1362     /*
1363      * Fractional digits.
1364      */
1365     while ((float)(INTN)f != f)
1366     {
1367       f *= 10;
1368     }
1369     ValueToString(Buffer + x, FALSE, (INTN)f);
1370     return;
1371 }
1372 
1373 VOID
1374 TimeToString (
1375     OUT CHAR16      *Buffer,
1376     IN EFI_TIME     *Time
1377     )
1378 {
1379     UINTN       Hour, Year;
1380     CHAR16      AmPm;
1381 
1382     AmPm = 'a';
1383     Hour = Time->Hour;
1384     if (Time->Hour == 0) {
1385         Hour = 12;
1386     } else if (Time->Hour >= 12) {
1387         AmPm = 'p';
1388         if (Time->Hour >= 13) {
1389             Hour -= 12;
1390         }
1391     }
1392 
1393     Year = Time->Year % 100;
1394 
1395     // bugbug: for now just print it any old way
1396     SPrint (Buffer, 0, L"%02d/%02d/%02d  %02d:%02d%c",
1397         Time->Month,
1398         Time->Day,
1399         Year,
1400         Hour,
1401         Time->Minute,
1402         AmPm
1403         );
1404 }
1405 
1406 
1407 
1408 
1409 VOID
1410 DumpHex (
1411     IN UINTN        Indent,
1412     IN UINTN        Offset,
1413     IN UINTN        DataSize,
1414     IN VOID         *UserData
1415     )
1416 {
1417     CHAR8           *Data, Val[50], Str[20], c;
1418     UINTN           Size, Index;
1419 
1420     UINTN           ScreenCount;
1421     UINTN           TempColumn;
1422     UINTN           ScreenSize;
1423     CHAR16          ReturnStr[1];
1424 
1425 
1426     uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &TempColumn, &ScreenSize);
1427     ScreenCount = 0;
1428     ScreenSize -= 2;
1429 
1430     Data = UserData;
1431     while (DataSize) {
1432         Size = 16;
1433         if (Size > DataSize) {
1434             Size = DataSize;
1435         }
1436 
1437         for (Index=0; Index < Size; Index += 1) {
1438             c = Data[Index];
1439             Val[Index*3+0] = Hex[c>>4];
1440             Val[Index*3+1] = Hex[c&0xF];
1441             Val[Index*3+2] = (Index == 7)?'-':' ';
1442             Str[Index] = (c < ' ' || c > 'z') ? '.' : c;
1443         }
1444 
1445         Val[Index*3] = 0;
1446         Str[Index] = 0;
1447         Print (L"%*a%X: %-.48a *%a*\n", Indent, "", Offset, Val, Str);
1448 
1449         Data += Size;
1450         Offset += Size;
1451         DataSize -= Size;
1452 
1453         ScreenCount++;
1454         if (ScreenCount >= ScreenSize && ScreenSize != 0) {
1455             //
1456             // If ScreenSize == 0 we have the console redirected so don't
1457             //  block updates
1458             //
1459             ScreenCount = 0;
1460             Print (L"Press Enter to continue :");
1461             Input (L"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16));
1462             Print (L"\n");
1463         }
1464 
1465     }
1466 }
1467