print.c revision 1.1.1.3 1 /* $NetBSD: print.c,v 1.1.1.3 2021/09/30 18:50:09 jmcneill 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 UnicodeSPrint, 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 // Dispatch function for UnicodeSPrint, 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 UnicodeVSPrint (
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 UnicodeSPrint (
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 = UnicodeVSPrint(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 AsciiPrint (
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 UINTN
848 AsciiVSPrint (
849 OUT CHAR8 *Str,
850 IN UINTN StrSize,
851 IN CONST CHAR8 *fmt,
852 va_list args
853 )
854 /*++
855
856 Routine Description:
857
858 Prints a formatted ascii string to a buffer using a va_list
859
860 Arguments:
861
862 Str - Output buffer to print the formatted string into
863
864 StrSize - Size of Str. String is truncated to this size.
865 A size of 0 means there is no limit
866
867 fmt - The format string
868
869 args - va_list
870
871
872 Returns:
873
874 String length returned in buffer
875
876 --*/
877 // Use UnicodeVSPrint() and convert back to ASCII
878 {
879 CHAR16 *UnicodeStr, *UnicodeFmt;
880 UINTN i, Len;
881
882 UnicodeStr = AllocatePool(StrSize * sizeof(CHAR16));
883 if (!UnicodeStr)
884 return 0;
885
886 UnicodeFmt = PoolPrint(L"%a", fmt);
887 if (!UnicodeFmt) {
888 FreePool(UnicodeStr);
889 return 0;
890 }
891
892 Len = UnicodeVSPrint(UnicodeStr, StrSize, UnicodeFmt, args);
893 FreePool(UnicodeFmt);
894
895 // The strings are ASCII so just do a plain Unicode conversion
896 for (i = 0; i < Len; i++)
897 Str[i] = (CHAR8)UnicodeStr[i];
898 Str[Len] = 0;
899 FreePool(UnicodeStr);
900
901 return Len;
902 }
903
904
905 STATIC
906 VOID
907 PFLUSH (
908 IN OUT PRINT_STATE *ps
909 )
910 {
911 *ps->Pos = 0;
912 if (IsLocalPrint(ps->Output))
913 ps->Output(ps->Context, ps->Buffer);
914 else
915 uefi_call_wrapper(ps->Output, 2, ps->Context, ps->Buffer);
916 ps->Pos = ps->Buffer;
917 }
918
919 STATIC
920 VOID
921 PSETATTR (
922 IN OUT PRINT_STATE *ps,
923 IN UINTN Attr
924 )
925 {
926 PFLUSH (ps);
927
928 ps->RestoreAttr = ps->Attr;
929 if (ps->SetAttr) {
930 uefi_call_wrapper(ps->SetAttr, 2, ps->Context, Attr);
931 }
932
933 ps->Attr = Attr;
934 }
935
936 STATIC
937 VOID
938 PPUTC (
939 IN OUT PRINT_STATE *ps,
940 IN CHAR16 c
941 )
942 {
943 // if this is a newline, add a carraige return
944 if (c == '\n') {
945 PPUTC (ps, '\r');
946 }
947
948 *ps->Pos = c;
949 ps->Pos += 1;
950 ps->Len += 1;
951
952 // if at the end of the buffer, flush it
953 if (ps->Pos >= ps->End) {
954 PFLUSH(ps);
955 }
956 }
957
958
959 STATIC
960 CHAR16
961 PGETC (
962 IN POINTER *p
963 )
964 {
965 CHAR16 c;
966
967 c = p->Ascii ? p->pc[p->Index] : p->pw[p->Index];
968 p->Index += 1;
969
970 return c;
971 }
972
973
974 STATIC
975 VOID
976 PITEM (
977 IN OUT PRINT_STATE *ps
978 )
979 {
980 UINTN Len, i;
981 PRINT_ITEM *Item;
982 CHAR16 c;
983
984 // Get the length of the item
985 Item = ps->Item;
986 Item->Item.Index = 0;
987 while (Item->Item.Index < Item->FieldWidth) {
988 c = PGETC(&Item->Item);
989 if (!c) {
990 Item->Item.Index -= 1;
991 break;
992 }
993 }
994 Len = Item->Item.Index;
995
996 // if there is no item field width, use the items width
997 if (Item->FieldWidth == (UINTN) -1) {
998 Item->FieldWidth = Len;
999 }
1000
1001 // if item is larger then width, update width
1002 if (Len > Item->Width) {
1003 Item->Width = Len;
1004 }
1005
1006
1007 // if pad field before, add pad char
1008 if (Item->PadBefore) {
1009 for (i=Item->Width; i < Item->FieldWidth; i+=1) {
1010 PPUTC (ps, ' ');
1011 }
1012 }
1013
1014 // pad item
1015 for (i=Len; i < Item->Width; i++) {
1016 PPUTC (ps, Item->Pad);
1017 }
1018
1019 // add the item
1020 Item->Item.Index=0;
1021 while (Item->Item.Index < Len) {
1022 PPUTC (ps, PGETC(&Item->Item));
1023 }
1024
1025 // If pad at the end, add pad char
1026 if (!Item->PadBefore) {
1027 for (i=Item->Width; i < Item->FieldWidth; i+=1) {
1028 PPUTC (ps, ' ');
1029 }
1030 }
1031 }
1032
1033
1034 STATIC
1035 UINTN
1036 _Print (
1037 IN PRINT_STATE *ps
1038 )
1039 /*++
1040
1041 Routine Description:
1042
1043 %w.lF - w = width
1044 l = field width
1045 F = format of arg
1046
1047 Args F:
1048 0 - pad with zeros
1049 - - justify on left (default is on right)
1050 , - add comma's to field
1051 * - width provided on stack
1052 n - Set output attribute to normal (for this field only)
1053 h - Set output attribute to highlight (for this field only)
1054 e - Set output attribute to error (for this field only)
1055 l - Value is 64 bits
1056
1057 a - ascii string
1058 s - unicode string
1059 X - fixed 8 byte value in hex
1060 x - hex value
1061 d - value as signed decimal
1062 u - value as unsigned decimal
1063 f - value as floating point
1064 c - Unicode char
1065 t - EFI time structure
1066 g - Pointer to GUID
1067 r - EFI status code (result code)
1068 D - pointer to Device Path with normal ending.
1069
1070 N - Set output attribute to normal
1071 H - Set output attribute to highlight
1072 E - Set output attribute to error
1073 % - Print a %
1074
1075 Arguments:
1076
1077 SystemTable - The system table
1078
1079 Returns:
1080
1081 Number of charactors written
1082
1083 --*/
1084 {
1085 CHAR16 c;
1086 UINTN Attr;
1087 PRINT_ITEM Item;
1088 CHAR16 Buffer[PRINT_STRING_LEN];
1089
1090 ps->Len = 0;
1091 ps->Buffer = Buffer;
1092 ps->Pos = Buffer;
1093 ps->End = Buffer + PRINT_STRING_LEN - 1;
1094 ps->Item = &Item;
1095
1096 ps->fmt.Index = 0;
1097 while ((c = PGETC(&ps->fmt))) {
1098
1099 if (c != '%') {
1100 PPUTC ( ps, c );
1101 continue;
1102 }
1103
1104 // setup for new item
1105 Item.FieldWidth = (UINTN) -1;
1106 Item.Width = 0;
1107 Item.WidthParse = &Item.Width;
1108 Item.Pad = ' ';
1109 Item.PadBefore = TRUE;
1110 Item.Comma = FALSE;
1111 Item.Long = FALSE;
1112 Item.Item.Ascii = FALSE;
1113 Item.Item.pw = NULL;
1114 ps->RestoreAttr = 0;
1115 Attr = 0;
1116
1117 while ((c = PGETC(&ps->fmt))) {
1118
1119 switch (c) {
1120
1121 case '%':
1122 //
1123 // %% -> %
1124 //
1125 Item.Scratch[0] = '%';
1126 Item.Scratch[1] = 0;
1127 Item.Item.pw = Item.Scratch;
1128 break;
1129
1130 case '0':
1131 Item.Pad = '0';
1132 break;
1133
1134 case '-':
1135 Item.PadBefore = FALSE;
1136 break;
1137
1138 case ',':
1139 Item.Comma = TRUE;
1140 break;
1141
1142 case '.':
1143 Item.WidthParse = &Item.FieldWidth;
1144 break;
1145
1146 case '*':
1147 *Item.WidthParse = va_arg(ps->args, UINTN);
1148 break;
1149
1150 case '1':
1151 case '2':
1152 case '3':
1153 case '4':
1154 case '5':
1155 case '6':
1156 case '7':
1157 case '8':
1158 case '9':
1159 *Item.WidthParse = 0;
1160 do {
1161 *Item.WidthParse = *Item.WidthParse * 10 + c - '0';
1162 c = PGETC(&ps->fmt);
1163 } while (c >= '0' && c <= '9') ;
1164 ps->fmt.Index -= 1;
1165 break;
1166
1167 case 'a':
1168 Item.Item.pc = va_arg(ps->args, CHAR8 *);
1169 Item.Item.Ascii = TRUE;
1170 if (!Item.Item.pc) {
1171 Item.Item.pc = (CHAR8 *)"(null)";
1172 }
1173 break;
1174
1175 case 's':
1176 Item.Item.pw = va_arg(ps->args, CHAR16 *);
1177 if (!Item.Item.pw) {
1178 Item.Item.pw = L"(null)";
1179 }
1180 break;
1181
1182 case 'c':
1183 Item.Scratch[0] = (CHAR16) va_arg(ps->args, UINTN);
1184 Item.Scratch[1] = 0;
1185 Item.Item.pw = Item.Scratch;
1186 break;
1187
1188 case 'l':
1189 Item.Long = TRUE;
1190 break;
1191
1192 case 'X':
1193 Item.Width = Item.Long ? 16 : 8;
1194 Item.Pad = '0';
1195 #if __GNUC__ >= 7
1196 __attribute__ ((fallthrough));
1197 #endif
1198 case 'x':
1199 ValueToHex (
1200 Item.Scratch,
1201 Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
1202 );
1203 Item.Item.pw = Item.Scratch;
1204
1205 break;
1206
1207
1208 case 'g':
1209 GuidToString (Item.Scratch, va_arg(ps->args, EFI_GUID *));
1210 Item.Item.pw = Item.Scratch;
1211 break;
1212
1213 case 'u':
1214 ValueToString (
1215 Item.Scratch,
1216 Item.Comma,
1217 Item.Long ? va_arg(ps->args, UINT64) : va_arg(ps->args, UINT32)
1218 );
1219 Item.Item.pw = Item.Scratch;
1220 break;
1221
1222 case 'd':
1223 ValueToString (
1224 Item.Scratch,
1225 Item.Comma,
1226 Item.Long ? va_arg(ps->args, INT64) : va_arg(ps->args, INT32)
1227 );
1228 Item.Item.pw = Item.Scratch;
1229 break;
1230
1231 case 'D':
1232 {
1233 EFI_DEVICE_PATH *dp = va_arg(ps->args, EFI_DEVICE_PATH *);
1234 CHAR16 *dpstr = DevicePathToStr(dp);
1235 StrnCpy(Item.Scratch, dpstr, PRINT_ITEM_BUFFER_LEN);
1236 Item.Scratch[PRINT_ITEM_BUFFER_LEN-1] = L'\0';
1237 FreePool(dpstr);
1238
1239 Item.Item.pw = Item.Scratch;
1240 break;
1241 }
1242
1243 case 'f':
1244 FloatToString (
1245 Item.Scratch,
1246 Item.Comma,
1247 va_arg(ps->args, double)
1248 );
1249 Item.Item.pw = Item.Scratch;
1250 break;
1251
1252 case 't':
1253 TimeToString (Item.Scratch, va_arg(ps->args, EFI_TIME *));
1254 Item.Item.pw = Item.Scratch;
1255 break;
1256
1257 case 'r':
1258 StatusToString (Item.Scratch, va_arg(ps->args, EFI_STATUS));
1259 Item.Item.pw = Item.Scratch;
1260 break;
1261
1262 case 'n':
1263 PSETATTR(ps, ps->AttrNorm);
1264 break;
1265
1266 case 'h':
1267 PSETATTR(ps, ps->AttrHighlight);
1268 break;
1269
1270 case 'e':
1271 PSETATTR(ps, ps->AttrError);
1272 break;
1273
1274 case 'N':
1275 Attr = ps->AttrNorm;
1276 break;
1277
1278 case 'H':
1279 Attr = ps->AttrHighlight;
1280 break;
1281
1282 case 'E':
1283 Attr = ps->AttrError;
1284 break;
1285
1286 default:
1287 Item.Scratch[0] = '?';
1288 Item.Scratch[1] = 0;
1289 Item.Item.pw = Item.Scratch;
1290 break;
1291 }
1292
1293 // if we have an Item
1294 if (Item.Item.pw) {
1295 PITEM (ps);
1296 break;
1297 }
1298
1299 // if we have an Attr set
1300 if (Attr) {
1301 PSETATTR(ps, Attr);
1302 ps->RestoreAttr = 0;
1303 break;
1304 }
1305 }
1306
1307 if (ps->RestoreAttr) {
1308 PSETATTR(ps, ps->RestoreAttr);
1309 }
1310 }
1311
1312 // Flush buffer
1313 PFLUSH (ps);
1314 return ps->Len;
1315 }
1316
1317 STATIC CHAR8 Hex[] = {'0','1','2','3','4','5','6','7',
1318 '8','9','A','B','C','D','E','F'};
1319
1320 VOID
1321 ValueToHex (
1322 IN CHAR16 *Buffer,
1323 IN UINT64 v
1324 )
1325 {
1326 CHAR8 str[30], *p1;
1327 CHAR16 *p2;
1328
1329 if (!v) {
1330 Buffer[0] = '0';
1331 Buffer[1] = 0;
1332 return ;
1333 }
1334
1335 p1 = str;
1336 p2 = Buffer;
1337
1338 while (v) {
1339 // Without the cast, the MSVC compiler may insert a reference to __allmull
1340 *(p1++) = Hex[(UINTN)(v & 0xf)];
1341 v = RShiftU64 (v, 4);
1342 }
1343
1344 while (p1 != str) {
1345 *(p2++) = *(--p1);
1346 }
1347 *p2 = 0;
1348 }
1349
1350
1351 VOID
1352 ValueToString (
1353 IN CHAR16 *Buffer,
1354 IN BOOLEAN Comma,
1355 IN INT64 v
1356 )
1357 {
1358 STATIC CHAR8 ca[] = { 3, 1, 2 };
1359 CHAR8 str[40], *p1;
1360 CHAR16 *p2;
1361 UINTN c, r;
1362
1363 if (!v) {
1364 Buffer[0] = '0';
1365 Buffer[1] = 0;
1366 return ;
1367 }
1368
1369 p1 = str;
1370 p2 = Buffer;
1371
1372 if (v < 0) {
1373 *(p2++) = '-';
1374 v = -v;
1375 }
1376
1377 while (v) {
1378 v = (INT64)DivU64x32 ((UINT64)v, 10, &r);
1379 *(p1++) = (CHAR8)r + '0';
1380 }
1381
1382 c = (UINTN) (Comma ? ca[(p1 - str) % 3] : 999) + 1;
1383 while (p1 != str) {
1384
1385 c -= 1;
1386 if (!c) {
1387 *(p2++) = ',';
1388 c = 3;
1389 }
1390
1391 *(p2++) = *(--p1);
1392 }
1393 *p2 = 0;
1394 }
1395
1396 VOID
1397 FloatToString (
1398 IN CHAR16 *Buffer,
1399 IN BOOLEAN Comma,
1400 IN double v
1401 )
1402 {
1403 /*
1404 * Integer part.
1405 */
1406 INTN i = (INTN)v;
1407 ValueToString(Buffer, Comma, i);
1408
1409
1410 /*
1411 * Decimal point.
1412 */
1413 UINTN x = StrLen(Buffer);
1414 Buffer[x] = L'.';
1415 x++;
1416
1417
1418 /*
1419 * Keep fractional part.
1420 */
1421 float f = (float)(v - i);
1422 if (f < 0) f = -f;
1423
1424
1425 /*
1426 * Leading fractional zeroes.
1427 */
1428 f *= 10.0;
1429 while ( (f != 0)
1430 && ((INTN)f == 0))
1431 {
1432 Buffer[x] = L'0';
1433 x++;
1434 f *= 10.0;
1435 }
1436
1437
1438 /*
1439 * Fractional digits.
1440 */
1441 while ((float)(INTN)f != f)
1442 {
1443 f *= 10;
1444 }
1445 ValueToString(Buffer + x, FALSE, (INTN)f);
1446 return;
1447 }
1448
1449 VOID
1450 TimeToString (
1451 OUT CHAR16 *Buffer,
1452 IN EFI_TIME *Time
1453 )
1454 {
1455 UINTN Hour, Year;
1456 CHAR16 AmPm;
1457
1458 AmPm = 'a';
1459 Hour = Time->Hour;
1460 if (Time->Hour == 0) {
1461 Hour = 12;
1462 } else if (Time->Hour >= 12) {
1463 AmPm = 'p';
1464 if (Time->Hour >= 13) {
1465 Hour -= 12;
1466 }
1467 }
1468
1469 Year = Time->Year % 100;
1470
1471 // bugbug: for now just print it any old way
1472 UnicodeSPrint (Buffer, 0, L"%02d/%02d/%02d %02d:%02d%c",
1473 Time->Month,
1474 Time->Day,
1475 Year,
1476 Hour,
1477 Time->Minute,
1478 AmPm
1479 );
1480 }
1481
1482
1483
1484
1485 VOID
1486 DumpHex (
1487 IN UINTN Indent,
1488 IN UINTN Offset,
1489 IN UINTN DataSize,
1490 IN VOID *UserData
1491 )
1492 {
1493 CHAR8 *Data, Val[50], Str[20], c;
1494 UINTN Size, Index;
1495
1496 UINTN ScreenCount;
1497 UINTN TempColumn;
1498 UINTN ScreenSize;
1499 CHAR16 ReturnStr[1];
1500
1501
1502 uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &TempColumn, &ScreenSize);
1503 ScreenCount = 0;
1504 ScreenSize -= 2;
1505
1506 Data = UserData;
1507 while (DataSize) {
1508 Size = 16;
1509 if (Size > DataSize) {
1510 Size = DataSize;
1511 }
1512
1513 for (Index=0; Index < Size; Index += 1) {
1514 c = Data[Index];
1515 Val[Index*3+0] = Hex[c>>4];
1516 Val[Index*3+1] = Hex[c&0xF];
1517 Val[Index*3+2] = (Index == 7)?'-':' ';
1518 Str[Index] = (c < ' ' || c > 'z') ? '.' : c;
1519 }
1520
1521 Val[Index*3] = 0;
1522 Str[Index] = 0;
1523 Print (L"%*a%X: %-.48a *%a*\n", Indent, "", Offset, Val, Str);
1524
1525 Data += Size;
1526 Offset += Size;
1527 DataSize -= Size;
1528
1529 ScreenCount++;
1530 if (ScreenCount >= ScreenSize && ScreenSize != 0) {
1531 //
1532 // If ScreenSize == 0 we have the console redirected so don't
1533 // block updates
1534 //
1535 ScreenCount = 0;
1536 Print (L"Press Enter to continue :");
1537 Input (L"", ReturnStr, sizeof(ReturnStr)/sizeof(CHAR16));
1538 Print (L"\n");
1539 }
1540
1541 }
1542 }
1543