]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BasePrintLib/PrintLibInternal.c
MdeModulePkg: Refine the services comments in EFI_PRINT2_PROTOCOL
[mirror_edk2.git] / MdePkg / Library / BasePrintLib / PrintLibInternal.c
1 /** @file
2 Print Library internal worker functions.
3
4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
5 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 **/
14
15 #include "PrintLibInternal.h"
16
17 #define WARNING_STATUS_NUMBER 5
18 #define ERROR_STATUS_NUMBER 33
19
20 //
21 // Safe print checks
22 //
23 #define RSIZE_MAX (PcdGet32 (PcdMaximumUnicodeStringLength))
24 #define ASCII_RSIZE_MAX (PcdGet32 (PcdMaximumAsciiStringLength))
25
26 #define SAFE_PRINT_CONSTRAINT_CHECK(Expression, RetVal) \
27 do { \
28 ASSERT (Expression); \
29 if (!(Expression)) { \
30 return RetVal; \
31 } \
32 } while (FALSE)
33
34 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
35
36 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 * CONST mStatusString[] = {
37 "Success", // RETURN_SUCCESS = 0
38 "Warning Unknown Glyph", // RETURN_WARN_UNKNOWN_GLYPH = 1
39 "Warning Delete Failure", // RETURN_WARN_DELETE_FAILURE = 2
40 "Warning Write Failure", // RETURN_WARN_WRITE_FAILURE = 3
41 "Warning Buffer Too Small", // RETURN_WARN_BUFFER_TOO_SMALL = 4
42 "Warning Stale Data", // RETURN_WARN_STALE_DATA = 5
43 "Load Error", // RETURN_LOAD_ERROR = 1 | MAX_BIT
44 "Invalid Parameter", // RETURN_INVALID_PARAMETER = 2 | MAX_BIT
45 "Unsupported", // RETURN_UNSUPPORTED = 3 | MAX_BIT
46 "Bad Buffer Size", // RETURN_BAD_BUFFER_SIZE = 4 | MAX_BIT
47 "Buffer Too Small", // RETURN_BUFFER_TOO_SMALL, = 5 | MAX_BIT
48 "Not Ready", // RETURN_NOT_READY = 6 | MAX_BIT
49 "Device Error", // RETURN_DEVICE_ERROR = 7 | MAX_BIT
50 "Write Protected", // RETURN_WRITE_PROTECTED = 8 | MAX_BIT
51 "Out of Resources", // RETURN_OUT_OF_RESOURCES = 9 | MAX_BIT
52 "Volume Corrupt", // RETURN_VOLUME_CORRUPTED = 10 | MAX_BIT
53 "Volume Full", // RETURN_VOLUME_FULL = 11 | MAX_BIT
54 "No Media", // RETURN_NO_MEDIA = 12 | MAX_BIT
55 "Media changed", // RETURN_MEDIA_CHANGED = 13 | MAX_BIT
56 "Not Found", // RETURN_NOT_FOUND = 14 | MAX_BIT
57 "Access Denied", // RETURN_ACCESS_DENIED = 15 | MAX_BIT
58 "No Response", // RETURN_NO_RESPONSE = 16 | MAX_BIT
59 "No mapping", // RETURN_NO_MAPPING = 17 | MAX_BIT
60 "Time out", // RETURN_TIMEOUT = 18 | MAX_BIT
61 "Not started", // RETURN_NOT_STARTED = 19 | MAX_BIT
62 "Already started", // RETURN_ALREADY_STARTED = 20 | MAX_BIT
63 "Aborted", // RETURN_ABORTED = 21 | MAX_BIT
64 "ICMP Error", // RETURN_ICMP_ERROR = 22 | MAX_BIT
65 "TFTP Error", // RETURN_TFTP_ERROR = 23 | MAX_BIT
66 "Protocol Error", // RETURN_PROTOCOL_ERROR = 24 | MAX_BIT
67 "Incompatible Version", // RETURN_INCOMPATIBLE_VERSION = 25 | MAX_BIT
68 "Security Violation", // RETURN_SECURITY_VIOLATION = 26 | MAX_BIT
69 "CRC Error", // RETURN_CRC_ERROR = 27 | MAX_BIT
70 "End of Media", // RETURN_END_OF_MEDIA = 28 | MAX_BIT
71 "Reserved (29)", // RESERVED = 29 | MAX_BIT
72 "Reserved (30)", // RESERVED = 30 | MAX_BIT
73 "End of File", // RETURN_END_OF_FILE = 31 | MAX_BIT
74 "Invalid Language", // RETURN_INVALID_LANGUAGE = 32 | MAX_BIT
75 "Compromised Data" // RETURN_COMPROMISED_DATA = 33 | MAX_BIT
76 };
77
78
79 /**
80 Internal function that places the character into the Buffer.
81
82 Internal function that places ASCII or Unicode character into the Buffer.
83
84 @param Buffer The buffer to place the Unicode or ASCII string.
85 @param EndBuffer The end of the input Buffer. No characters will be
86 placed after that.
87 @param Length The count of character to be placed into Buffer.
88 (Negative value indicates no buffer fill.)
89 @param Character The character to be placed into Buffer.
90 @param Increment The character increment in Buffer.
91
92 @return Buffer.
93
94 **/
95 CHAR8 *
96 BasePrintLibFillBuffer (
97 OUT CHAR8 *Buffer,
98 IN CHAR8 *EndBuffer,
99 IN INTN Length,
100 IN UINTN Character,
101 IN INTN Increment
102 )
103 {
104 INTN Index;
105
106 for (Index = 0; Index < Length && Buffer < EndBuffer; Index++) {
107 *Buffer = (CHAR8) Character;
108 if (Increment != 1) {
109 *(Buffer + 1) = (CHAR8)(Character >> 8);
110 }
111 Buffer += Increment;
112 }
113
114 return Buffer;
115 }
116
117 /**
118 Internal function that convert a number to a string in Buffer.
119
120 Print worker function that converts a decimal or hexadecimal number to an ASCII string in Buffer.
121
122 @param Buffer Location to place the ASCII string of Value.
123 @param Value The value to convert to a Decimal or Hexadecimal string in Buffer.
124 @param Radix Radix of the value
125
126 @return A pointer to the end of buffer filled with ASCII string.
127
128 **/
129 CHAR8 *
130 BasePrintLibValueToString (
131 IN OUT CHAR8 *Buffer,
132 IN INT64 Value,
133 IN UINTN Radix
134 )
135 {
136 UINT32 Remainder;
137
138 //
139 // Loop to convert one digit at a time in reverse order
140 //
141 *Buffer = 0;
142 do {
143 Value = (INT64)DivU64x32Remainder ((UINT64)Value, (UINT32)Radix, &Remainder);
144 *(++Buffer) = mHexStr[Remainder];
145 } while (Value != 0);
146
147 //
148 // Return pointer of the end of filled buffer.
149 //
150 return Buffer;
151 }
152
153 /**
154 Internal function that converts a decimal value to a Null-terminated string.
155
156 Converts the decimal number specified by Value to a Null-terminated
157 string specified by Buffer containing at most Width characters.
158 If Width is 0 then a width of MAXIMUM_VALUE_CHARACTERS is assumed.
159 The total number of characters placed in Buffer is returned.
160 If the conversion contains more than Width characters, then only the first
161 Width characters are returned, and the total number of characters
162 required to perform the conversion is returned.
163 Additional conversion parameters are specified in Flags.
164 The Flags bit LEFT_JUSTIFY is always ignored.
165 All conversions are left justified in Buffer.
166 If Width is 0, PREFIX_ZERO is ignored in Flags.
167 If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and commas
168 are inserted every 3rd digit starting from the right.
169 If Value is < 0, then the fist character in Buffer is a '-'.
170 If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,
171 then Buffer is padded with '0' characters so the combination of the optional '-'
172 sign character, '0' characters, digit characters for Value, and the Null-terminator
173 add up to Width characters.
174
175 If Buffer is NULL, then ASSERT().
176 If unsupported bits are set in Flags, then ASSERT().
177 If Width >= MAXIMUM_VALUE_CHARACTERS, then ASSERT()
178
179 @param Buffer The pointer to the output buffer for the produced Null-terminated
180 string.
181 @param Flags The bitmask of flags that specify left justification, zero pad,
182 and commas.
183 @param Value The 64-bit signed value to convert to a string.
184 @param Width The maximum number of characters to place in Buffer, not including
185 the Null-terminator.
186 @param Increment The character increment in Buffer.
187
188 @return Total number of characters required to perform the conversion.
189
190 **/
191 UINTN
192 BasePrintLibConvertValueToString (
193 IN OUT CHAR8 *Buffer,
194 IN UINTN Flags,
195 IN INT64 Value,
196 IN UINTN Width,
197 IN UINTN Increment
198 )
199 {
200 CHAR8 *OriginalBuffer;
201 CHAR8 *EndBuffer;
202 CHAR8 ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
203 CHAR8 *ValueBufferPtr;
204 UINTN Count;
205 UINTN Digits;
206 UINTN Index;
207 UINTN Radix;
208
209 //
210 // Make sure Buffer is not NULL and Width < MAXIMUM
211 //
212 ASSERT (Buffer != NULL);
213 ASSERT (Width < MAXIMUM_VALUE_CHARACTERS);
214 //
215 // Make sure Flags can only contain supported bits.
216 //
217 ASSERT ((Flags & ~(LEFT_JUSTIFY | COMMA_TYPE | PREFIX_ZERO | RADIX_HEX)) == 0);
218
219 //
220 // If both COMMA_TYPE and RADIX_HEX are set, then ASSERT ()
221 //
222 ASSERT (((Flags & COMMA_TYPE) == 0) || ((Flags & RADIX_HEX) == 0));
223
224 OriginalBuffer = Buffer;
225
226 //
227 // Width is 0 or COMMA_TYPE is set, PREFIX_ZERO is ignored.
228 //
229 if (Width == 0 || (Flags & COMMA_TYPE) != 0) {
230 Flags &= ~((UINTN) PREFIX_ZERO);
231 }
232 //
233 // If Width is 0 then a width of MAXIMUM_VALUE_CHARACTERS is assumed.
234 //
235 if (Width == 0) {
236 Width = MAXIMUM_VALUE_CHARACTERS - 1;
237 }
238 //
239 // Set the tag for the end of the input Buffer.
240 //
241 EndBuffer = Buffer + Width * Increment;
242
243 //
244 // Convert decimal negative
245 //
246 if ((Value < 0) && ((Flags & RADIX_HEX) == 0)) {
247 Value = -Value;
248 Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, '-', Increment);
249 Width--;
250 }
251
252 //
253 // Count the length of the value string.
254 //
255 Radix = ((Flags & RADIX_HEX) == 0)? 10 : 16;
256 ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, Value, Radix);
257 Count = ValueBufferPtr - ValueBuffer;
258
259 //
260 // Append Zero
261 //
262 if ((Flags & PREFIX_ZERO) != 0) {
263 Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Count, '0', Increment);
264 }
265
266 //
267 // Print Comma type for every 3 characters
268 //
269 Digits = Count % 3;
270 if (Digits != 0) {
271 Digits = 3 - Digits;
272 }
273 for (Index = 0; Index < Count; Index++) {
274 Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, *ValueBufferPtr--, Increment);
275 if ((Flags & COMMA_TYPE) != 0) {
276 Digits++;
277 if (Digits == 3) {
278 Digits = 0;
279 if ((Index + 1) < Count) {
280 Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', Increment);
281 }
282 }
283 }
284 }
285
286 //
287 // Print Null-terminator
288 //
289 BasePrintLibFillBuffer (Buffer, EndBuffer + Increment, 1, 0, Increment);
290
291 return ((Buffer - OriginalBuffer) / Increment);
292 }
293
294 /**
295 Worker function that produces a Null-terminated string in an output buffer
296 based on a Null-terminated format string and a VA_LIST argument list.
297
298 VSPrint function to process format and place the results in Buffer. Since a
299 VA_LIST is used this routine allows the nesting of Vararg routines. Thus
300 this is the main print working routine.
301
302 If COUNT_ONLY_NO_PRINT is set in Flags, Buffer will not be modified at all.
303
304 @param[out] Buffer The character buffer to print the results of the
305 parsing of Format into.
306 @param[in] BufferSize The maximum number of characters to put into
307 buffer.
308 @param[in] Flags Initial flags value.
309 Can only have FORMAT_UNICODE, OUTPUT_UNICODE,
310 and COUNT_ONLY_NO_PRINT set.
311 @param[in] Format A Null-terminated format string.
312 @param[in] VaListMarker VA_LIST style variable argument list consumed by
313 processing Format.
314 @param[in] BaseListMarker BASE_LIST style variable argument list consumed
315 by processing Format.
316
317 @return The number of characters printed not including the Null-terminator.
318 If COUNT_ONLY_NO_PRINT was set returns the same, but without any
319 modification to Buffer.
320
321 **/
322 UINTN
323 BasePrintLibSPrintMarker (
324 OUT CHAR8 *Buffer,
325 IN UINTN BufferSize,
326 IN UINTN Flags,
327 IN CONST CHAR8 *Format,
328 IN VA_LIST VaListMarker, OPTIONAL
329 IN BASE_LIST BaseListMarker OPTIONAL
330 )
331 {
332 CHAR8 *OriginalBuffer;
333 CHAR8 *EndBuffer;
334 CHAR8 ValueBuffer[MAXIMUM_VALUE_CHARACTERS];
335 UINT32 BytesPerOutputCharacter;
336 UINTN BytesPerFormatCharacter;
337 UINTN FormatMask;
338 UINTN FormatCharacter;
339 UINTN Width;
340 UINTN Precision;
341 INT64 Value;
342 CONST CHAR8 *ArgumentString;
343 UINTN Character;
344 GUID *TmpGuid;
345 TIME *TmpTime;
346 UINTN Count;
347 UINTN ArgumentMask;
348 INTN BytesPerArgumentCharacter;
349 UINTN ArgumentCharacter;
350 BOOLEAN Done;
351 UINTN Index;
352 CHAR8 Prefix;
353 BOOLEAN ZeroPad;
354 BOOLEAN Comma;
355 UINTN Digits;
356 UINTN Radix;
357 RETURN_STATUS Status;
358 UINT32 GuidData1;
359 UINT16 GuidData2;
360 UINT16 GuidData3;
361 UINTN LengthToReturn;
362
363 //
364 // If you change this code be sure to match the 2 versions of this function.
365 // Nearly identical logic is found in the BasePrintLib and
366 // DxePrintLibPrint2Protocol (both PrintLib instances).
367 //
368
369 //
370 // 1. Buffer shall not be a null pointer when both BufferSize > 0 and
371 // COUNT_ONLY_NO_PRINT is not set in Flags.
372 //
373 if ((BufferSize > 0) && ((Flags & COUNT_ONLY_NO_PRINT) == 0)) {
374 SAFE_PRINT_CONSTRAINT_CHECK ((Buffer != NULL), 0);
375 }
376
377 //
378 // 2. Format shall not be a null pointer when BufferSize > 0 or when
379 // COUNT_ONLY_NO_PRINT is set in Flags.
380 //
381 if ((BufferSize > 0) || ((Flags & COUNT_ONLY_NO_PRINT) != 0)) {
382 SAFE_PRINT_CONSTRAINT_CHECK ((Format != NULL), 0);
383 }
384
385 //
386 // 3. BufferSize shall not be greater than RSIZE_MAX for Unicode output or
387 // ASCII_RSIZE_MAX for Ascii output.
388 //
389 if ((Flags & OUTPUT_UNICODE) != 0) {
390 if (RSIZE_MAX != 0) {
391 SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= RSIZE_MAX), 0);
392 }
393 BytesPerOutputCharacter = 2;
394 } else {
395 if (ASCII_RSIZE_MAX != 0) {
396 SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= ASCII_RSIZE_MAX), 0);
397 }
398 BytesPerOutputCharacter = 1;
399 }
400
401 //
402 // 4. Format shall not contain more than RSIZE_MAX Unicode characters or
403 // ASCII_RSIZE_MAX Ascii characters.
404 //
405 if ((Flags & FORMAT_UNICODE) != 0) {
406 if (RSIZE_MAX != 0) {
407 SAFE_PRINT_CONSTRAINT_CHECK ((StrnLenS ((CHAR16 *)Format, RSIZE_MAX + 1) <= RSIZE_MAX), 0);
408 }
409 BytesPerFormatCharacter = 2;
410 FormatMask = 0xffff;
411 } else {
412 if (ASCII_RSIZE_MAX != 0) {
413 SAFE_PRINT_CONSTRAINT_CHECK ((AsciiStrnLenS (Format, ASCII_RSIZE_MAX + 1) <= ASCII_RSIZE_MAX), 0);
414 }
415 BytesPerFormatCharacter = 1;
416 FormatMask = 0xff;
417 }
418
419 if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
420 if (BufferSize == 0) {
421 Buffer = NULL;
422 }
423 } else {
424 //
425 // We can run without a Buffer for counting only.
426 //
427 if (BufferSize == 0) {
428 return 0;
429 }
430 }
431
432 LengthToReturn = 0;
433 EndBuffer = NULL;
434 OriginalBuffer = NULL;
435
436 //
437 // Reserve space for the Null terminator.
438 //
439 if (Buffer != NULL) {
440 BufferSize--;
441 OriginalBuffer = Buffer;
442
443 //
444 // Set the tag for the end of the input Buffer.
445 //
446 EndBuffer = Buffer + BufferSize * BytesPerOutputCharacter;
447 }
448
449 //
450 // Get the first character from the format string
451 //
452 FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
453
454 //
455 // Loop until the end of the format string is reached or the output buffer is full
456 //
457 while (FormatCharacter != 0) {
458 if ((Buffer != NULL) && (Buffer >= EndBuffer)) {
459 break;
460 }
461 //
462 // Clear all the flag bits except those that may have been passed in
463 //
464 Flags &= (UINTN) (OUTPUT_UNICODE | FORMAT_UNICODE | COUNT_ONLY_NO_PRINT);
465
466 //
467 // Set the default width to zero, and the default precision to 1
468 //
469 Width = 0;
470 Precision = 1;
471 Prefix = 0;
472 Comma = FALSE;
473 ZeroPad = FALSE;
474 Count = 0;
475 Digits = 0;
476
477 switch (FormatCharacter) {
478 case '%':
479 //
480 // Parse Flags and Width
481 //
482 for (Done = FALSE; !Done; ) {
483 Format += BytesPerFormatCharacter;
484 FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
485 switch (FormatCharacter) {
486 case '.':
487 Flags |= PRECISION;
488 break;
489 case '-':
490 Flags |= LEFT_JUSTIFY;
491 break;
492 case '+':
493 Flags |= PREFIX_SIGN;
494 break;
495 case ' ':
496 Flags |= PREFIX_BLANK;
497 break;
498 case ',':
499 Flags |= COMMA_TYPE;
500 break;
501 case 'L':
502 case 'l':
503 Flags |= LONG_TYPE;
504 break;
505 case '*':
506 if ((Flags & PRECISION) == 0) {
507 Flags |= PAD_TO_WIDTH;
508 if (BaseListMarker == NULL) {
509 Width = VA_ARG (VaListMarker, UINTN);
510 } else {
511 Width = BASE_ARG (BaseListMarker, UINTN);
512 }
513 } else {
514 if (BaseListMarker == NULL) {
515 Precision = VA_ARG (VaListMarker, UINTN);
516 } else {
517 Precision = BASE_ARG (BaseListMarker, UINTN);
518 }
519 }
520 break;
521 case '0':
522 if ((Flags & PRECISION) == 0) {
523 Flags |= PREFIX_ZERO;
524 }
525 case '1':
526 case '2':
527 case '3':
528 case '4':
529 case '5':
530 case '6':
531 case '7':
532 case '8':
533 case '9':
534 for (Count = 0; ((FormatCharacter >= '0') && (FormatCharacter <= '9')); ){
535 Count = (Count * 10) + FormatCharacter - '0';
536 Format += BytesPerFormatCharacter;
537 FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
538 }
539 Format -= BytesPerFormatCharacter;
540 if ((Flags & PRECISION) == 0) {
541 Flags |= PAD_TO_WIDTH;
542 Width = Count;
543 } else {
544 Precision = Count;
545 }
546 break;
547
548 case '\0':
549 //
550 // Make no output if Format string terminates unexpectedly when
551 // looking up for flag, width, precision and type.
552 //
553 Format -= BytesPerFormatCharacter;
554 Precision = 0;
555 //
556 // break skipped on purpose.
557 //
558 default:
559 Done = TRUE;
560 break;
561 }
562 }
563
564 //
565 // Handle each argument type
566 //
567 switch (FormatCharacter) {
568 case 'p':
569 //
570 // Flag space, +, 0, L & l are invalid for type p.
571 //
572 Flags &= ~((UINTN) (PREFIX_BLANK | PREFIX_SIGN | PREFIX_ZERO | LONG_TYPE));
573 if (sizeof (VOID *) > 4) {
574 Flags |= LONG_TYPE;
575 }
576 //
577 // break skipped on purpose
578 //
579 case 'X':
580 Flags |= PREFIX_ZERO;
581 //
582 // break skipped on purpose
583 //
584 case 'x':
585 Flags |= RADIX_HEX;
586 //
587 // break skipped on purpose
588 //
589 case 'u':
590 if ((Flags & RADIX_HEX) == 0) {
591 Flags &= ~((UINTN) (PREFIX_SIGN));
592 Flags |= UNSIGNED_TYPE;
593 }
594 //
595 // break skipped on purpose
596 //
597 case 'd':
598 if ((Flags & LONG_TYPE) == 0) {
599 //
600 // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
601 // This assumption is made so the format string definition is compatible with the ANSI C
602 // Specification for formatted strings. It is recommended that the Base Types be used
603 // everywhere, but in this one case, compliance with ANSI C is more important, and
604 // provides an implementation that is compatible with that largest possible set of CPU
605 // architectures. This is why the type "int" is used in this one case.
606 //
607 if (BaseListMarker == NULL) {
608 Value = VA_ARG (VaListMarker, int);
609 } else {
610 Value = BASE_ARG (BaseListMarker, int);
611 }
612 } else {
613 if (BaseListMarker == NULL) {
614 Value = VA_ARG (VaListMarker, INT64);
615 } else {
616 Value = BASE_ARG (BaseListMarker, INT64);
617 }
618 }
619 if ((Flags & PREFIX_BLANK) != 0) {
620 Prefix = ' ';
621 }
622 if ((Flags & PREFIX_SIGN) != 0) {
623 Prefix = '+';
624 }
625 if ((Flags & COMMA_TYPE) != 0) {
626 Comma = TRUE;
627 }
628 if ((Flags & RADIX_HEX) == 0) {
629 Radix = 10;
630 if (Comma) {
631 Flags &= ~((UINTN) PREFIX_ZERO);
632 Precision = 1;
633 }
634 if (Value < 0 && (Flags & UNSIGNED_TYPE) == 0) {
635 Flags |= PREFIX_SIGN;
636 Prefix = '-';
637 Value = -Value;
638 } else if ((Flags & UNSIGNED_TYPE) != 0 && (Flags & LONG_TYPE) == 0) {
639 //
640 // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
641 // This assumption is made so the format string definition is compatible with the ANSI C
642 // Specification for formatted strings. It is recommended that the Base Types be used
643 // everywhere, but in this one case, compliance with ANSI C is more important, and
644 // provides an implementation that is compatible with that largest possible set of CPU
645 // architectures. This is why the type "unsigned int" is used in this one case.
646 //
647 Value = (unsigned int)Value;
648 }
649 } else {
650 Radix = 16;
651 Comma = FALSE;
652 if ((Flags & LONG_TYPE) == 0 && Value < 0) {
653 //
654 // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".
655 // This assumption is made so the format string definition is compatible with the ANSI C
656 // Specification for formatted strings. It is recommended that the Base Types be used
657 // everywhere, but in this one case, compliance with ANSI C is more important, and
658 // provides an implementation that is compatible with that largest possible set of CPU
659 // architectures. This is why the type "unsigned int" is used in this one case.
660 //
661 Value = (unsigned int)Value;
662 }
663 }
664 //
665 // Convert Value to a reversed string
666 //
667 Count = BasePrintLibValueToString (ValueBuffer, Value, Radix) - ValueBuffer;
668 if (Value == 0 && Precision == 0) {
669 Count = 0;
670 }
671 ArgumentString = (CHAR8 *)ValueBuffer + Count;
672
673 Digits = Count % 3;
674 if (Digits != 0) {
675 Digits = 3 - Digits;
676 }
677 if (Comma && Count != 0) {
678 Count += ((Count - 1) / 3);
679 }
680 if (Prefix != 0) {
681 Count++;
682 Precision++;
683 }
684 Flags |= ARGUMENT_REVERSED;
685 ZeroPad = TRUE;
686 if ((Flags & PREFIX_ZERO) != 0) {
687 if ((Flags & LEFT_JUSTIFY) == 0) {
688 if ((Flags & PAD_TO_WIDTH) != 0) {
689 if ((Flags & PRECISION) == 0) {
690 Precision = Width;
691 }
692 }
693 }
694 }
695 break;
696
697 case 's':
698 case 'S':
699 Flags |= ARGUMENT_UNICODE;
700 //
701 // break skipped on purpose
702 //
703 case 'a':
704 if (BaseListMarker == NULL) {
705 ArgumentString = VA_ARG (VaListMarker, CHAR8 *);
706 } else {
707 ArgumentString = BASE_ARG (BaseListMarker, CHAR8 *);
708 }
709 if (ArgumentString == NULL) {
710 Flags &= ~((UINTN) ARGUMENT_UNICODE);
711 ArgumentString = "<null string>";
712 }
713 //
714 // Set the default precision for string to be zero if not specified.
715 //
716 if ((Flags & PRECISION) == 0) {
717 Precision = 0;
718 }
719 break;
720
721 case 'c':
722 if (BaseListMarker == NULL) {
723 Character = VA_ARG (VaListMarker, UINTN) & 0xffff;
724 } else {
725 Character = BASE_ARG (BaseListMarker, UINTN) & 0xffff;
726 }
727 ArgumentString = (CHAR8 *)&Character;
728 Flags |= ARGUMENT_UNICODE;
729 break;
730
731 case 'g':
732 if (BaseListMarker == NULL) {
733 TmpGuid = VA_ARG (VaListMarker, GUID *);
734 } else {
735 TmpGuid = BASE_ARG (BaseListMarker, GUID *);
736 }
737 if (TmpGuid == NULL) {
738 ArgumentString = "<null guid>";
739 } else {
740 GuidData1 = ReadUnaligned32 (&(TmpGuid->Data1));
741 GuidData2 = ReadUnaligned16 (&(TmpGuid->Data2));
742 GuidData3 = ReadUnaligned16 (&(TmpGuid->Data3));
743 BasePrintLibSPrint (
744 ValueBuffer,
745 MAXIMUM_VALUE_CHARACTERS,
746 0,
747 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
748 GuidData1,
749 GuidData2,
750 GuidData3,
751 TmpGuid->Data4[0],
752 TmpGuid->Data4[1],
753 TmpGuid->Data4[2],
754 TmpGuid->Data4[3],
755 TmpGuid->Data4[4],
756 TmpGuid->Data4[5],
757 TmpGuid->Data4[6],
758 TmpGuid->Data4[7]
759 );
760 ArgumentString = ValueBuffer;
761 }
762 break;
763
764 case 't':
765 if (BaseListMarker == NULL) {
766 TmpTime = VA_ARG (VaListMarker, TIME *);
767 } else {
768 TmpTime = BASE_ARG (BaseListMarker, TIME *);
769 }
770 if (TmpTime == NULL) {
771 ArgumentString = "<null time>";
772 } else {
773 BasePrintLibSPrint (
774 ValueBuffer,
775 MAXIMUM_VALUE_CHARACTERS,
776 0,
777 "%02d/%02d/%04d %02d:%02d",
778 TmpTime->Month,
779 TmpTime->Day,
780 TmpTime->Year,
781 TmpTime->Hour,
782 TmpTime->Minute
783 );
784 ArgumentString = ValueBuffer;
785 }
786 break;
787
788 case 'r':
789 if (BaseListMarker == NULL) {
790 Status = VA_ARG (VaListMarker, RETURN_STATUS);
791 } else {
792 Status = BASE_ARG (BaseListMarker, RETURN_STATUS);
793 }
794 ArgumentString = ValueBuffer;
795 if (RETURN_ERROR (Status)) {
796 //
797 // Clear error bit
798 //
799 Index = Status & ~MAX_BIT;
800 if (Index > 0 && Index <= ERROR_STATUS_NUMBER) {
801 ArgumentString = mStatusString [Index + WARNING_STATUS_NUMBER];
802 }
803 } else {
804 Index = Status;
805 if (Index <= WARNING_STATUS_NUMBER) {
806 ArgumentString = mStatusString [Index];
807 }
808 }
809 if (ArgumentString == ValueBuffer) {
810 BasePrintLibSPrint ((CHAR8 *) ValueBuffer, MAXIMUM_VALUE_CHARACTERS, 0, "%08X", Status);
811 }
812 break;
813
814 case '\r':
815 Format += BytesPerFormatCharacter;
816 FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
817 if (FormatCharacter == '\n') {
818 //
819 // Translate '\r\n' to '\r\n'
820 //
821 ArgumentString = "\r\n";
822 } else {
823 //
824 // Translate '\r' to '\r'
825 //
826 ArgumentString = "\r";
827 Format -= BytesPerFormatCharacter;
828 }
829 break;
830
831 case '\n':
832 //
833 // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
834 //
835 ArgumentString = "\r\n";
836 Format += BytesPerFormatCharacter;
837 FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
838 if (FormatCharacter != '\r') {
839 Format -= BytesPerFormatCharacter;
840 }
841 break;
842
843 case '%':
844 default:
845 //
846 // if the type is '%' or unknown, then print it to the screen
847 //
848 ArgumentString = (CHAR8 *)&FormatCharacter;
849 Flags |= ARGUMENT_UNICODE;
850 break;
851 }
852 break;
853
854 case '\r':
855 Format += BytesPerFormatCharacter;
856 FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
857 if (FormatCharacter == '\n') {
858 //
859 // Translate '\r\n' to '\r\n'
860 //
861 ArgumentString = "\r\n";
862 } else {
863 //
864 // Translate '\r' to '\r'
865 //
866 ArgumentString = "\r";
867 Format -= BytesPerFormatCharacter;
868 }
869 break;
870
871 case '\n':
872 //
873 // Translate '\n' to '\r\n' and '\n\r' to '\r\n'
874 //
875 ArgumentString = "\r\n";
876 Format += BytesPerFormatCharacter;
877 FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
878 if (FormatCharacter != '\r') {
879 Format -= BytesPerFormatCharacter;
880 }
881 break;
882
883 default:
884 ArgumentString = (CHAR8 *)&FormatCharacter;
885 Flags |= ARGUMENT_UNICODE;
886 break;
887 }
888
889 //
890 // Retrieve the ArgumentString attriubutes
891 //
892 if ((Flags & ARGUMENT_UNICODE) != 0) {
893 ArgumentMask = 0xffff;
894 BytesPerArgumentCharacter = 2;
895 } else {
896 ArgumentMask = 0xff;
897 BytesPerArgumentCharacter = 1;
898 }
899 if ((Flags & ARGUMENT_REVERSED) != 0) {
900 BytesPerArgumentCharacter = -BytesPerArgumentCharacter;
901 } else {
902 //
903 // Compute the number of characters in ArgumentString and store it in Count
904 // ArgumentString is either null-terminated, or it contains Precision characters
905 //
906 for (Count = 0; Count < Precision || ((Flags & PRECISION) == 0); Count++) {
907 ArgumentCharacter = ((ArgumentString[Count * BytesPerArgumentCharacter] & 0xff) | ((ArgumentString[Count * BytesPerArgumentCharacter + 1]) << 8)) & ArgumentMask;
908 if (ArgumentCharacter == 0) {
909 break;
910 }
911 }
912 }
913
914 if (Precision < Count) {
915 Precision = Count;
916 }
917
918 //
919 // Pad before the string
920 //
921 if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH)) {
922 LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
923 if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
924 Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
925 }
926 }
927
928 if (ZeroPad) {
929 if (Prefix != 0) {
930 LengthToReturn += (1 * BytesPerOutputCharacter);
931 if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
932 Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
933 }
934 }
935 LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
936 if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
937 Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, '0', BytesPerOutputCharacter);
938 }
939 } else {
940 LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);
941 if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
942 Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, ' ', BytesPerOutputCharacter);
943 }
944 if (Prefix != 0) {
945 LengthToReturn += (1 * BytesPerOutputCharacter);
946 if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
947 Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);
948 }
949 }
950 }
951
952 //
953 // Output the Prefix character if it is present
954 //
955 Index = 0;
956 if (Prefix != 0) {
957 Index++;
958 }
959
960 //
961 // Copy the string into the output buffer performing the required type conversions
962 //
963 while (Index < Count) {
964 ArgumentCharacter = ((*ArgumentString & 0xff) | (*(ArgumentString + 1) << 8)) & ArgumentMask;
965
966 LengthToReturn += (1 * BytesPerOutputCharacter);
967 if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
968 Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ArgumentCharacter, BytesPerOutputCharacter);
969 }
970 ArgumentString += BytesPerArgumentCharacter;
971 Index++;
972 if (Comma) {
973 Digits++;
974 if (Digits == 3) {
975 Digits = 0;
976 Index++;
977 if (Index < Count) {
978 LengthToReturn += (1 * BytesPerOutputCharacter);
979 if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
980 Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', BytesPerOutputCharacter);
981 }
982 }
983 }
984 }
985 }
986
987 //
988 // Pad after the string
989 //
990 if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH | LEFT_JUSTIFY)) {
991 LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);
992 if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {
993 Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);
994 }
995 }
996
997 //
998 // Get the next character from the format string
999 //
1000 Format += BytesPerFormatCharacter;
1001
1002 //
1003 // Get the next character from the format string
1004 //
1005 FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;
1006 }
1007
1008 if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {
1009 return (LengthToReturn / BytesPerOutputCharacter);
1010 }
1011
1012 ASSERT (Buffer != NULL);
1013 //
1014 // Null terminate the Unicode or ASCII string
1015 //
1016 BasePrintLibFillBuffer (Buffer, EndBuffer + BytesPerOutputCharacter, 1, 0, BytesPerOutputCharacter);
1017
1018 return ((Buffer - OriginalBuffer) / BytesPerOutputCharacter);
1019 }
1020
1021 /**
1022 Worker function that produces a Null-terminated string in an output buffer
1023 based on a Null-terminated format string and variable argument list.
1024
1025 VSPrint function to process format and place the results in Buffer. Since a
1026 VA_LIST is used this routine allows the nesting of Vararg routines. Thus
1027 this is the main print working routine
1028
1029 @param StartOfBuffer The character buffer to print the results of the parsing
1030 of Format into.
1031 @param BufferSize The maximum number of characters to put into buffer.
1032 Zero means no limit.
1033 @param Flags Initial flags value.
1034 Can only have FORMAT_UNICODE and OUTPUT_UNICODE set
1035 @param FormatString A Null-terminated format string.
1036 @param ... The variable argument list.
1037
1038 @return The number of characters printed.
1039
1040 **/
1041 UINTN
1042 EFIAPI
1043 BasePrintLibSPrint (
1044 OUT CHAR8 *StartOfBuffer,
1045 IN UINTN BufferSize,
1046 IN UINTN Flags,
1047 IN CONST CHAR8 *FormatString,
1048 ...
1049 )
1050 {
1051 VA_LIST Marker;
1052 UINTN NumberOfPrinted;
1053
1054 VA_START (Marker, FormatString);
1055 NumberOfPrinted = BasePrintLibSPrintMarker (StartOfBuffer, BufferSize, Flags, FormatString, Marker, NULL);
1056 VA_END (Marker);
1057 return NumberOfPrinted;
1058 }