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