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