Subversion Repositories HelenOS

Rev

Rev 2726 | Details | Compare with Previous | 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
}