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