Add Mde String and PrintLibs. Port StrGather to the Mde Unicode implementation. Compi...
[mirror_edk2.git] / Tools / Source / TianoTools / String / PrintLib.c
1 /** @file
2 Print Library.
3
4 Copyright (c) 2006, Intel Corporation<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 Module Name: PrintLib.c
14
15 **/
16
17 #include <Base.h>
18 #include <UefiBaseTypes.h>
19 #include <PrintLib.h>
20 #include <CommonLib.h>
21 #include "PrintLibInternal.h"
22
23 typedef struct {
24 RETURN_STATUS Status;
25 CHAR8 *String;
26 } STATUS_LOOKUP_TABLE_ENTRY;
27
28 static CONST STATUS_LOOKUP_TABLE_ENTRY StatusString[] = {
29 { RETURN_SUCCESS, "Success" },
30 { RETURN_LOAD_ERROR, "Load Error" },
31 { RETURN_INVALID_PARAMETER, "Invalid Parameter" },
32 { RETURN_UNSUPPORTED, "Unsupported" },
33 { RETURN_BAD_BUFFER_SIZE, "Bad Buffer Size" },
34 { RETURN_BUFFER_TOO_SMALL, "Buffer Too Small" },
35 { RETURN_NOT_READY, "Not Ready" },
36 { RETURN_DEVICE_ERROR, "Device Error" },
37 { RETURN_WRITE_PROTECTED, "Write Protected" },
38 { RETURN_OUT_OF_RESOURCES, "Out of Resources" },
39 { RETURN_VOLUME_CORRUPTED, "Volume Corrupt" },
40 { RETURN_VOLUME_FULL, "Volume Full" },
41 { RETURN_NO_MEDIA, "No Media" },
42 { RETURN_MEDIA_CHANGED, "Media changed" },
43 { RETURN_NOT_FOUND, "Not Found" },
44 { RETURN_ACCESS_DENIED, "Access Denied" },
45 { RETURN_NO_RESPONSE, "No Response" },
46 { RETURN_NO_MAPPING, "No mapping" },
47 { RETURN_TIMEOUT, "Time out" },
48 { RETURN_NOT_STARTED, "Not started" },
49 { RETURN_ALREADY_STARTED, "Already started" },
50 { RETURN_ABORTED, "Aborted" },
51 { RETURN_ICMP_ERROR, "ICMP Error" },
52 { RETURN_TFTP_ERROR, "TFTP Error" },
53 { RETURN_PROTOCOL_ERROR, "Protocol Error" },
54 { RETURN_WARN_UNKNOWN_GLYPH, "Warning Unknown Glyph" },
55 { RETURN_WARN_DELETE_FAILURE, "Warning Delete Failure" },
56 { RETURN_WARN_WRITE_FAILURE, "Warning Write Failure" },
57 { RETURN_WARN_BUFFER_TOO_SMALL, "Warning Buffer Too Small" },
58 { 0, NULL }
59 };
60
61
62 /**
63 VSPrint function to process format and place the results in Buffer. Since a
64 VA_LIST is used this rountine allows the nesting of Vararg routines. Thus
65 this is the main print working routine
66
67 @param StartOfBuffer Unicode buffer to print the results of the parsing of Format into.
68
69 @param BufferSize Maximum number of characters to put into buffer. Zero means
70 no limit.
71
72 @param Flags Intial flags value. Can only have FORMAT_UNICODE and OUTPUT_UNICODE set
73
74 @param FormatString Unicode format string see file header for more details.
75
76 @param Marker Vararg list consumed by processing Format.
77
78 @return Number of characters printed.
79
80 **/
81 UINTN
82 BasePrintLibVSPrint (
83 OUT CHAR8 *Buffer,
84 IN UINTN BufferSize,
85 IN UINTN Flags,
86 IN CONST CHAR8 *Format,
87 IN VA_LIST Marker
88 )
89 {
90 CHAR8 *OriginalBuffer;
91 CHAR8 ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
92 UINTN BytesPerOutputCharacter;
93 UINTN BytesPerFormatCharacter;
94 UINTN FormatMask;
95 UINTN FormatCharacter;
96 UINTN Width;
97 UINTN Precision;
98 INT64 Value;
99 CHAR8 *ArgumentString;
100 UINTN Character;
101 GUID *TmpGuid;
102 TIME *TmpTime;
103 UINTN Count;
104 UINTN ArgumentMask;
105 INTN BytesPerArgumentCharacter;
106 UINTN ArgumentCharacter;
107 BOOLEAN Done;
108 UINTN Index;
109 CHAR8 Prefix;
110 BOOLEAN ZeroPad;
111 BOOLEAN Comma;
112 UINTN Digits;
113 UINTN Radix;
114 RETURN_STATUS Status;
115
116 OriginalBuffer = Buffer;
117
118 if ((Flags & OUTPUT_UNICODE) != 0) {
119 BytesPerOutputCharacter = 2;
120 } else {
121 BytesPerOutputCharacter = 1;
122 }
123 if ((Flags & FORMAT_UNICODE) != 0) {
124 BytesPerFormatCharacter = 2;
125 FormatMask = 0xffff;
126 } else {
127 BytesPerFormatCharacter = 1;
128 FormatMask = 0xff;
129 }
130
131 //
132 // Reserve space for the Null terminator.
133 // If BufferSize is 0, this will set BufferSize to the max unsigned value
134 //
135 BufferSize--;
136
137 //
138 // Get the first character from the format string
139 //
140 FormatCharacter = (*Format | (*(Format + 1) << 8)) & FormatMask;
141
142 //
143 // Loop until the end of the format string is reached or the output buffer is full
144 //
145 while (FormatCharacter != 0 && BufferSize > 0) {
146 //
147 // Clear all the flag bits except those that may have been passed in
148 //
149 Flags &= (OUTPUT_UNICODE | FORMAT_UNICODE);
150
151 //
152 // Set the default width to zero, and the default precision to 1
153 //
154 Width = 0;
155 Precision = 1;
156 Prefix = 0;
157 Comma = FALSE;
158 ZeroPad = FALSE;
159 Count = 0;
160 Digits = 0;
161
162 switch (FormatCharacter) {
163 case '%':
164 //
165 // Parse Flags and Width
166 //
167 for (Done = FALSE; !Done; ) {
168 Format += BytesPerFormatCharacter;
169 FormatCharacter = (*Format | (*(Format + 1) << 8)) & FormatMask;
170 switch (FormatCharacter) {
171 case '.':
172 Flags |= PRECISION;
173 break;
174 case '-':
175 Flags |= LEFT_JUSTIFY;
176 break;
177 case '+':
178 Flags |= PREFIX_SIGN;
179 break;
180 case ' ':
181 Flags |= PREFIX_BLANK;
182 break;
183 case ',':
184 Flags |= COMMA_TYPE;
185 break;
186 case 'L':
187 case 'l':
188 Flags |= LONG_TYPE;
189 break;
190 case '*':
191 if ((Flags & PRECISION) == 0) {
192 Flags |= PAD_TO_WIDTH;
193 Width = VA_ARG (Marker, UINTN);
194 } else {
195 Precision = VA_ARG (Marker, UINTN);
196 }
197 break;
198 case '0':
199 if ((Flags & PRECISION) == 0) {
200 Flags |= PREFIX_ZERO;
201 }
202 case '1':
203 case '2':
204 case '3':
205 case '4':
206 case '5':
207 case '6':
208 case '7':
209 case '8':
210 case '9':
211 for (Count = 0; ((FormatCharacter >= '0') && (FormatCharacter <= '9')); ){
212 Count = (Count * 10) + FormatCharacter - '0';
213 Format += BytesPerFormatCharacter;
214 FormatCharacter = (*Format | (*(Format + 1) << 8)) & FormatMask;
215 }
216 Format -= BytesPerFormatCharacter;
217 if ((Flags & PRECISION) == 0) {
218 Flags |= PAD_TO_WIDTH;
219 Width = Count;
220 } else {
221 Precision = Count;
222 }
223 break;
224 default:
225 Done = TRUE;
226 break;
227 }
228 }
229
230 //
231 // Limit the maximum field width to the remaining characters in the output buffer
232 //
233 if (Width > BufferSize) {
234 Width = BufferSize;
235 }
236
237 //
238 // Handle each argument type
239 //
240 switch (FormatCharacter) {
241 case 'X':
242 Flags |= PREFIX_ZERO;
243 //
244 // break skiped on purpose
245 //
246 case 'x':
247 Flags |= RADIX_HEX;
248 //
249 // break skiped on purpose
250 //
251 case 'd':
252 if ((Flags & LONG_TYPE) == 0) {
253 Value = (VA_ARG (Marker, INTN));
254 } else {
255 Value = VA_ARG (Marker, INT64);
256 }
257 if ((Flags & PREFIX_BLANK) != 0) {
258 Prefix = ' ';
259 }
260 if ((Flags & PREFIX_SIGN) != 0) {
261 Prefix = '+';
262 }
263 if ((Flags & COMMA_TYPE) != 0) {
264 Comma = TRUE;
265 }
266 if ((Flags & RADIX_HEX) == 0) {
267 Radix = 10;
268 if (Comma) {
269 Flags &= (~PREFIX_ZERO);
270 Precision = 1;
271 }
272 if (Value < 0) {
273 Flags |= PREFIX_SIGN;
274 Prefix = '-';
275 Value = -Value;
276 }
277 } else {
278 Radix = 16;
279 Comma = FALSE;
280 if ((Flags & LONG_TYPE) == 0 && Value < 0) {
281 Value = (UINTN)Value;
282 }
283 }
284 //
285 // Convert Value to a reversed string
286 //
287 Count = BasePrintLibValueToString (ValueBuffer, Value, Radix);
288 if (Value == 0 && Precision == 0) {
289 Count = 0;
290 }
291 ArgumentString = (CHAR8 *)ValueBuffer + Count;
292 Digits = 3 - (Count % 3);
293 if (Comma && Count != 0) {
294 Count += ((Count - 1) / 3);
295 }
296 if (Prefix != 0) {
297 Count++;
298 }
299 Flags |= ARGUMENT_REVERSED;
300 ZeroPad = TRUE;
301 if ((Flags & PREFIX_ZERO) != 0) {
302 if ((Flags & PAD_TO_WIDTH) != 0) {
303 if ((Flags & PRECISION) == 0) {
304 Precision = Width;
305 }
306 }
307 }
308 break;
309
310 case 's':
311 case 'S':
312 Flags |= ARGUMENT_UNICODE;
313 //
314 // break skipped on purpose
315 //
316 case 'a':
317 ArgumentString = (CHAR8 *)VA_ARG (Marker, CHAR8 *);
318 if (ArgumentString == NULL) {
319 Flags &= (~ARGUMENT_UNICODE);
320 ArgumentString = "<null string>";
321 }
322 break;
323
324 case 'c':
325 Character = VA_ARG (Marker, UINTN) & 0xffff;
326 ArgumentString = (CHAR8 *)&Character;
327 Flags |= ARGUMENT_UNICODE;
328 break;
329
330 case 'g':
331 TmpGuid = VA_ARG (Marker, GUID *);
332 if (TmpGuid == NULL) {
333 ArgumentString = "<null guid>";
334 } else {
335 BasePrintLibSPrint (
336 ValueBuffer,
337 0,
338 0,
339 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
340 TmpGuid->Data1,
341 TmpGuid->Data2,
342 TmpGuid->Data3,
343 TmpGuid->Data4[0],
344 TmpGuid->Data4[1],
345 TmpGuid->Data4[2],
346 TmpGuid->Data4[3],
347 TmpGuid->Data4[4],
348 TmpGuid->Data4[5],
349 TmpGuid->Data4[6],
350 TmpGuid->Data4[7]
351 );
352 ArgumentString = ValueBuffer;
353 }
354 break;
355
356 case 't':
357 TmpTime = VA_ARG (Marker, TIME *);
358 if (TmpTime == NULL) {
359 ArgumentString = "<null time>";
360 } else {
361 BasePrintLibSPrint (
362 ValueBuffer,
363 0,
364 0,
365 "%02d/%02d/%04d %02d:%02d",
366 TmpTime->Month,
367 TmpTime->Day,
368 TmpTime->Year,
369 TmpTime->Hour,
370 TmpTime->Minute
371 );
372 ArgumentString = ValueBuffer;
373 }
374 break;
375
376 case 'r':
377 Status = VA_ARG (Marker, RETURN_STATUS);
378 ArgumentString = ValueBuffer;
379 for (Index = 0; StatusString[Index].String != NULL; Index++) {
380 if (Status == StatusString[Index].Status) {
381 ArgumentString = StatusString[Index].String;
382 }
383 }
384 if (ArgumentString == ValueBuffer) {
385 BasePrintLibSPrint ((CHAR8 *) ValueBuffer, 0, 0, "%08X", Status);
386 }
387 break;
388
389 case '%':
390 default:
391 //
392 // if the type is '%' or unknown, then print it to the screen
393 //
394 ArgumentString = (CHAR8 *)&FormatCharacter;
395 Flags |= ARGUMENT_UNICODE;
396 break;
397 }
398 break;
399 case '\n':
400 ArgumentString = "\r\n";
401 break;
402 default:
403 ArgumentString = (CHAR8 *)&FormatCharacter;
404 Flags |= ARGUMENT_UNICODE;
405 break;
406 }
407
408 //
409 // Retrieve the ArgumentString attriubutes
410 //
411 if ((Flags & ARGUMENT_UNICODE) != 0) {
412 ArgumentMask = 0xffff;
413 BytesPerArgumentCharacter = 2;
414 } else {
415 ArgumentMask = 0xff;
416 BytesPerArgumentCharacter = 1;
417 }
418 if ((Flags & ARGUMENT_REVERSED) != 0) {
419 BytesPerArgumentCharacter = -BytesPerArgumentCharacter;
420 } else {
421 //
422 // Compute the number of characters in ArgumentString and store it in Count
423 // ArgumentString is either null-terminated, or it contains Precision characters
424 //
425 for (Count = 0; Count < Precision || ((Flags & PRECISION) == 0); Count++) {
426 ArgumentCharacter = ((ArgumentString[Count * BytesPerArgumentCharacter] & 0xff) | ((ArgumentString[Count * BytesPerArgumentCharacter + 1]) << 8)) & ArgumentMask;
427 if (ArgumentCharacter == 0) {
428 break;
429 }
430 }
431 }
432
433 //
434 // Limit the length of the string to append to the remaining characters in the output buffer
435 //
436 if (Count > BufferSize) {
437 Count = BufferSize;
438 }
439 if (Precision < Count) {
440 Precision = Count;
441 }
442
443 //
444 // Pad before the string
445 //
446 if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH)) {
447 Buffer = BasePrintLibFillBuffer (Buffer, Width - Precision, ' ', BytesPerOutputCharacter);
448 }
449
450 if (ZeroPad) {
451 if (Prefix != 0) {
452 Buffer = BasePrintLibFillBuffer (Buffer, 1, Prefix, BytesPerOutputCharacter);
453 }
454 Buffer = BasePrintLibFillBuffer (Buffer, Precision - Count, '0', BytesPerOutputCharacter);
455 } else {
456 Buffer = BasePrintLibFillBuffer (Buffer, Precision - Count, ' ', BytesPerOutputCharacter);
457 if (Prefix != 0) {
458 Buffer = BasePrintLibFillBuffer (Buffer, 1, Prefix, BytesPerOutputCharacter);
459 }
460 }
461
462 //
463 // Output the Prefix character if it is present
464 //
465 Index = 0;
466 if (Prefix) {
467 Index++;
468 }
469
470 //
471 // Copy the string into the output buffer performing the required type conversions
472 //
473 while (Index < Count) {
474 ArgumentCharacter = ((*ArgumentString & 0xff) | (*(ArgumentString + 1) << 8)) & ArgumentMask;
475
476 Buffer = BasePrintLibFillBuffer (Buffer, 1, ArgumentCharacter, BytesPerOutputCharacter);
477 ArgumentString += BytesPerArgumentCharacter;
478 Index++;
479 if (Comma) {
480 Digits++;
481 if (Digits == 3) {
482 Digits = 0;
483 Index++;
484 if (Index < Count) {
485 Buffer = BasePrintLibFillBuffer (Buffer, 1, ',', BytesPerOutputCharacter);
486 }
487 }
488 }
489 }
490
491 //
492 // Pad after the string
493 //
494 if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH | LEFT_JUSTIFY)) {
495 Buffer = BasePrintLibFillBuffer (Buffer, Width - Precision, ' ', BytesPerOutputCharacter);
496 }
497
498 //
499 // Reduce the number of characters
500 //
501 BufferSize -= Count;
502
503 //
504 // Get the next character from the format string
505 //
506 Format += BytesPerFormatCharacter;
507
508 //
509 // Get the next character from the format string
510 //
511 FormatCharacter = (*Format | (*(Format + 1) << 8)) & FormatMask;
512 }
513
514 //
515 // Null terminate the Unicode or ASCII string
516 //
517 Buffer = BasePrintLibFillBuffer (Buffer, 1, 0, BytesPerOutputCharacter);
518
519 return ((Buffer - OriginalBuffer) / BytesPerOutputCharacter);
520 }
521
522 UINTN
523 BasePrintLibSPrint (
524 OUT CHAR8 *StartOfBuffer,
525 IN UINTN BufferSize,
526 IN UINTN Flags,
527 IN CONST CHAR8 *FormatString,
528 ...
529 )
530 {
531 VA_LIST Marker;
532
533 VA_START (Marker, FormatString);
534 return BasePrintLibVSPrint (StartOfBuffer, BufferSize, Flags, FormatString, Marker);
535 }
536
537 UINTN
538 EFIAPI
539 UnicodeVSPrint (
540 OUT CHAR16 *StartOfBuffer,
541 IN UINTN BufferSize,
542 IN CONST CHAR16 *FormatString,
543 IN VA_LIST Marker
544 )
545 {
546 return BasePrintLibVSPrint ((CHAR8 *)StartOfBuffer, BufferSize >> 1, FORMAT_UNICODE | OUTPUT_UNICODE, (CHAR8 *)FormatString, Marker);
547 }
548
549 UINTN
550 EFIAPI
551 UnicodeSPrint (
552 OUT CHAR16 *StartOfBuffer,
553 IN UINTN BufferSize,
554 IN CONST CHAR16 *FormatString,
555 ...
556 )
557 {
558 VA_LIST Marker;
559
560 VA_START (Marker, FormatString);
561 return UnicodeVSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
562 }
563
564 UINTN
565 EFIAPI
566 UnicodeVSPrintAsciiFormat (
567 OUT CHAR16 *StartOfBuffer,
568 IN UINTN BufferSize,
569 IN CONST CHAR8 *FormatString,
570 IN VA_LIST Marker
571 )
572 {
573 return BasePrintLibVSPrint ((CHAR8 *)StartOfBuffer, BufferSize >> 1, OUTPUT_UNICODE,FormatString, Marker);
574 }
575
576 UINTN
577 EFIAPI
578 UnicodeSPrintAsciiFormat (
579 OUT CHAR16 *StartOfBuffer,
580 IN UINTN BufferSize,
581 IN CONST CHAR8 *FormatString,
582 ...
583 )
584 {
585 VA_LIST Marker;
586
587 VA_START (Marker, FormatString);
588 return UnicodeVSPrintAsciiFormat (StartOfBuffer, BufferSize >> 1, FormatString, Marker);
589 }
590
591 UINTN
592 EFIAPI
593 AsciiVSPrint (
594 OUT CHAR8 *StartOfBuffer,
595 IN UINTN BufferSize,
596 IN CONST CHAR8 *FormatString,
597 IN VA_LIST Marker
598 )
599 {
600 return BasePrintLibVSPrint (StartOfBuffer, BufferSize, 0, FormatString, Marker);
601 }
602
603 UINTN
604 EFIAPI
605 AsciiSPrint (
606 OUT CHAR8 *StartOfBuffer,
607 IN UINTN BufferSize,
608 IN CONST CHAR8 *FormatString,
609 ...
610 )
611 {
612 VA_LIST Marker;
613
614 VA_START (Marker, FormatString);
615 return AsciiVSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
616 }
617
618 UINTN
619 EFIAPI
620 AsciiVSPrintUnicodeFormat (
621 OUT CHAR8 *StartOfBuffer,
622 IN UINTN BufferSize,
623 IN CONST CHAR16 *FormatString,
624 IN VA_LIST Marker
625 )
626 {
627 return BasePrintLibVSPrint (StartOfBuffer, BufferSize, FORMAT_UNICODE, (CHAR8 *)FormatString, Marker);
628 }
629
630 UINTN
631 EFIAPI
632 AsciiSPrintUnicodeFormat (
633 OUT CHAR8 *StartOfBuffer,
634 IN UINTN BufferSize,
635 IN CONST CHAR16 *FormatString,
636 ...
637 )
638 {
639 VA_LIST Marker;
640
641 VA_START (Marker, FormatString);
642 return AsciiVSPrintUnicodeFormat (StartOfBuffer, BufferSize, FormatString, Marker);
643 }
644
645 UINTN
646 EFIAPI
647 UnicodeValueToString (
648 IN OUT CHAR16 *Buffer,
649 IN UINTN Flags,
650 IN INT64 Value,
651 IN UINTN Width
652 )
653 {
654 return BasePrintLibConvertValueToString ((CHAR8 *)Buffer, Flags, Value, Width, 2);
655 }
656
657 UINTN
658 EFIAPI
659 AsciiValueToString (
660 IN OUT CHAR8 *Buffer,
661 IN UINTN Flags,
662 IN INT64 Value,
663 IN UINTN Width
664 )
665 {
666 return BasePrintLibConvertValueToString ((CHAR8 *)Buffer, Flags, Value, Width, 1);
667 }