Imported Upstream version 3.0
[platform/upstream/gnu-efi.git] / lib / print.c
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         ps.SetAttr (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         ps.SetAttr (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-1] = 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 SPrint (
425     OUT CHAR16  *Str,
426     IN UINTN    StrSize,
427     IN CHAR16   *fmt,
428     ...
429     )
430 /*++
431
432 Routine Description:
433
434     Prints a formatted unicode string to a buffer
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 Returns:
446
447     String length returned in buffer
448
449 --*/
450 {
451     POOL_PRINT          spc;
452     va_list             args;
453
454
455     va_start (args, fmt);
456     spc.str    = Str;
457     spc.maxlen = StrSize / sizeof(CHAR16) - 1;
458     spc.len    = 0;
459
460     _PoolCatPrint (fmt, args, &spc, _SPrint);
461     va_end (args);
462     return spc.len;
463 }
464
465
466 CHAR16 *
467 PoolPrint (
468     IN CHAR16           *fmt,
469     ...
470     )
471 /*++
472
473 Routine Description:
474
475     Prints a formatted unicode string to allocated pool.  The caller
476     must free the resulting buffer.
477
478 Arguments:
479
480     fmt         - The format string
481
482 Returns:
483
484     Allocated buffer with the formatted string printed in it.  
485     The caller must free the allocated buffer.   The buffer
486     allocation is not packed.
487
488 --*/
489 {
490     POOL_PRINT          spc;
491     va_list             args;
492
493     ZeroMem (&spc, sizeof(spc));
494     va_start (args, fmt);
495     _PoolCatPrint (fmt, args, &spc, _PoolPrint);
496     va_end (args);
497     return spc.str;
498 }
499
500
501
502 CHAR16 *
503 CatPrint (
504     IN OUT POOL_PRINT   *Str,
505     IN CHAR16           *fmt,
506     ...
507     )
508 /*++
509
510 Routine Description:
511
512     Concatenates a formatted unicode string to allocated pool.  
513     The caller must free the resulting buffer.
514
515 Arguments:
516
517     Str         - Tracks the allocated pool, size in use, and 
518                   amount of pool allocated.
519
520     fmt         - The format string
521
522 Returns:
523
524     Allocated buffer with the formatted string printed in it.  
525     The caller must free the allocated buffer.   The buffer
526     allocation is not packed.
527
528 --*/
529 {
530     va_list             args;
531
532     va_start (args, fmt);
533     _PoolCatPrint (fmt, args, Str, _PoolPrint);
534     va_end (args);
535     return Str->str;
536 }
537
538
539
540 UINTN
541 Print (
542     IN CHAR16   *fmt,
543     ...
544     )
545 /*++
546
547 Routine Description:
548
549     Prints a formatted unicode string to the default console
550
551 Arguments:
552
553     fmt         - Format string
554
555 Returns:
556
557     Length of string printed to the console
558
559 --*/
560 {
561     va_list     args;
562     UINTN       back;
563
564     va_start (args, fmt);
565     back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
566     va_end (args);
567     return back;
568 }
569
570 UINTN
571 VPrint (
572     IN CHAR16   *fmt,
573     va_list     args
574     )
575 /*++
576
577 Routine Description:
578
579     Prints a formatted unicode string to the default console using a va_list
580
581 Arguments:
582
583     fmt         - Format string
584     args        - va_list
585 Returns:
586
587     Length of string printed to the console
588
589 --*/
590 {
591     return _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
592 }
593
594
595 UINTN
596 PrintAt (
597     IN UINTN     Column,
598     IN UINTN     Row,
599     IN CHAR16    *fmt,
600     ...
601     )
602 /*++
603
604 Routine Description:
605
606     Prints a formatted unicode string to the default console, at 
607     the supplied cursor position
608
609 Arguments:
610
611     Column, Row - The cursor position to print the string at
612
613     fmt         - Format string
614
615 Returns:
616
617     Length of string printed to the console
618
619 --*/
620 {
621     va_list     args;
622     UINTN       back;
623
624     va_start (args, fmt);
625     back = _IPrint (Column, Row, ST->ConOut, fmt, NULL, args);
626     va_end (args);
627     return back;
628 }
629
630
631 UINTN
632 IPrint (
633     IN SIMPLE_TEXT_OUTPUT_INTERFACE    *Out,
634     IN CHAR16                          *fmt,
635     ...
636     )
637 /*++
638
639 Routine Description:
640
641     Prints a formatted unicode string to the specified console
642
643 Arguments:
644
645     Out         - The console to print the string too
646
647     fmt         - Format string
648
649 Returns:
650
651     Length of string printed to the console
652
653 --*/
654 {
655     va_list     args;
656     UINTN       back;
657
658     va_start (args, fmt);
659     back = _IPrint ((UINTN) -1, (UINTN) -1, Out, fmt, NULL, args);
660     va_end (args);
661     return back;
662 }
663
664
665 UINTN
666 IPrintAt (
667     IN SIMPLE_TEXT_OUTPUT_INTERFACE     *Out,
668     IN UINTN                            Column,
669     IN UINTN                            Row,
670     IN CHAR16                           *fmt,
671     ...
672     )
673 /*++
674
675 Routine Description:
676
677     Prints a formatted unicode string to the specified console, at
678     the supplied cursor position
679
680 Arguments:
681
682     Out         - The console to print the string too
683
684     Column, Row - The cursor position to print the string at
685
686     fmt         - Format string
687
688 Returns:
689
690     Length of string printed to the console
691
692 --*/
693 {
694     va_list     args;
695     UINTN       back;
696
697     va_start (args, fmt);
698     back = _IPrint (Column, Row, ST->ConOut, fmt, NULL, args);
699     va_end (args);
700     return back;
701 }
702
703
704 UINTN
705 _IPrint (
706     IN UINTN                            Column,
707     IN UINTN                            Row,
708     IN SIMPLE_TEXT_OUTPUT_INTERFACE     *Out,
709     IN CHAR16                           *fmt,
710     IN CHAR8                            *fmta,
711     IN va_list                          args
712     )
713 // Display string worker for: Print, PrintAt, IPrint, IPrintAt
714 {
715     PRINT_STATE     ps;
716     UINTN            back;
717
718     ZeroMem (&ps, sizeof(ps));
719     ps.Context = Out;
720     ps.Output  = (INTN EFIAPI (*)(VOID *, CHAR16 *)) Out->OutputString;
721     ps.SetAttr = (INTN EFIAPI (*)(VOID *, UINTN))  Out->SetAttribute;
722     ps.Attr = Out->Mode->Attribute;
723    
724     back = (ps.Attr >> 4) & 0xF;
725     ps.AttrNorm = EFI_TEXT_ATTR(EFI_LIGHTGRAY, back);
726     ps.AttrHighlight = EFI_TEXT_ATTR(EFI_WHITE, back);
727     ps.AttrError = EFI_TEXT_ATTR(EFI_YELLOW, back);
728
729     if (fmt) {
730         ps.fmt.pw = fmt;
731     } else {
732         ps.fmt.Ascii = TRUE;
733         ps.fmt.pc = fmta;
734     }
735
736     va_copy(ps.args, args);
737
738     if (Column != (UINTN) -1) {
739         uefi_call_wrapper(Out->SetCursorPosition, 3, Out, Column, Row);
740     }
741
742     back = _Print (&ps);
743     va_end(ps.args);
744     return back;
745 }
746
747
748 UINTN
749 APrint (
750     IN CHAR8    *fmt,
751     ...
752     )
753 /*++
754
755 Routine Description:
756
757     For those whom really can't deal with unicode, a print
758     function that takes an ascii format string
759
760 Arguments:
761
762     fmt         - ascii format string
763
764 Returns:
765
766     Length of string printed to the console
767
768 --*/
769
770 {
771     va_list     args;
772     UINTN       back;
773
774     va_start (args, fmt);
775     back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, NULL, fmt, args);
776     va_end (args);
777     return back;
778 }
779
780
781 STATIC
782 VOID
783 PFLUSH (
784     IN OUT PRINT_STATE     *ps
785     )
786 {
787     *ps->Pos = 0;
788     if (IsLocalPrint(ps->Output))
789         ps->Output(ps->Context, ps->Buffer);            
790     else
791         uefi_call_wrapper(ps->Output, 2, ps->Context, ps->Buffer);
792     ps->Pos = ps->Buffer;
793 }
794
795 STATIC
796 VOID
797 PSETATTR (
798     IN OUT PRINT_STATE  *ps,
799     IN UINTN             Attr
800     )
801 {
802    PFLUSH (ps);
803
804    ps->RestoreAttr = ps->Attr;
805    if (ps->SetAttr) {
806         uefi_call_wrapper(ps->SetAttr, 2, ps->Context, Attr);
807    }
808
809    ps->Attr = Attr;
810 }   
811
812 STATIC
813 VOID
814 PPUTC (
815     IN OUT PRINT_STATE     *ps,
816     IN CHAR16              c
817     )
818 {
819     // if this is a newline, add a carraige return
820     if (c == '\n') {
821         PPUTC (ps, '\r');
822     }
823
824     *ps->Pos = c;
825     ps->Pos += 1;
826     ps->Len += 1;
827
828     // if at the end of the buffer, flush it
829     if (ps->Pos >= ps->End) {
830         PFLUSH(ps);
831     }
832 }
833
834
835 STATIC
836 CHAR16
837 PGETC (
838     IN POINTER      *p
839     )
840 {
841     CHAR16      c;
842
843     c = p->Ascii ? p->pc[p->Index] : p->pw[p->Index];
844     p->Index += 1;
845
846     return  c;
847 }
848
849
850 STATIC
851 VOID
852 PITEM (
853     IN OUT PRINT_STATE  *ps
854     )
855 {
856     UINTN               Len, i;
857     PRINT_ITEM          *Item;
858     CHAR16              c;
859
860     // Get the length of the item
861     Item = ps->Item;
862     Item->Item.Index = 0;
863     while (Item->Item.Index < Item->FieldWidth) {
864         c = PGETC(&Item->Item);
865         if (!c) {
866             Item->Item.Index -= 1;
867             break;
868         }
869     }
870     Len = Item->Item.Index;
871
872     // if there is no item field width, use the items width
873     if (Item->FieldWidth == (UINTN) -1) {
874         Item->FieldWidth = Len;
875     }
876
877     // if item is larger then width, update width
878     if (Len > Item->Width) {
879         Item->Width = Len;
880     }
881
882
883     // if pad field before, add pad char
884     if (Item->PadBefore) {
885         for (i=Item->Width; i < Item->FieldWidth; i+=1) {
886             PPUTC (ps, ' ');
887         }
888     }
889
890     // pad item
891     for (i=Len; i < Item->Width; i++) {
892         PPUTC (ps, Item->Pad);
893     }
894
895     // add the item
896     Item->Item.Index=0; 
897     while (Item->Item.Index < Len) {
898         PPUTC (ps, PGETC(&Item->Item));
899     }
900
901     // If pad at the end, add pad char
902     if (!Item->PadBefore) {
903         for (i=Item->Width; i < Item->FieldWidth; i+=1) {
904             PPUTC (ps, ' ');
905         }
906     }
907 }
908
909
910 STATIC
911 UINTN
912 _Print (
913     IN PRINT_STATE     *ps
914     )
915 /*++
916
917 Routine Description:
918
919     %w.lF   -   w = width
920                 l = field width
921                 F = format of arg
922
923   Args F:
924     0       -   pad with zeros
925     -       -   justify on left (default is on right)
926     ,       -   add comma's to field    
927     *       -   width provided on stack
928     n       -   Set output attribute to normal (for this field only)
929     h       -   Set output attribute to highlight (for this field only)
930     e       -   Set output attribute to error (for this field only)
931     l       -   Value is 64 bits
932
933     a       -   ascii string
934     s       -   unicode string
935     X       -   fixed 8 byte value in hex
936     x       -   hex value
937     d       -   value as decimal    
938     c       -   Unicode char
939     t       -   EFI time structure
940     g       -   Pointer to GUID
941     r       -   EFI status code (result code)
942
943     N       -   Set output attribute to normal
944     H       -   Set output attribute to highlight
945     E       -   Set output attribute to error
946     %       -   Print a %
947     
948 Arguments:
949
950     SystemTable     - The system table
951
952 Returns:
953
954     Number of charactors written   
955
956 --*/
957 {
958     CHAR16          c;
959     UINTN           Attr;
960     PRINT_ITEM      Item;
961     CHAR16          Buffer[PRINT_STRING_LEN];
962
963     ps->Len = 0;
964     ps->Buffer = Buffer;
965     ps->Pos = Buffer;
966     ps->End = Buffer + PRINT_STRING_LEN - 1;
967     ps->Item = &Item;
968
969     ps->fmt.Index = 0;
970     while ((c = PGETC(&ps->fmt))) {
971
972         if (c != '%') {
973             PPUTC ( ps, c );
974             continue;   
975         }
976
977         // setup for new item
978         Item.FieldWidth = (UINTN) -1;
979         Item.Width = 0;
980         Item.WidthParse = &Item.Width;
981         Item.Pad = ' ';
982         Item.PadBefore = TRUE;
983         Item.Comma = FALSE;
984         Item.Long = FALSE;
985         Item.Item.Ascii = FALSE;
986         Item.Item.pw = NULL;
987         ps->RestoreAttr = 0;
988         Attr = 0;
989
990         while ((c = PGETC(&ps->fmt))) {
991
992             switch (c) {
993             
994             case '%':
995                 //
996                 // %% -> %
997                 //
998                 Item.Item.pw = Item.Scratch;
999                 Item.Item.pw[0] = '%';  
1000                 Item.Item.pw[1] = 0;
1001                 break;
1002
1003             case '0':
1004                 Item.Pad = '0';
1005                 break;
1006
1007             case '-':
1008                 Item.PadBefore = FALSE;
1009                 break;
1010
1011             case ',':
1012                 Item.Comma = TRUE;
1013                 break;
1014
1015             case '.':
1016                 Item.WidthParse = &Item.FieldWidth;
1017                 break;
1018
1019             case '*':
1020                 *Item.WidthParse = va_arg(ps->args, UINTN);
1021                 break;
1022             
1023             case '1':
1024             case '2':
1025             case '3':
1026             case '4':
1027             case '5':
1028             case '6':
1029             case '7':
1030             case '8':
1031             case '9':
1032                 *Item.WidthParse = 0;
1033                 do {
1034                     *Item.WidthParse = *Item.WidthParse * 10 + c - '0';
1035                     c = PGETC(&ps->fmt);
1036                 } while (c >= '0'  &&  c <= '9') ;
1037                 ps->fmt.Index -= 1;
1038                 break;
1039
1040             case 'a':
1041                 Item.Item.pc = va_arg(ps->args, CHAR8 *);
1042                 Item.Item.Ascii = TRUE;
1043                 if (!Item.Item.pc) {
1044                     Item.Item.pc = (CHAR8 *)"(null)";
1045                 }
1046                 break;
1047
1048             case 's':
1049                 Item.Item.pw = va_arg(ps->args, CHAR16 *);
1050                 if (!Item.Item.pw) {
1051                     Item.Item.pw = L"(null)";
1052                 }
1053                 break;
1054
1055             case 'c':
1056                 Item.Item.pw = Item.Scratch;
1057                 Item.Item.pw[0] = (CHAR16) va_arg(ps->args, UINTN);  
1058                 Item.Item.pw[1] = 0;
1059                 break;
1060
1061             case 'l':
1062                 Item.Long = TRUE;
1063                 break;
1064
1065             case 'X':
1066                 Item.Width = Item.Long ? 16 : 8;
1067                 Item.Pad = '0';
1068             case 'x':
1069                 Item.Item.pw = Item.Scratch;
1070                 ValueToHex (
1071                     Item.Item.pw, 
1072                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
1073                     );
1074
1075                 break;
1076         
1077
1078             case 'g':
1079                 Item.Item.pw = Item.Scratch;
1080                 GuidToString (Item.Item.pw, va_arg(ps->args, EFI_GUID *));
1081                 break;
1082
1083             case 'd':
1084                 Item.Item.pw = Item.Scratch;
1085                 ValueToString (
1086                     Item.Item.pw, 
1087                     Item.Comma, 
1088                     Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
1089                     );
1090                 break
1091                     ;
1092             case 't':
1093                 Item.Item.pw = Item.Scratch;
1094                 TimeToString (Item.Item.pw, va_arg(ps->args, EFI_TIME *));
1095                 break;
1096
1097             case 'r':
1098                 Item.Item.pw = Item.Scratch;
1099                 StatusToString (Item.Item.pw, va_arg(ps->args, EFI_STATUS));
1100                 break;
1101
1102             case 'n':
1103                 PSETATTR(ps, ps->AttrNorm);
1104                 break;
1105
1106             case 'h':
1107                 PSETATTR(ps, ps->AttrHighlight);
1108                 break;
1109
1110             case 'e':
1111                 PSETATTR(ps, ps->AttrError);
1112                 break;
1113
1114             case 'N':
1115                 Attr = ps->AttrNorm;
1116                 break;
1117
1118             case 'H':
1119                 Attr = ps->AttrHighlight;
1120                 break;
1121
1122             case 'E':
1123                 Attr = ps->AttrError;
1124                 break;
1125
1126             default:
1127                 Item.Item.pw = Item.Scratch;
1128                 Item.Item.pw[0] = '?';
1129                 Item.Item.pw[1] = 0;
1130                 break;
1131             }
1132
1133             // if we have an Item
1134             if (Item.Item.pw) {
1135                 PITEM (ps);
1136                 break;
1137             }
1138
1139             // if we have an Attr set
1140             if (Attr) {
1141                 PSETATTR(ps, Attr);
1142                 ps->RestoreAttr = 0;
1143                 break;
1144             }
1145         }
1146
1147         if (ps->RestoreAttr) {
1148             PSETATTR(ps, ps->RestoreAttr);
1149         }
1150     }
1151
1152     // Flush buffer
1153     PFLUSH (ps);
1154     return ps->Len;
1155 }
1156
1157 STATIC CHAR8 Hex[] = {'0','1','2','3','4','5','6','7',
1158                       '8','9','A','B','C','D','E','F'};
1159
1160 VOID
1161 ValueToHex (
1162     IN CHAR16   *Buffer,
1163     IN UINT64   v
1164     )
1165 {
1166     CHAR8           str[30], *p1;
1167     CHAR16          *p2;
1168
1169     if (!v) {
1170         Buffer[0] = '0';
1171         Buffer[1] = 0;
1172         return ;
1173     }
1174
1175     p1 = str;
1176     p2 = Buffer;
1177
1178     while (v) {
1179         *(p1++) = Hex[v & 0xf];
1180         v = RShiftU64 (v, 4);
1181     }
1182
1183     while (p1 != str) {
1184         *(p2++) = *(--p1);
1185     }
1186     *p2 = 0;
1187 }
1188
1189
1190 VOID
1191 ValueToString (
1192     IN CHAR16   *Buffer,
1193     IN BOOLEAN  Comma,
1194     IN INT64    v
1195     )
1196 {
1197     STATIC CHAR8 ca[] = {  3, 1, 2 };
1198     CHAR8        str[40], *p1;
1199     CHAR16       *p2;
1200     UINTN        c, r;
1201
1202     if (!v) {
1203         Buffer[0] = '0';
1204         Buffer[1] = 0;
1205         return ;
1206     }
1207
1208     p1 = str;
1209     p2 = Buffer;
1210
1211     if (v < 0) {
1212         *(p2++) = '-';
1213         v = -v;
1214     }
1215
1216     while (v) {
1217         v = (INT64)DivU64x32 ((UINT64)v, 10, &r);
1218         *(p1++) = (CHAR8)r + '0';
1219     }
1220
1221     c = (Comma ? ca[(p1 - str) % 3] : 999) + 1;
1222     while (p1 != str) {
1223
1224         c -= 1;
1225         if (!c) {
1226             *(p2++) = ',';
1227             c = 3;
1228         }
1229
1230         *(p2++) = *(--p1);
1231     }
1232     *p2 = 0;
1233 }
1234
1235 VOID
1236 TimeToString (
1237     OUT CHAR16      *Buffer,
1238     IN EFI_TIME     *Time
1239     )
1240 {
1241     UINTN       Hour, Year;
1242     CHAR16      AmPm;
1243
1244     AmPm = 'a';
1245     Hour = Time->Hour;
1246     if (Time->Hour == 0) {
1247         Hour = 12;
1248     } else if (Time->Hour >= 12) {
1249         AmPm = 'p';
1250         if (Time->Hour >= 13) {
1251             Hour -= 12;
1252         }
1253     }
1254
1255     Year = Time->Year % 100;
1256     
1257     // bugbug: for now just print it any old way
1258     SPrint (Buffer, 0, L"%02d/%02d/%02d  %02d:%02d%c",
1259         Time->Month,
1260         Time->Day,
1261         Year,
1262         Hour,
1263         Time->Minute,
1264         AmPm
1265         );
1266
1267
1268
1269
1270
1271 VOID
1272 DumpHex (
1273     IN UINTN        Indent,
1274     IN UINTN        Offset,
1275     IN UINTN        DataSize,
1276     IN VOID         *UserData
1277     )
1278 {
1279     CHAR8           *Data, Val[50], Str[20], c;
1280     UINTN           Size, Index;
1281     
1282     UINTN           ScreenCount;
1283     UINTN           TempColumn;
1284     UINTN           ScreenSize;
1285     CHAR16          ReturnStr[1];
1286
1287
1288     uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &TempColumn, &ScreenSize);
1289     ScreenCount = 0;
1290     ScreenSize -= 2;
1291
1292     Data = UserData;
1293     while (DataSize) {
1294         Size = 16;
1295         if (Size > DataSize) {
1296             Size = DataSize;
1297         }
1298
1299         for (Index=0; Index < Size; Index += 1) {
1300             c = Data[Index];
1301             Val[Index*3+0] = Hex[c>>4];
1302             Val[Index*3+1] = Hex[c&0xF];
1303             Val[Index*3+2] = (Index == 7)?'-':' ';
1304             Str[Index] = (c < ' ' || c > 'z') ? '.' : c;
1305         }
1306
1307         Val[Index*3] = 0;
1308         Str[Index] = 0;
1309         Print (L"%*a%X: %-.48a *%a*\n", Indent, "", Offset, Val, Str);
1310
1311         Data += Size;
1312         Offset += Size;
1313         DataSize -= Size;
1314
1315         ScreenCount++;
1316         if (ScreenCount >= ScreenSize && ScreenSize != 0) {
1317             //
1318             // If ScreenSize == 0 we have the console redirected so don't
1319             //  block updates
1320             //
1321             ScreenCount = 0;
1322             Print (L"Press Enter to continue :");
1323             Input (L"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16));
1324             Print (L"\n");
1325         }
1326
1327     }
1328 }