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