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