print.c revision 1.3 1 /* $NetBSD: print.c,v 1.3 2019/01/27 02:08:43 pgoyette 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 >>>>>>> 1.1.1.1.34.1
536
537 CHAR16 *
538 PoolPrint (
539 IN CONST CHAR16 *fmt,
540 ...
541 )
542 /*++
543
544 Routine Description:
545
546 Prints a formatted unicode string to allocated pool. The caller
547 must free the resulting buffer.
548
549 Arguments:
550
551 fmt - The format string
552
553 Returns:
554
555 Allocated buffer with the formatted string printed in it.
556 The caller must free the allocated buffer. The buffer
557 allocation is not packed.
558
559 --*/
560 {
561 va_list args;
562 CHAR16 *pool;
563 va_start (args, fmt);
564 pool = VPoolPrint(fmt, args);
565 va_end (args);
566 return pool;
567 }
568
569 CHAR16 *
570 CatPrint (
571 IN OUT POOL_PRINT *Str,
572 IN CONST CHAR16 *fmt,
573 ...
574 )
575 /*++
576
577 Routine Description:
578
579 Concatenates a formatted unicode string to allocated pool.
580 The caller must free the resulting buffer.
581
582 Arguments:
583
584 Str - Tracks the allocated pool, size in use, and
585 amount of pool allocated.
586
587 fmt - The format string
588
589 Returns:
590
591 Allocated buffer with the formatted string printed in it.
592 The caller must free the allocated buffer. The buffer
593 allocation is not packed.
594
595 --*/
596 {
597 va_list args;
598
599 va_start (args, fmt);
600 _PoolCatPrint (fmt, args, Str, _PoolPrint);
601 va_end (args);
602 return Str->str;
603 }
604
605
606
607 UINTN
608 Print (
609 IN CONST CHAR16 *fmt,
610 ...
611 )
612 /*++
613
614 Routine Description:
615
616 Prints a formatted unicode string to the default console
617
618 Arguments:
619
620 fmt - Format string
621
622 Returns:
623
624 Length of string printed to the console
625
626 --*/
627 {
628 va_list args;
629 UINTN back;
630
631 va_start (args, fmt);
632 back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
633 va_end (args);
634 return back;
635 }
636
637 UINTN
638 VPrint (
639 IN CONST CHAR16 *fmt,
640 va_list args
641 )
642 /*++
643
644 Routine Description:
645
646 Prints a formatted unicode string to the default console using a va_list
647
648 Arguments:
649
650 fmt - Format string
651 args - va_list
652 Returns:
653
654 Length of string printed to the console
655
656 --*/
657 {
658 return _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, fmt, NULL, args);
659 }
660
661
662 UINTN
663 PrintAt (
664 IN UINTN Column,
665 IN UINTN Row,
666 IN CONST CHAR16 *fmt,
667 ...
668 )
669 /*++
670
671 Routine Description:
672
673 Prints a formatted unicode string to the default console, at
674 the supplied cursor position
675
676 Arguments:
677
678 Column, Row - The cursor position to print the string at
679
680 fmt - Format string
681
682 Returns:
683
684 Length of string printed to the console
685
686 --*/
687 {
688 va_list args;
689 UINTN back;
690
691 va_start (args, fmt);
692 back = _IPrint (Column, Row, ST->ConOut, fmt, NULL, args);
693 va_end (args);
694 return back;
695 }
696
697
698 UINTN
699 IPrint (
700 IN SIMPLE_TEXT_OUTPUT_INTERFACE *Out,
701 IN CONST CHAR16 *fmt,
702 ...
703 )
704 /*++
705
706 Routine Description:
707
708 Prints a formatted unicode string to the specified console
709
710 Arguments:
711
712 Out - The console to print the string too
713
714 fmt - Format string
715
716 Returns:
717
718 Length of string printed to the console
719
720 --*/
721 {
722 va_list args;
723 UINTN back;
724
725 va_start (args, fmt);
726 back = _IPrint ((UINTN) -1, (UINTN) -1, Out, fmt, NULL, args);
727 va_end (args);
728 return back;
729 }
730
731
732 UINTN
733 IPrintAt (
734 IN SIMPLE_TEXT_OUTPUT_INTERFACE *Out,
735 IN UINTN Column,
736 IN UINTN Row,
737 IN CONST CHAR16 *fmt,
738 ...
739 )
740 /*++
741
742 Routine Description:
743
744 Prints a formatted unicode string to the specified console, at
745 the supplied cursor position
746
747 Arguments:
748
749 Out - The console to print the string to
750
751 Column, Row - The cursor position to print the string at
752
753 fmt - Format string
754
755 Returns:
756
757 Length of string printed to the console
758
759 --*/
760 {
761 va_list args;
762 UINTN back;
763
764 va_start (args, fmt);
765 back = _IPrint (Column, Row, Out, fmt, NULL, args);
766 va_end (args);
767 return back;
768 }
769
770
771 UINTN
772 _IPrint (
773 IN UINTN Column,
774 IN UINTN Row,
775 IN SIMPLE_TEXT_OUTPUT_INTERFACE *Out,
776 IN CONST CHAR16 *fmt,
777 IN CONST CHAR8 *fmta,
778 IN va_list args
779 )
780 // Display string worker for: Print, PrintAt, IPrint, IPrintAt
781 {
782 PRINT_STATE ps;
783 UINTN back;
784
785 ZeroMem (&ps, sizeof(ps));
786 ps.Context = Out;
787 ps.Output = (INTN (EFIAPI *)(VOID *, CHAR16 *)) Out->OutputString;
788 ps.SetAttr = (INTN (EFIAPI *)(VOID *, UINTN)) Out->SetAttribute;
789 ps.Attr = Out->Mode->Attribute;
790
791 back = (ps.Attr >> 4) & 0xF;
792 ps.AttrNorm = EFI_TEXT_ATTR(EFI_LIGHTGRAY, back);
793 ps.AttrHighlight = EFI_TEXT_ATTR(EFI_WHITE, back);
794 ps.AttrError = EFI_TEXT_ATTR(EFI_YELLOW, back);
795
796 if (fmt) {
797 ps.fmt.pw = fmt;
798 } else {
799 ps.fmt.Ascii = TRUE;
800 ps.fmt.pc = fmta;
801 }
802
803 va_copy(ps.args, args);
804
805 if (Column != (UINTN) -1) {
806 uefi_call_wrapper(Out->SetCursorPosition, 3, Out, Column, Row);
807 }
808
809 back = _Print (&ps);
810 va_end(ps.args);
811 return back;
812 }
813
814
815 UINTN
816 APrint (
817 IN CONST CHAR8 *fmt,
818 ...
819 )
820 /*++
821
822 Routine Description:
823
824 For those whom really can't deal with unicode, a print
825 function that takes an ascii format string
826
827 Arguments:
828
829 fmt - ascii format string
830
831 Returns:
832
833 Length of string printed to the console
834
835 --*/
836
837 {
838 va_list args;
839 UINTN back;
840
841 va_start (args, fmt);
842 back = _IPrint ((UINTN) -1, (UINTN) -1, ST->ConOut, NULL, fmt, args);
843 va_end (args);
844 return back;
845 }
846
847
848 STATIC
849 VOID
850 PFLUSH (
851 IN OUT PRINT_STATE *ps
852 )
853 {
854 *ps->Pos = 0;
855 if (IsLocalPrint(ps->Output))
856 ps->Output(ps->Context, ps->Buffer);
857 else
858 uefi_call_wrapper(ps->Output, 2, ps->Context, ps->Buffer);
859 ps->Pos = ps->Buffer;
860 }
861
862 STATIC
863 VOID
864 PSETATTR (
865 IN OUT PRINT_STATE *ps,
866 IN UINTN Attr
867 )
868 {
869 PFLUSH (ps);
870
871 ps->RestoreAttr = ps->Attr;
872 if (ps->SetAttr) {
873 uefi_call_wrapper(ps->SetAttr, 2, ps->Context, Attr);
874 }
875
876 ps->Attr = Attr;
877 }
878
879 STATIC
880 VOID
881 PPUTC (
882 IN OUT PRINT_STATE *ps,
883 IN CHAR16 c
884 )
885 {
886 // if this is a newline, add a carraige return
887 if (c == '\n') {
888 PPUTC (ps, '\r');
889 }
890
891 *ps->Pos = c;
892 ps->Pos += 1;
893 ps->Len += 1;
894
895 // if at the end of the buffer, flush it
896 if (ps->Pos >= ps->End) {
897 PFLUSH(ps);
898 }
899 }
900
901
902 STATIC
903 CHAR16
904 PGETC (
905 IN POINTER *p
906 )
907 {
908 CHAR16 c;
909
910 c = p->Ascii ? p->pc[p->Index] : p->pw[p->Index];
911 p->Index += 1;
912
913 return c;
914 }
915
916
917 STATIC
918 VOID
919 PITEM (
920 IN OUT PRINT_STATE *ps
921 )
922 {
923 UINTN Len, i;
924 PRINT_ITEM *Item;
925 CHAR16 c;
926
927 // Get the length of the item
928 Item = ps->Item;
929 Item->Item.Index = 0;
930 while (Item->Item.Index < Item->FieldWidth) {
931 c = PGETC(&Item->Item);
932 if (!c) {
933 Item->Item.Index -= 1;
934 break;
935 }
936 }
937 Len = Item->Item.Index;
938
939 // if there is no item field width, use the items width
940 if (Item->FieldWidth == (UINTN) -1) {
941 Item->FieldWidth = Len;
942 }
943
944 // if item is larger then width, update width
945 if (Len > Item->Width) {
946 Item->Width = Len;
947 }
948
949
950 // if pad field before, add pad char
951 if (Item->PadBefore) {
952 for (i=Item->Width; i < Item->FieldWidth; i+=1) {
953 PPUTC (ps, ' ');
954 }
955 }
956
957 // pad item
958 for (i=Len; i < Item->Width; i++) {
959 PPUTC (ps, Item->Pad);
960 }
961
962 // add the item
963 Item->Item.Index=0;
964 while (Item->Item.Index < Len) {
965 PPUTC (ps, PGETC(&Item->Item));
966 }
967
968 // If pad at the end, add pad char
969 if (!Item->PadBefore) {
970 for (i=Item->Width; i < Item->FieldWidth; i+=1) {
971 PPUTC (ps, ' ');
972 }
973 }
974 }
975
976
977 STATIC
978 UINTN
979 _Print (
980 IN PRINT_STATE *ps
981 )
982 /*++
983
984 Routine Description:
985
986 %w.lF - w = width
987 l = field width
988 F = format of arg
989
990 Args F:
991 0 - pad with zeros
992 - - justify on left (default is on right)
993 , - add comma's to field
994 * - width provided on stack
995 n - Set output attribute to normal (for this field only)
996 h - Set output attribute to highlight (for this field only)
997 e - Set output attribute to error (for this field only)
998 l - Value is 64 bits
999
1000 a - ascii string
1001 s - unicode string
1002 X - fixed 8 byte value in hex
1003 x - hex value
1004 d - value as signed decimal
1005 u - value as unsigned decimal
1006 f - value as floating point
1007 c - Unicode char
1008 t - EFI time structure
1009 g - Pointer to GUID
1010 r - EFI status code (result code)
1011 D - pointer to Device Path with normal ending.
1012
1013 N - Set output attribute to normal
1014 H - Set output attribute to highlight
1015 E - Set output attribute to error
1016 % - Print a %
1017
1018 Arguments:
1019
1020 SystemTable - The system table
1021
1022 Returns:
1023
1024 Number of charactors written
1025
1026 --*/
1027 {
1028 CHAR16 c;
1029 UINTN Attr;
1030 PRINT_ITEM Item;
1031 CHAR16 Buffer[PRINT_STRING_LEN];
1032
1033 ps->Len = 0;
1034 ps->Buffer = Buffer;
1035 ps->Pos = Buffer;
1036 ps->End = Buffer + PRINT_STRING_LEN - 1;
1037 ps->Item = &Item;
1038
1039 ps->fmt.Index = 0;
1040 while ((c = PGETC(&ps->fmt))) {
1041
1042 if (c != '%') {
1043 PPUTC ( ps, c );
1044 continue;
1045 }
1046
1047 // setup for new item
1048 Item.FieldWidth = (UINTN) -1;
1049 Item.Width = 0;
1050 Item.WidthParse = &Item.Width;
1051 Item.Pad = ' ';
1052 Item.PadBefore = TRUE;
1053 Item.Comma = FALSE;
1054 Item.Long = FALSE;
1055 Item.Item.Ascii = FALSE;
1056 Item.Item.pw = NULL;
1057 ps->RestoreAttr = 0;
1058 Attr = 0;
1059
1060 while ((c = PGETC(&ps->fmt))) {
1061
1062 switch (c) {
1063
1064 case '%':
1065 //
1066 // %% -> %
1067 //
1068 Item.Scratch[0] = '%';
1069 Item.Scratch[1] = 0;
1070 Item.Item.pw = Item.Scratch;
1071 break;
1072
1073 case '0':
1074 Item.Pad = '0';
1075 break;
1076
1077 case '-':
1078 Item.PadBefore = FALSE;
1079 break;
1080
1081 case ',':
1082 Item.Comma = TRUE;
1083 break;
1084
1085 case '.':
1086 Item.WidthParse = &Item.FieldWidth;
1087 break;
1088
1089 case '*':
1090 *Item.WidthParse = va_arg(ps->args, UINTN);
1091 break;
1092
1093 case '1':
1094 case '2':
1095 case '3':
1096 case '4':
1097 case '5':
1098 case '6':
1099 case '7':
1100 case '8':
1101 case '9':
1102 *Item.WidthParse = 0;
1103 do {
1104 *Item.WidthParse = *Item.WidthParse * 10 + c - '0';
1105 c = PGETC(&ps->fmt);
1106 } while (c >= '0' && c <= '9') ;
1107 ps->fmt.Index -= 1;
1108 break;
1109
1110 case 'a':
1111 Item.Item.pc = va_arg(ps->args, CHAR8 *);
1112 Item.Item.Ascii = TRUE;
1113 if (!Item.Item.pc) {
1114 Item.Item.pc = (CHAR8 *)"(null)";
1115 }
1116 break;
1117
1118 case 's':
1119 Item.Item.pw = va_arg(ps->args, CHAR16 *);
1120 if (!Item.Item.pw) {
1121 Item.Item.pw = L"(null)";
1122 }
1123 break;
1124
1125 case 'c':
1126 Item.Scratch[0] = (CHAR16) va_arg(ps->args, UINTN);
1127 Item.Scratch[1] = 0;
1128 Item.Item.pw = Item.Scratch;
1129 break;
1130
1131 case 'l':
1132 Item.Long = TRUE;
1133 break;
1134
1135 case 'X':
1136 Item.Width = Item.Long ? 16 : 8;
1137 Item.Pad = '0';
1138 #if __GNUC__ >= 7
1139 __attribute__ ((fallthrough));
1140 #endif
1141 case 'x':
1142 ValueToHex (
1143 Item.Scratch,
1144 Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
1145 );
1146 Item.Item.pw = Item.Scratch;
1147
1148 break;
1149
1150
1151 case 'g':
1152 GuidToString (Item.Scratch, va_arg(ps->args, EFI_GUID *));
1153 Item.Item.pw = Item.Scratch;
1154 break;
1155
1156 case 'u':
1157 ValueToString (
1158 Item.Scratch,
1159 Item.Comma,
1160 Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
1161 );
1162 Item.Item.pw = Item.Scratch;
1163 break;
1164
1165 case 'd':
1166 ValueToString (
1167 Item.Scratch,
1168 Item.Comma,
1169 Item.Long ? va_arg(ps->args, INT64) : va_arg(ps->args, INT32)
1170 );
1171 Item.Item.pw = Item.Scratch;
1172 break;
1173
1174 case 'D':
1175 {
1176 EFI_DEVICE_PATH *dp = va_arg(ps->args, EFI_DEVICE_PATH *);
1177 CHAR16 *dpstr = DevicePathToStr(dp);
1178 StrnCpy(Item.Scratch, dpstr, PRINT_ITEM_BUFFER_LEN);
1179 Item.Scratch[PRINT_ITEM_BUFFER_LEN-1] = L'\0';
1180 FreePool(dpstr);
1181
1182 Item.Item.pw = Item.Scratch;
1183 break;
1184 }
1185
1186 #ifndef __NetBSD__
1187 case 'f':
1188 FloatToString (
1189 Item.Scratch,
1190 Item.Comma,
1191 va_arg(ps->args, double)
1192 );
1193 Item.Item.pw = Item.Scratch;
1194 break;
1195 #endif
1196
1197 case 't':
1198 TimeToString (Item.Scratch, va_arg(ps->args, EFI_TIME *));
1199 Item.Item.pw = Item.Scratch;
1200 break;
1201
1202 case 'r':
1203 StatusToString (Item.Scratch, va_arg(ps->args, EFI_STATUS));
1204 Item.Item.pw = Item.Scratch;
1205 break;
1206
1207 case 'n':
1208 PSETATTR(ps, ps->AttrNorm);
1209 break;
1210
1211 case 'h':
1212 PSETATTR(ps, ps->AttrHighlight);
1213 break;
1214
1215 case 'e':
1216 PSETATTR(ps, ps->AttrError);
1217 break;
1218
1219 case 'N':
1220 Attr = ps->AttrNorm;
1221 break;
1222
1223 case 'H':
1224 Attr = ps->AttrHighlight;
1225 break;
1226
1227 case 'E':
1228 Attr = ps->AttrError;
1229 break;
1230
1231 default:
1232 Item.Scratch[0] = '?';
1233 Item.Scratch[1] = 0;
1234 Item.Item.pw = Item.Scratch;
1235 break;
1236 }
1237
1238 // if we have an Item
1239 if (Item.Item.pw) {
1240 PITEM (ps);
1241 break;
1242 }
1243
1244 // if we have an Attr set
1245 if (Attr) {
1246 PSETATTR(ps, Attr);
1247 ps->RestoreAttr = 0;
1248 break;
1249 }
1250 }
1251
1252 if (ps->RestoreAttr) {
1253 PSETATTR(ps, ps->RestoreAttr);
1254 }
1255 }
1256
1257 // Flush buffer
1258 PFLUSH (ps);
1259 return ps->Len;
1260 }
1261
1262 STATIC CHAR8 Hex[] = {'0','1','2','3','4','5','6','7',
1263 '8','9','A','B','C','D','E','F'};
1264
1265 VOID
1266 ValueToHex (
1267 IN CHAR16 *Buffer,
1268 IN UINT64 v
1269 )
1270 {
1271 CHAR8 str[30], *p1;
1272 CHAR16 *p2;
1273
1274 if (!v) {
1275 Buffer[0] = '0';
1276 Buffer[1] = 0;
1277 return ;
1278 }
1279
1280 p1 = str;
1281 p2 = Buffer;
1282
1283 while (v) {
1284 // Without the cast, the MSVC compiler may insert a reference to __allmull
1285 *(p1++) = Hex[(UINTN)(v & 0xf)];
1286 v = RShiftU64 (v, 4);
1287 }
1288
1289 while (p1 != str) {
1290 *(p2++) = *(--p1);
1291 }
1292 *p2 = 0;
1293 }
1294
1295
1296 VOID
1297 ValueToString (
1298 IN CHAR16 *Buffer,
1299 IN BOOLEAN Comma,
1300 IN INT64 v
1301 )
1302 {
1303 STATIC CHAR8 ca[] = { 3, 1, 2 };
1304 CHAR8 str[40], *p1;
1305 CHAR16 *p2;
1306 UINTN c, r;
1307
1308 if (!v) {
1309 Buffer[0] = '0';
1310 Buffer[1] = 0;
1311 return ;
1312 }
1313
1314 p1 = str;
1315 p2 = Buffer;
1316
1317 if (v < 0) {
1318 *(p2++) = '-';
1319 v = -v;
1320 }
1321
1322 while (v) {
1323 v = (INT64)DivU64x32 ((UINT64)v, 10, &r);
1324 *(p1++) = (CHAR8)r + '0';
1325 }
1326
1327 c = (Comma ? ca[(p1 - str) % 3] : 999) + 1;
1328 while (p1 != str) {
1329
1330 c -= 1;
1331 if (!c) {
1332 *(p2++) = ',';
1333 c = 3;
1334 }
1335
1336 *(p2++) = *(--p1);
1337 }
1338 *p2 = 0;
1339 }
1340
1341 #ifndef __NetBSD__
1342 VOID
1343 FloatToString (
1344 IN CHAR16 *Buffer,
1345 IN BOOLEAN Comma,
1346 IN double v
1347 )
1348 {
1349 /*
1350 * Integer part.
1351 */
1352 INTN i = (INTN)v;
1353 ValueToString(Buffer, Comma, i);
1354
1355
1356 /*
1357 * Decimal point.
1358 */
1359 UINTN x = StrLen(Buffer);
1360 Buffer[x] = L'.';
1361 x++;
1362
1363
1364 /*
1365 * Keep fractional part.
1366 */
1367 float f = (float)(v - i);
1368 if (f < 0) f = -f;
1369
1370
1371 /*
1372 * Leading fractional zeroes.
1373 */
1374 f *= 10.0;
1375 while ( (f != 0)
1376 && ((INTN)f == 0))
1377 {
1378 Buffer[x] = L'0';
1379 x++;
1380 f *= 10.0;
1381 }
1382
1383
1384 /*
1385 * Fractional digits.
1386 */
1387 while ((float)(INTN)f != f)
1388 {
1389 f *= 10;
1390 }
1391 ValueToString(Buffer + x, FALSE, (INTN)f);
1392 return;
1393 }
1394 #endif
1395
1396 VOID
1397 TimeToString (
1398 OUT CHAR16 *Buffer,
1399 IN EFI_TIME *Time
1400 )
1401 {
1402 UINTN Hour, Year;
1403 CHAR16 AmPm;
1404
1405 AmPm = 'a';
1406 Hour = Time->Hour;
1407 if (Time->Hour == 0) {
1408 Hour = 12;
1409 } else if (Time->Hour >= 12) {
1410 AmPm = 'p';
1411 if (Time->Hour >= 13) {
1412 Hour -= 12;
1413 }
1414 }
1415
1416 Year = Time->Year % 100;
1417
1418 // bugbug: for now just print it any old way
1419 SPrint (Buffer, 0, L"%02d/%02d/%02d %02d:%02d%c",
1420 Time->Month,
1421 Time->Day,
1422 Year,
1423 Hour,
1424 Time->Minute,
1425 AmPm
1426 );
1427 }
1428
1429
1430
1431
1432 VOID
1433 DumpHex (
1434 IN UINTN Indent,
1435 IN UINTN Offset,
1436 IN UINTN DataSize,
1437 IN VOID *UserData
1438 )
1439 {
1440 CHAR8 *Data, Val[50], Str[20], c;
1441 UINTN Size, Index;
1442
1443 UINTN ScreenCount;
1444 UINTN TempColumn;
1445 UINTN ScreenSize;
1446 CHAR16 ReturnStr[1];
1447
1448
1449 uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &TempColumn, &ScreenSize);
1450 ScreenCount = 0;
1451 ScreenSize -= 2;
1452
1453 Data = UserData;
1454 while (DataSize) {
1455 Size = 16;
1456 if (Size > DataSize) {
1457 Size = DataSize;
1458 }
1459
1460 for (Index=0; Index < Size; Index += 1) {
1461 c = Data[Index];
1462 Val[Index*3+0] = Hex[c>>4];
1463 Val[Index*3+1] = Hex[c&0xF];
1464 Val[Index*3+2] = (Index == 7)?'-':' ';
1465 Str[Index] = (c < ' ' || c > 'z') ? '.' : c;
1466 }
1467
1468 Val[Index*3] = 0;
1469 Str[Index] = 0;
1470 Print (L"%*a%X: %-.48a *%a*\n", Indent, "", Offset, Val, Str);
1471
1472 Data += Size;
1473 Offset += Size;
1474 DataSize -= Size;
1475
1476 ScreenCount++;
1477 if (ScreenCount >= ScreenSize && ScreenSize != 0) {
1478 //
1479 // If ScreenSize == 0 we have the console redirected so don't
1480 // block updates
1481 //
1482 ScreenCount = 0;
1483 Print (L"Press Enter to continue :");
1484 Input (L"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16));
1485 Print (L"\n");
1486 }
1487
1488 }
1489 }
1490