/** @file\r
Print Library internal worker functions.\r
\r
- Copyright (c) 2006 - 2008, Intel Corporation<BR>\r
- All rights reserved. This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "PrintLibInternal.h"\r
\r
-#define WARNING_STATUS_NUMBER 4\r
-#define ERROR_STATUS_NUMBER 24\r
+#define WARNING_STATUS_NUMBER 5\r
+#define ERROR_STATUS_NUMBER 33\r
+\r
+//\r
+// Safe print checks\r
+//\r
+#define RSIZE_MAX (PcdGet32 (PcdMaximumUnicodeStringLength))\r
+#define ASCII_RSIZE_MAX (PcdGet32 (PcdMaximumAsciiStringLength))\r
+\r
+#define SAFE_PRINT_CONSTRAINT_CHECK(Expression, RetVal) \\r
+ do { \\r
+ ASSERT (Expression); \\r
+ if (!(Expression)) { \\r
+ return RetVal; \\r
+ } \\r
+ } while (FALSE)\r
\r
GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};\r
\r
-GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mStatusString[] = {\r
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 * CONST mStatusString[] = {\r
"Success", // RETURN_SUCCESS = 0\r
"Warning Unknown Glyph", // RETURN_WARN_UNKNOWN_GLYPH = 1\r
"Warning Delete Failure", // RETURN_WARN_DELETE_FAILURE = 2\r
"Warning Write Failure", // RETURN_WARN_WRITE_FAILURE = 3\r
"Warning Buffer Too Small", // RETURN_WARN_BUFFER_TOO_SMALL = 4\r
+ "Warning Stale Data", // RETURN_WARN_STALE_DATA = 5\r
"Load Error", // RETURN_LOAD_ERROR = 1 | MAX_BIT\r
"Invalid Parameter", // RETURN_INVALID_PARAMETER = 2 | MAX_BIT\r
"Unsupported", // RETURN_UNSUPPORTED = 3 | MAX_BIT\r
"Aborted", // RETURN_ABORTED = 21 | MAX_BIT\r
"ICMP Error", // RETURN_ICMP_ERROR = 22 | MAX_BIT\r
"TFTP Error", // RETURN_TFTP_ERROR = 23 | MAX_BIT\r
- "Protocol Error" // RETURN_PROTOCOL_ERROR = 24 | MAX_BIT\r
+ "Protocol Error", // RETURN_PROTOCOL_ERROR = 24 | MAX_BIT\r
+ "Incompatible Version", // RETURN_INCOMPATIBLE_VERSION = 25 | MAX_BIT\r
+ "Security Violation", // RETURN_SECURITY_VIOLATION = 26 | MAX_BIT\r
+ "CRC Error", // RETURN_CRC_ERROR = 27 | MAX_BIT\r
+ "End of Media", // RETURN_END_OF_MEDIA = 28 | MAX_BIT\r
+ "Reserved (29)", // RESERVED = 29 | MAX_BIT\r
+ "Reserved (30)", // RESERVED = 30 | MAX_BIT\r
+ "End of File", // RETURN_END_OF_FILE = 31 | MAX_BIT\r
+ "Invalid Language", // RETURN_INVALID_LANGUAGE = 32 | MAX_BIT\r
+ "Compromised Data" // RETURN_COMPROMISED_DATA = 33 | MAX_BIT\r
};\r
\r
\r
\r
Internal function that places ASCII or Unicode character into the Buffer.\r
\r
- @param Buffer Buffer to place the Unicode or ASCII string.\r
+ @param Buffer The buffer to place the Unicode or ASCII string.\r
@param EndBuffer The end of the input Buffer. No characters will be\r
- placed after that. \r
- @param Length Count of character to be placed into Buffer.\r
- @param Character Character to be placed into Buffer.\r
- @param Increment Character increment in Buffer.\r
+ placed after that.\r
+ @param Length The count of character to be placed into Buffer.\r
+ (Negative value indicates no buffer fill.)\r
+ @param Character The character to be placed into Buffer.\r
+ @param Increment The character increment in Buffer.\r
\r
- @return Buffer Buffer filled with the input Character.\r
+ @return Buffer.\r
\r
**/\r
CHAR8 *\r
INTN Index;\r
\r
for (Index = 0; Index < Length && Buffer < EndBuffer; Index++) {\r
- *Buffer = (CHAR8) Character;\r
- *(Buffer + 1) = (CHAR8) (Character >> 8);\r
- Buffer += Increment;\r
+ *Buffer = (CHAR8) Character;\r
+ if (Increment != 1) {\r
+ *(Buffer + 1) = (CHAR8)(Character >> 8);\r
+ }\r
+ Buffer += Increment;\r
}\r
+\r
return Buffer;\r
}\r
\r
/**\r
- Internal function that convert a decimal number to a string in Buffer.\r
+ Internal function that convert a number to a string in Buffer.\r
\r
- Print worker function that convert a decimal number to a string in Buffer.\r
+ Print worker function that converts a decimal or hexadecimal number to an ASCII string in Buffer.\r
\r
- @param Buffer Location to place the Unicode or ASCII string of Value.\r
- @param Value Value to convert to a Decimal or Hexidecimal string in Buffer.\r
+ @param Buffer Location to place the ASCII string of Value.\r
+ @param Value The value to convert to a Decimal or Hexadecimal string in Buffer.\r
@param Radix Radix of the value\r
\r
- @return Number of characters printed.\r
+ @return A pointer to the end of buffer filled with ASCII string.\r
\r
**/\r
-UINTN\r
+CHAR8 *\r
BasePrintLibValueToString (\r
- IN OUT CHAR8 *Buffer, \r
- IN INT64 Value, \r
+ IN OUT CHAR8 *Buffer,\r
+ IN INT64 Value,\r
IN UINTN Radix\r
)\r
{\r
- UINTN Digits;\r
UINT32 Remainder;\r
\r
//\r
// Loop to convert one digit at a time in reverse order\r
//\r
- *(Buffer++) = 0;\r
- Digits = 0;\r
+ *Buffer = 0;\r
do {\r
Value = (INT64)DivU64x32Remainder ((UINT64)Value, (UINT32)Radix, &Remainder);\r
- *(Buffer++) = mHexStr[Remainder];\r
- Digits++;\r
+ *(++Buffer) = mHexStr[Remainder];\r
} while (Value != 0);\r
\r
//\r
- // the length of Buffer string converted from Value\r
+ // Return pointer of the end of filled buffer.\r
//\r
- return Digits;\r
+ return Buffer;\r
}\r
\r
/**\r
Internal function that converts a decimal value to a Null-terminated string.\r
- \r
- Converts the decimal number specified by Value to a Null-terminated \r
+\r
+ Converts the decimal number specified by Value to a Null-terminated\r
string specified by Buffer containing at most Width characters.\r
If Width is 0 then a width of MAXIMUM_VALUE_CHARACTERS is assumed.\r
The total number of characters placed in Buffer is returned.\r
If the conversion contains more than Width characters, then only the first\r
- Width characters are returned, and the total number of characters \r
+ Width characters are returned, and the total number of characters\r
required to perform the conversion is returned.\r
- Additional conversion parameters are specified in Flags. \r
+ Additional conversion parameters are specified in Flags.\r
The Flags bit LEFT_JUSTIFY is always ignored.\r
All conversions are left justified in Buffer.\r
If Width is 0, PREFIX_ZERO is ignored in Flags.\r
If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and commas\r
are inserted every 3rd digit starting from the right.\r
If Value is < 0, then the fist character in Buffer is a '-'.\r
- If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored, \r
- then Buffer is padded with '0' characters so the combination of the optional '-' \r
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,\r
+ then Buffer is padded with '0' characters so the combination of the optional '-'\r
sign character, '0' characters, digit characters for Value, and the Null-terminator\r
add up to Width characters.\r
\r
If unsupported bits are set in Flags, then ASSERT().\r
If Width >= MAXIMUM_VALUE_CHARACTERS, then ASSERT()\r
\r
- @param Buffer Pointer to the output buffer for the produced Null-terminated\r
+ @param Buffer The pointer to the output buffer for the produced Null-terminated\r
string.\r
@param Flags The bitmask of flags that specify left justification, zero pad,\r
and commas.\r
@param Value The 64-bit signed value to convert to a string.\r
@param Width The maximum number of characters to place in Buffer, not including\r
the Null-terminator.\r
- @param Increment Character increment in Buffer.\r
- \r
+ @param Increment The character increment in Buffer.\r
+\r
@return Total number of characters required to perform the conversion.\r
\r
**/\r
CHAR8 *OriginalBuffer;\r
CHAR8 *EndBuffer;\r
CHAR8 ValueBuffer[MAXIMUM_VALUE_CHARACTERS];\r
+ CHAR8 *ValueBufferPtr;\r
UINTN Count;\r
UINTN Digits;\r
UINTN Index;\r
ASSERT ((Flags & ~(LEFT_JUSTIFY | COMMA_TYPE | PREFIX_ZERO | RADIX_HEX)) == 0);\r
\r
//\r
- // If both COMMA_TYPE and HEX_RADIX are set, then ASSERT ()\r
+ // If both COMMA_TYPE and RADIX_HEX are set, then ASSERT ()\r
//\r
- ASSERT (((Flags & COMMA_TYPE) != 0 && (Flags & RADIX_HEX) != 0) == FALSE);\r
+ ASSERT (((Flags & COMMA_TYPE) == 0) || ((Flags & RADIX_HEX) == 0));\r
\r
OriginalBuffer = Buffer;\r
- \r
+\r
//\r
// Width is 0 or COMMA_TYPE is set, PREFIX_ZERO is ignored.\r
//\r
if (Width == 0 || (Flags & COMMA_TYPE) != 0) {\r
- Flags &= (~PREFIX_ZERO);\r
+ Flags &= ~((UINTN) PREFIX_ZERO);\r
}\r
//\r
// If Width is 0 then a width of MAXIMUM_VALUE_CHARACTERS is assumed.\r
// Set the tag for the end of the input Buffer.\r
//\r
EndBuffer = Buffer + Width * Increment;\r
- \r
+\r
//\r
// Convert decimal negative\r
//\r
Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, '-', Increment);\r
Width--;\r
}\r
- \r
+\r
//\r
// Count the length of the value string.\r
//\r
Radix = ((Flags & RADIX_HEX) == 0)? 10 : 16;\r
- Count = BasePrintLibValueToString (ValueBuffer, Value, Radix);\r
- \r
+ ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, Value, Radix);\r
+ Count = ValueBufferPtr - ValueBuffer;\r
+\r
//\r
// Append Zero\r
//\r
if ((Flags & PREFIX_ZERO) != 0) {\r
Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Count, '0', Increment);\r
}\r
- \r
+\r
//\r
// Print Comma type for every 3 characters\r
//\r
Digits = 3 - Digits;\r
}\r
for (Index = 0; Index < Count; Index++) {\r
- Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ValueBuffer[Count - Index], Increment);\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, *ValueBufferPtr--, Increment);\r
if ((Flags & COMMA_TYPE) != 0) {\r
Digits++;\r
if (Digits == 3) {\r
}\r
}\r
}\r
- \r
+\r
//\r
// Print Null-terminator\r
//\r
}\r
\r
/**\r
- Worker function that produces a Null-terminated string in an output buffer \r
+ Internal function that converts a decimal value to a Null-terminated string.\r
+\r
+ Converts the decimal number specified by Value to a Null-terminated string\r
+ specified by Buffer containing at most Width characters. If Width is 0 then a\r
+ width of MAXIMUM_VALUE_CHARACTERS is assumed. If the conversion contains more\r
+ than Width characters, then only the first Width characters are placed in\r
+ Buffer. Additional conversion parameters are specified in Flags.\r
+ The Flags bit LEFT_JUSTIFY is always ignored.\r
+ All conversions are left justified in Buffer.\r
+ If Width is 0, PREFIX_ZERO is ignored in Flags.\r
+ If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and\r
+ commas are inserted every 3rd digit starting from the right.\r
+ If Value is < 0, then the fist character in Buffer is a '-'.\r
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,\r
+ then Buffer is padded with '0' characters so the combination of the optional\r
+ '-' sign character, '0' characters, digit characters for Value, and the\r
+ Null-terminator add up to Width characters.\r
+\r
+ If an error would be returned, the function will ASSERT().\r
+\r
+ @param Buffer The pointer to the output buffer for the produced\r
+ Null-terminated string.\r
+ @param BufferSize The size of Buffer in bytes, including the\r
+ Null-terminator.\r
+ @param Flags The bitmask of flags that specify left justification,\r
+ zero pad, and commas.\r
+ @param Value The 64-bit signed value to convert to a string.\r
+ @param Width The maximum number of characters to place in Buffer,\r
+ not including the Null-terminator.\r
+ @param Increment The character increment in Buffer.\r
+\r
+ @retval RETURN_SUCCESS The decimal value is converted.\r
+ @retval RETURN_BUFFER_TOO_SMALL If BufferSize cannot hold the converted\r
+ value.\r
+ @retval RETURN_INVALID_PARAMETER If Buffer is NULL.\r
+ If Increment is 1 and\r
+ PcdMaximumAsciiStringLength is not zero,\r
+ BufferSize is greater than\r
+ PcdMaximumAsciiStringLength.\r
+ If Increment is not 1 and\r
+ PcdMaximumUnicodeStringLength is not zero,\r
+ BufferSize is greater than\r
+ (PcdMaximumUnicodeStringLength *\r
+ sizeof (CHAR16) + 1).\r
+ If unsupported bits are set in Flags.\r
+ If both COMMA_TYPE and RADIX_HEX are set in\r
+ Flags.\r
+ If Width >= MAXIMUM_VALUE_CHARACTERS.\r
+\r
+**/\r
+RETURN_STATUS\r
+BasePrintLibConvertValueToStringS (\r
+ IN OUT CHAR8 *Buffer,\r
+ IN UINTN BufferSize,\r
+ IN UINTN Flags,\r
+ IN INT64 Value,\r
+ IN UINTN Width,\r
+ IN UINTN Increment\r
+ )\r
+{\r
+ CHAR8 *EndBuffer;\r
+ CHAR8 ValueBuffer[MAXIMUM_VALUE_CHARACTERS];\r
+ CHAR8 *ValueBufferPtr;\r
+ UINTN Count;\r
+ UINTN Digits;\r
+ UINTN Index;\r
+ UINTN Radix;\r
+\r
+ //\r
+ // 1. Buffer shall not be a null pointer.\r
+ //\r
+ SAFE_PRINT_CONSTRAINT_CHECK ((Buffer != NULL), RETURN_INVALID_PARAMETER);\r
+\r
+ //\r
+ // 2. BufferSize shall not be greater than (RSIZE_MAX * sizeof (CHAR16)) for\r
+ // Unicode output string or shall not be greater than ASCII_RSIZE_MAX for\r
+ // Ascii output string.\r
+ //\r
+ if (Increment == 1) {\r
+ //\r
+ // Ascii output string\r
+ //\r
+ if (ASCII_RSIZE_MAX != 0) {\r
+ SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);\r
+ }\r
+ } else {\r
+ //\r
+ // Unicode output string\r
+ //\r
+ if (RSIZE_MAX != 0) {\r
+ SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= RSIZE_MAX * sizeof (CHAR16) + 1), RETURN_INVALID_PARAMETER);\r
+ }\r
+ }\r
+\r
+ //\r
+ // 3. Flags shall be set properly.\r
+ //\r
+ SAFE_PRINT_CONSTRAINT_CHECK (((Flags & ~(LEFT_JUSTIFY | COMMA_TYPE | PREFIX_ZERO | RADIX_HEX)) == 0), RETURN_INVALID_PARAMETER);\r
+ SAFE_PRINT_CONSTRAINT_CHECK ((((Flags & COMMA_TYPE) == 0) || ((Flags & RADIX_HEX) == 0)), RETURN_INVALID_PARAMETER);\r
+\r
+ //\r
+ // 4. Width shall be smaller than MAXIMUM_VALUE_CHARACTERS.\r
+ //\r
+ SAFE_PRINT_CONSTRAINT_CHECK ((Width < MAXIMUM_VALUE_CHARACTERS), RETURN_INVALID_PARAMETER);\r
+\r
+ //\r
+ // Width is 0 or COMMA_TYPE is set, PREFIX_ZERO is ignored.\r
+ //\r
+ if (Width == 0 || (Flags & COMMA_TYPE) != 0) {\r
+ Flags &= ~((UINTN) PREFIX_ZERO);\r
+ }\r
+ //\r
+ // If Width is 0 then a width of MAXIMUM_VALUE_CHARACTERS is assumed.\r
+ //\r
+ if (Width == 0) {\r
+ Width = MAXIMUM_VALUE_CHARACTERS - 1;\r
+ }\r
+\r
+ //\r
+ // Count the characters of the output string.\r
+ //\r
+ Count = 0;\r
+ Radix = ((Flags & RADIX_HEX) == 0)? 10 : 16;\r
+\r
+ if ((Flags & PREFIX_ZERO) != 0) {\r
+ Count = Width;\r
+ } else {\r
+ if ((Value < 0) && ((Flags & RADIX_HEX) == 0)) {\r
+ Count++; // minus sign\r
+ ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, -Value, Radix);\r
+ } else {\r
+ ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, Value, Radix);\r
+ }\r
+ Digits = ValueBufferPtr - ValueBuffer;\r
+ Count += Digits;\r
+\r
+ if ((Flags & COMMA_TYPE) != 0) {\r
+ Count += (Digits - 1) / 3; // commas\r
+ }\r
+ }\r
+\r
+ Width = MIN (Count, Width);\r
+\r
+ //\r
+ // 5. BufferSize shall be large enough to hold the converted string.\r
+ //\r
+ SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize >= (Width + 1) * Increment), RETURN_BUFFER_TOO_SMALL);\r
+\r
+ //\r
+ // Set the tag for the end of the input Buffer.\r
+ //\r
+ EndBuffer = Buffer + Width * Increment;\r
+\r
+ //\r
+ // Convert decimal negative\r
+ //\r
+ if ((Value < 0) && ((Flags & RADIX_HEX) == 0)) {\r
+ Value = -Value;\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, '-', Increment);\r
+ Width--;\r
+ }\r
+\r
+ //\r
+ // Count the length of the value string.\r
+ //\r
+ ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, Value, Radix);\r
+ Count = ValueBufferPtr - ValueBuffer;\r
+\r
+ //\r
+ // Append Zero\r
+ //\r
+ if ((Flags & PREFIX_ZERO) != 0) {\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Count, '0', Increment);\r
+ }\r
+\r
+ //\r
+ // Print Comma type for every 3 characters\r
+ //\r
+ Digits = Count % 3;\r
+ if (Digits != 0) {\r
+ Digits = 3 - Digits;\r
+ }\r
+ for (Index = 0; Index < Count; Index++) {\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, *ValueBufferPtr--, Increment);\r
+ if ((Flags & COMMA_TYPE) != 0) {\r
+ Digits++;\r
+ if (Digits == 3) {\r
+ Digits = 0;\r
+ if ((Index + 1) < Count) {\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', Increment);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Print Null-terminator\r
+ //\r
+ BasePrintLibFillBuffer (Buffer, EndBuffer + Increment, 1, 0, Increment);\r
+\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Worker function that produces a Null-terminated string in an output buffer\r
based on a Null-terminated format string and a VA_LIST argument list.\r
\r
- VSPrint function to process format and place the results in Buffer. Since a \r
- VA_LIST is used this rountine allows the nesting of Vararg routines. Thus \r
+ VSPrint function to process format and place the results in Buffer. Since a\r
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus\r
this is the main print working routine.\r
\r
- @param Buffer Character buffer to print the results of the parsing\r
- of Format into.\r
- @param BufferSize Maximum number of characters to put into buffer.\r
- @param Flags Intial flags value.\r
- Can only have FORMAT_UNICODE and OUTPUT_UNICODE set.\r
- @param Format Null-terminated format string.\r
- @param Marker Vararg list consumed by processing Format.\r
-\r
- @return Number of characters printed not including the Null-terminator.\r
+ If COUNT_ONLY_NO_PRINT is set in Flags, Buffer will not be modified at all.\r
+\r
+ @param[out] Buffer The character buffer to print the results of the\r
+ parsing of Format into.\r
+ @param[in] BufferSize The maximum number of characters to put into\r
+ buffer.\r
+ @param[in] Flags Initial flags value.\r
+ Can only have FORMAT_UNICODE, OUTPUT_UNICODE,\r
+ and COUNT_ONLY_NO_PRINT set.\r
+ @param[in] Format A Null-terminated format string.\r
+ @param[in] VaListMarker VA_LIST style variable argument list consumed by\r
+ processing Format.\r
+ @param[in] BaseListMarker BASE_LIST style variable argument list consumed\r
+ by processing Format.\r
+\r
+ @return The number of characters printed not including the Null-terminator.\r
+ If COUNT_ONLY_NO_PRINT was set returns the same, but without any\r
+ modification to Buffer.\r
\r
**/\r
UINTN\r
-BasePrintLibVSPrint (\r
+BasePrintLibSPrintMarker (\r
OUT CHAR8 *Buffer,\r
IN UINTN BufferSize,\r
IN UINTN Flags,\r
IN CONST CHAR8 *Format,\r
- IN VA_LIST Marker\r
+ IN VA_LIST VaListMarker, OPTIONAL\r
+ IN BASE_LIST BaseListMarker OPTIONAL\r
)\r
{\r
- CHAR8 *OriginalBuffer;\r
- CHAR8 *EndBuffer;\r
- CHAR8 ValueBuffer[MAXIMUM_VALUE_CHARACTERS];\r
- UINTN BytesPerOutputCharacter;\r
- UINTN BytesPerFormatCharacter;\r
- UINTN FormatMask;\r
- UINTN FormatCharacter;\r
- UINTN Width;\r
- UINTN Precision;\r
- INT64 Value;\r
- CONST CHAR8 *ArgumentString;\r
- UINTN Character;\r
- GUID *TmpGuid;\r
- TIME *TmpTime;\r
- UINTN Count;\r
- UINTN ArgumentMask;\r
- INTN BytesPerArgumentCharacter;\r
- UINTN ArgumentCharacter;\r
- BOOLEAN Done;\r
- UINTN Index;\r
- CHAR8 Prefix;\r
- BOOLEAN ZeroPad;\r
- BOOLEAN Comma;\r
- UINTN Digits;\r
- UINTN Radix;\r
- RETURN_STATUS Status;\r
-\r
- if (BufferSize == 0) {\r
- return 0;\r
+ CHAR8 *OriginalBuffer;\r
+ CHAR8 *EndBuffer;\r
+ CHAR8 ValueBuffer[MAXIMUM_VALUE_CHARACTERS];\r
+ UINT32 BytesPerOutputCharacter;\r
+ UINTN BytesPerFormatCharacter;\r
+ UINTN FormatMask;\r
+ UINTN FormatCharacter;\r
+ UINTN Width;\r
+ UINTN Precision;\r
+ INT64 Value;\r
+ CONST CHAR8 *ArgumentString;\r
+ UINTN Character;\r
+ GUID *TmpGuid;\r
+ TIME *TmpTime;\r
+ UINTN Count;\r
+ UINTN ArgumentMask;\r
+ INTN BytesPerArgumentCharacter;\r
+ UINTN ArgumentCharacter;\r
+ BOOLEAN Done;\r
+ UINTN Index;\r
+ CHAR8 Prefix;\r
+ BOOLEAN ZeroPad;\r
+ BOOLEAN Comma;\r
+ UINTN Digits;\r
+ UINTN Radix;\r
+ RETURN_STATUS Status;\r
+ UINT32 GuidData1;\r
+ UINT16 GuidData2;\r
+ UINT16 GuidData3;\r
+ UINTN LengthToReturn;\r
+\r
+ //\r
+ // If you change this code be sure to match the 2 versions of this function.\r
+ // Nearly identical logic is found in the BasePrintLib and\r
+ // DxePrintLibPrint2Protocol (both PrintLib instances).\r
+ //\r
+\r
+ //\r
+ // 1. Buffer shall not be a null pointer when both BufferSize > 0 and\r
+ // COUNT_ONLY_NO_PRINT is not set in Flags.\r
+ //\r
+ if ((BufferSize > 0) && ((Flags & COUNT_ONLY_NO_PRINT) == 0)) {\r
+ SAFE_PRINT_CONSTRAINT_CHECK ((Buffer != NULL), 0);\r
+ }\r
+\r
+ //\r
+ // 2. Format shall not be a null pointer when BufferSize > 0 or when\r
+ // COUNT_ONLY_NO_PRINT is set in Flags.\r
+ //\r
+ if ((BufferSize > 0) || ((Flags & COUNT_ONLY_NO_PRINT) != 0)) {\r
+ SAFE_PRINT_CONSTRAINT_CHECK ((Format != NULL), 0);\r
}\r
- ASSERT (Buffer != NULL);\r
\r
+ //\r
+ // 3. BufferSize shall not be greater than RSIZE_MAX for Unicode output or\r
+ // ASCII_RSIZE_MAX for Ascii output.\r
+ //\r
if ((Flags & OUTPUT_UNICODE) != 0) {\r
+ if (RSIZE_MAX != 0) {\r
+ SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= RSIZE_MAX), 0);\r
+ }\r
BytesPerOutputCharacter = 2;\r
} else {\r
+ if (ASCII_RSIZE_MAX != 0) {\r
+ SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= ASCII_RSIZE_MAX), 0);\r
+ }\r
BytesPerOutputCharacter = 1;\r
}\r
\r
//\r
- // Reserve space for the Null terminator.\r
- //\r
- BufferSize--;\r
- OriginalBuffer = Buffer;\r
- //\r
- // Set the tag for the end of the input Buffer.\r
+ // 4. Format shall not contain more than RSIZE_MAX Unicode characters or\r
+ // ASCII_RSIZE_MAX Ascii characters.\r
//\r
- EndBuffer = Buffer + BufferSize * BytesPerOutputCharacter;\r
-\r
if ((Flags & FORMAT_UNICODE) != 0) {\r
- //\r
- // Make sure format string cannot contain more than PcdMaximumUnicodeStringLength\r
- // Unicode characters if PcdMaximumUnicodeStringLength is not zero. \r
- //\r
- ASSERT (StrSize ((CHAR16 *) Format) != 0);\r
+ if (RSIZE_MAX != 0) {\r
+ SAFE_PRINT_CONSTRAINT_CHECK ((StrnLenS ((CHAR16 *)Format, RSIZE_MAX + 1) <= RSIZE_MAX), 0);\r
+ }\r
BytesPerFormatCharacter = 2;\r
FormatMask = 0xffff;\r
} else {\r
- //\r
- // Make sure format string cannot contain more than PcdMaximumAsciiStringLength\r
- // Ascii characters if PcdMaximumAsciiStringLength is not zero. \r
- //\r
- ASSERT (AsciiStrSize (Format) != 0);\r
+ if (ASCII_RSIZE_MAX != 0) {\r
+ SAFE_PRINT_CONSTRAINT_CHECK ((AsciiStrnLenS (Format, ASCII_RSIZE_MAX + 1) <= ASCII_RSIZE_MAX), 0);\r
+ }\r
BytesPerFormatCharacter = 1;\r
FormatMask = 0xff;\r
}\r
\r
+ if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {\r
+ if (BufferSize == 0) {\r
+ Buffer = NULL;\r
+ }\r
+ } else {\r
+ //\r
+ // We can run without a Buffer for counting only.\r
+ //\r
+ if (BufferSize == 0) {\r
+ return 0;\r
+ }\r
+ }\r
+\r
+ LengthToReturn = 0;\r
+ EndBuffer = NULL;\r
+ OriginalBuffer = NULL;\r
+\r
+ //\r
+ // Reserve space for the Null terminator.\r
+ //\r
+ if (Buffer != NULL) {\r
+ BufferSize--;\r
+ OriginalBuffer = Buffer;\r
\r
+ //\r
+ // Set the tag for the end of the input Buffer.\r
+ //\r
+ EndBuffer = Buffer + BufferSize * BytesPerOutputCharacter;\r
+ }\r
\r
//\r
// Get the first character from the format string\r
//\r
- FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;\r
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;\r
\r
//\r
// Loop until the end of the format string is reached or the output buffer is full\r
//\r
- while (FormatCharacter != 0 && Buffer < EndBuffer) {\r
+ while (FormatCharacter != 0) {\r
+ if ((Buffer != NULL) && (Buffer >= EndBuffer)) {\r
+ break;\r
+ }\r
//\r
// Clear all the flag bits except those that may have been passed in\r
//\r
- Flags &= (OUTPUT_UNICODE | FORMAT_UNICODE);\r
+ Flags &= (UINTN) (OUTPUT_UNICODE | FORMAT_UNICODE | COUNT_ONLY_NO_PRINT);\r
\r
//\r
// Set the default width to zero, and the default precision to 1\r
//\r
for (Done = FALSE; !Done; ) {\r
Format += BytesPerFormatCharacter;\r
- FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;\r
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;\r
switch (FormatCharacter) {\r
- case '.': \r
- Flags |= PRECISION; \r
+ case '.':\r
+ Flags |= PRECISION;\r
break;\r
- case '-': \r
- Flags |= LEFT_JUSTIFY; \r
+ case '-':\r
+ Flags |= LEFT_JUSTIFY;\r
break;\r
- case '+': \r
- Flags |= PREFIX_SIGN; \r
+ case '+':\r
+ Flags |= PREFIX_SIGN;\r
break;\r
- case ' ': \r
- Flags |= PREFIX_BLANK; \r
+ case ' ':\r
+ Flags |= PREFIX_BLANK;\r
break;\r
- case ',': \r
- Flags |= COMMA_TYPE; \r
+ case ',':\r
+ Flags |= COMMA_TYPE;\r
break;\r
case 'L':\r
- case 'l': \r
- Flags |= LONG_TYPE; \r
+ case 'l':\r
+ Flags |= LONG_TYPE;\r
break;\r
case '*':\r
if ((Flags & PRECISION) == 0) {\r
Flags |= PAD_TO_WIDTH;\r
- Width = VA_ARG (Marker, UINTN);\r
+ if (BaseListMarker == NULL) {\r
+ Width = VA_ARG (VaListMarker, UINTN);\r
+ } else {\r
+ Width = BASE_ARG (BaseListMarker, UINTN);\r
+ }\r
} else {\r
- Precision = VA_ARG (Marker, UINTN);\r
+ if (BaseListMarker == NULL) {\r
+ Precision = VA_ARG (VaListMarker, UINTN);\r
+ } else {\r
+ Precision = BASE_ARG (BaseListMarker, UINTN);\r
+ }\r
}\r
break;\r
case '0':\r
for (Count = 0; ((FormatCharacter >= '0') && (FormatCharacter <= '9')); ){\r
Count = (Count * 10) + FormatCharacter - '0';\r
Format += BytesPerFormatCharacter;\r
- FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;\r
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;\r
}\r
Format -= BytesPerFormatCharacter;\r
if ((Flags & PRECISION) == 0) {\r
Precision = Count;\r
}\r
break;\r
- \r
+\r
case '\0':\r
//\r
// Make no output if Format string terminates unexpectedly when\r
- // looking up for flag, width, precision and type. \r
+ // looking up for flag, width, precision and type.\r
//\r
Format -= BytesPerFormatCharacter;\r
Precision = 0;\r
Done = TRUE;\r
break;\r
}\r
- } \r
+ }\r
\r
//\r
// Handle each argument type\r
//\r
// Flag space, +, 0, L & l are invalid for type p.\r
//\r
- Flags &= ~(PREFIX_BLANK | PREFIX_SIGN | PREFIX_ZERO | LONG_TYPE);\r
+ Flags &= ~((UINTN) (PREFIX_BLANK | PREFIX_SIGN | PREFIX_ZERO | LONG_TYPE));\r
if (sizeof (VOID *) > 4) {\r
Flags |= LONG_TYPE;\r
}\r
+ //\r
+ // break skipped on purpose\r
+ //\r
case 'X':\r
Flags |= PREFIX_ZERO;\r
//\r
//\r
// break skipped on purpose\r
//\r
+ case 'u':\r
+ if ((Flags & RADIX_HEX) == 0) {\r
+ Flags &= ~((UINTN) (PREFIX_SIGN));\r
+ Flags |= UNSIGNED_TYPE;\r
+ }\r
+ //\r
+ // break skipped on purpose\r
+ //\r
case 'd':\r
if ((Flags & LONG_TYPE) == 0) {\r
- Value = (VA_ARG (Marker, int));\r
+ //\r
+ // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".\r
+ // This assumption is made so the format string definition is compatible with the ANSI C\r
+ // Specification for formatted strings. It is recommended that the Base Types be used\r
+ // everywhere, but in this one case, compliance with ANSI C is more important, and\r
+ // provides an implementation that is compatible with that largest possible set of CPU\r
+ // architectures. This is why the type "int" is used in this one case.\r
+ //\r
+ if (BaseListMarker == NULL) {\r
+ Value = VA_ARG (VaListMarker, int);\r
+ } else {\r
+ Value = BASE_ARG (BaseListMarker, int);\r
+ }\r
} else {\r
- Value = VA_ARG (Marker, INT64);\r
+ if (BaseListMarker == NULL) {\r
+ Value = VA_ARG (VaListMarker, INT64);\r
+ } else {\r
+ Value = BASE_ARG (BaseListMarker, INT64);\r
+ }\r
}\r
if ((Flags & PREFIX_BLANK) != 0) {\r
Prefix = ' ';\r
if ((Flags & RADIX_HEX) == 0) {\r
Radix = 10;\r
if (Comma) {\r
- Flags &= (~PREFIX_ZERO);\r
+ Flags &= ~((UINTN) PREFIX_ZERO);\r
Precision = 1;\r
}\r
- if (Value < 0) {\r
+ if (Value < 0 && (Flags & UNSIGNED_TYPE) == 0) {\r
Flags |= PREFIX_SIGN;\r
Prefix = '-';\r
Value = -Value;\r
+ } else if ((Flags & UNSIGNED_TYPE) != 0 && (Flags & LONG_TYPE) == 0) {\r
+ //\r
+ // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".\r
+ // This assumption is made so the format string definition is compatible with the ANSI C\r
+ // Specification for formatted strings. It is recommended that the Base Types be used\r
+ // everywhere, but in this one case, compliance with ANSI C is more important, and\r
+ // provides an implementation that is compatible with that largest possible set of CPU\r
+ // architectures. This is why the type "unsigned int" is used in this one case.\r
+ //\r
+ Value = (unsigned int)Value;\r
}\r
} else {\r
Radix = 16;\r
Comma = FALSE;\r
if ((Flags & LONG_TYPE) == 0 && Value < 0) {\r
+ //\r
+ // 'd', 'u', 'x', and 'X' that are not preceded by 'l' or 'L' are assumed to be type "int".\r
+ // This assumption is made so the format string definition is compatible with the ANSI C\r
+ // Specification for formatted strings. It is recommended that the Base Types be used\r
+ // everywhere, but in this one case, compliance with ANSI C is more important, and\r
+ // provides an implementation that is compatible with that largest possible set of CPU\r
+ // architectures. This is why the type "unsigned int" is used in this one case.\r
+ //\r
Value = (unsigned int)Value;\r
}\r
}\r
//\r
// Convert Value to a reversed string\r
//\r
- Count = BasePrintLibValueToString (ValueBuffer, Value, Radix);\r
+ Count = BasePrintLibValueToString (ValueBuffer, Value, Radix) - ValueBuffer;\r
if (Value == 0 && Precision == 0) {\r
Count = 0;\r
}\r
ArgumentString = (CHAR8 *)ValueBuffer + Count;\r
- \r
+\r
Digits = Count % 3;\r
if (Digits != 0) {\r
Digits = 3 - Digits;\r
// break skipped on purpose\r
//\r
case 'a':\r
- ArgumentString = (CHAR8 *)VA_ARG (Marker, CHAR8 *);\r
+ if (BaseListMarker == NULL) {\r
+ ArgumentString = VA_ARG (VaListMarker, CHAR8 *);\r
+ } else {\r
+ ArgumentString = BASE_ARG (BaseListMarker, CHAR8 *);\r
+ }\r
if (ArgumentString == NULL) {\r
- Flags &= (~ARGUMENT_UNICODE);\r
+ Flags &= ~((UINTN) ARGUMENT_UNICODE);\r
ArgumentString = "<null string>";\r
}\r
//\r
break;\r
\r
case 'c':\r
- Character = VA_ARG (Marker, UINTN) & 0xffff;\r
+ if (BaseListMarker == NULL) {\r
+ Character = VA_ARG (VaListMarker, UINTN) & 0xffff;\r
+ } else {\r
+ Character = BASE_ARG (BaseListMarker, UINTN) & 0xffff;\r
+ }\r
ArgumentString = (CHAR8 *)&Character;\r
Flags |= ARGUMENT_UNICODE;\r
break;\r
\r
case 'g':\r
- TmpGuid = VA_ARG (Marker, GUID *);\r
+ if (BaseListMarker == NULL) {\r
+ TmpGuid = VA_ARG (VaListMarker, GUID *);\r
+ } else {\r
+ TmpGuid = BASE_ARG (BaseListMarker, GUID *);\r
+ }\r
if (TmpGuid == NULL) {\r
ArgumentString = "<null guid>";\r
} else {\r
+ GuidData1 = ReadUnaligned32 (&(TmpGuid->Data1));\r
+ GuidData2 = ReadUnaligned16 (&(TmpGuid->Data2));\r
+ GuidData3 = ReadUnaligned16 (&(TmpGuid->Data3));\r
BasePrintLibSPrint (\r
ValueBuffer,\r
- MAXIMUM_VALUE_CHARACTERS, \r
+ MAXIMUM_VALUE_CHARACTERS,\r
0,\r
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",\r
- TmpGuid->Data1,\r
- TmpGuid->Data2,\r
- TmpGuid->Data3,\r
+ GuidData1,\r
+ GuidData2,\r
+ GuidData3,\r
TmpGuid->Data4[0],\r
TmpGuid->Data4[1],\r
TmpGuid->Data4[2],\r
break;\r
\r
case 't':\r
- TmpTime = VA_ARG (Marker, TIME *); \r
+ if (BaseListMarker == NULL) {\r
+ TmpTime = VA_ARG (VaListMarker, TIME *);\r
+ } else {\r
+ TmpTime = BASE_ARG (BaseListMarker, TIME *);\r
+ }\r
if (TmpTime == NULL) {\r
ArgumentString = "<null time>";\r
} else {\r
break;\r
\r
case 'r':\r
- Status = VA_ARG (Marker, RETURN_STATUS);\r
+ if (BaseListMarker == NULL) {\r
+ Status = VA_ARG (VaListMarker, RETURN_STATUS);\r
+ } else {\r
+ Status = BASE_ARG (BaseListMarker, RETURN_STATUS);\r
+ }\r
ArgumentString = ValueBuffer;\r
if (RETURN_ERROR (Status)) {\r
//\r
}\r
break;\r
\r
+ case '\r':\r
+ Format += BytesPerFormatCharacter;\r
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;\r
+ if (FormatCharacter == '\n') {\r
+ //\r
+ // Translate '\r\n' to '\r\n'\r
+ //\r
+ ArgumentString = "\r\n";\r
+ } else {\r
+ //\r
+ // Translate '\r' to '\r'\r
+ //\r
+ ArgumentString = "\r";\r
+ Format -= BytesPerFormatCharacter;\r
+ }\r
+ break;\r
+\r
case '\n':\r
- ArgumentString = "\n\r";\r
+ //\r
+ // Translate '\n' to '\r\n' and '\n\r' to '\r\n'\r
+ //\r
+ ArgumentString = "\r\n";\r
+ Format += BytesPerFormatCharacter;\r
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;\r
+ if (FormatCharacter != '\r') {\r
+ Format -= BytesPerFormatCharacter;\r
+ }\r
break;\r
\r
case '%':\r
break;\r
}\r
break;\r
- \r
+\r
+ case '\r':\r
+ Format += BytesPerFormatCharacter;\r
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;\r
+ if (FormatCharacter == '\n') {\r
+ //\r
+ // Translate '\r\n' to '\r\n'\r
+ //\r
+ ArgumentString = "\r\n";\r
+ } else {\r
+ //\r
+ // Translate '\r' to '\r'\r
+ //\r
+ ArgumentString = "\r";\r
+ Format -= BytesPerFormatCharacter;\r
+ }\r
+ break;\r
+\r
case '\n':\r
- ArgumentString = "\n\r";\r
+ //\r
+ // Translate '\n' to '\r\n' and '\n\r' to '\r\n'\r
+ //\r
+ ArgumentString = "\r\n";\r
+ Format += BytesPerFormatCharacter;\r
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;\r
+ if (FormatCharacter != '\r') {\r
+ Format -= BytesPerFormatCharacter;\r
+ }\r
break;\r
\r
default:\r
// Compute the number of characters in ArgumentString and store it in Count\r
// ArgumentString is either null-terminated, or it contains Precision characters\r
//\r
- for (Count = 0; Count < Precision || ((Flags & PRECISION) == 0); Count++) {\r
+ for (Count = 0;\r
+ (ArgumentString[Count * BytesPerArgumentCharacter] != '\0' ||\r
+ (BytesPerArgumentCharacter > 1 &&\r
+ ArgumentString[Count * BytesPerArgumentCharacter + 1]!= '\0')) &&\r
+ (Count < Precision || ((Flags & PRECISION) == 0));\r
+ Count++) {\r
ArgumentCharacter = ((ArgumentString[Count * BytesPerArgumentCharacter] & 0xff) | ((ArgumentString[Count * BytesPerArgumentCharacter + 1]) << 8)) & ArgumentMask;\r
if (ArgumentCharacter == 0) {\r
break;\r
// Pad before the string\r
//\r
if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH)) {\r
- Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);\r
+ LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);\r
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);\r
+ }\r
}\r
\r
if (ZeroPad) {\r
if (Prefix != 0) {\r
- Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);\r
+ LengthToReturn += (1 * BytesPerOutputCharacter);\r
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);\r
+ }\r
+ }\r
+ LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);\r
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, '0', BytesPerOutputCharacter);\r
}\r
- Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, '0', BytesPerOutputCharacter);\r
} else {\r
- Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, ' ', BytesPerOutputCharacter);\r
+ LengthToReturn += ((Precision - Count) * BytesPerOutputCharacter);\r
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Precision - Count, ' ', BytesPerOutputCharacter);\r
+ }\r
if (Prefix != 0) {\r
- Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);\r
+ LengthToReturn += (1 * BytesPerOutputCharacter);\r
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, Prefix, BytesPerOutputCharacter);\r
+ }\r
}\r
}\r
\r
//\r
// Copy the string into the output buffer performing the required type conversions\r
//\r
- while (Index < Count) {\r
- ArgumentCharacter = ((*ArgumentString & 0xff) | (*(ArgumentString + 1) << 8)) & ArgumentMask;\r
-\r
- Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ArgumentCharacter, BytesPerOutputCharacter);\r
+ while (Index < Count &&\r
+ (ArgumentString[0] != '\0' ||\r
+ (BytesPerArgumentCharacter > 1 && ArgumentString[1] != '\0'))) {\r
+ ArgumentCharacter = ((*ArgumentString & 0xff) | (((UINT8)*(ArgumentString + 1)) << 8)) & ArgumentMask;\r
+\r
+ LengthToReturn += (1 * BytesPerOutputCharacter);\r
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ArgumentCharacter, BytesPerOutputCharacter);\r
+ }\r
ArgumentString += BytesPerArgumentCharacter;\r
Index++;\r
if (Comma) {\r
Digits = 0;\r
Index++;\r
if (Index < Count) {\r
- Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', BytesPerOutputCharacter);\r
+ LengthToReturn += (1 * BytesPerOutputCharacter);\r
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', BytesPerOutputCharacter);\r
+ }\r
}\r
}\r
}\r
// Pad after the string\r
//\r
if ((Flags & (PAD_TO_WIDTH | LEFT_JUSTIFY)) == (PAD_TO_WIDTH | LEFT_JUSTIFY)) {\r
- Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);\r
+ LengthToReturn += ((Width - Precision) * BytesPerOutputCharacter);\r
+ if ((Flags & COUNT_ONLY_NO_PRINT) == 0 && Buffer != NULL) {\r
+ Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Precision, ' ', BytesPerOutputCharacter);\r
+ }\r
}\r
\r
//\r
//\r
// Get the next character from the format string\r
//\r
- FormatCharacter = ((*Format & 0xff) | (*(Format + 1) << 8)) & FormatMask;\r
+ FormatCharacter = ((*Format & 0xff) | ((BytesPerFormatCharacter == 1) ? 0 : (*(Format + 1) << 8))) & FormatMask;\r
+ }\r
+\r
+ if ((Flags & COUNT_ONLY_NO_PRINT) != 0) {\r
+ return (LengthToReturn / BytesPerOutputCharacter);\r
}\r
\r
+ ASSERT (Buffer != NULL);\r
//\r
// Null terminate the Unicode or ASCII string\r
//\r
BasePrintLibFillBuffer (Buffer, EndBuffer + BytesPerOutputCharacter, 1, 0, BytesPerOutputCharacter);\r
- //\r
- // Make sure output buffer cannot contain more than PcdMaximumUnicodeStringLength\r
- // Unicode characters if PcdMaximumUnicodeStringLength is not zero. \r
- //\r
- ASSERT ((((Flags & OUTPUT_UNICODE) == 0)) || (StrSize ((CHAR16 *) OriginalBuffer) != 0));\r
- //\r
- // Make sure output buffer cannot contain more than PcdMaximumAsciiStringLength\r
- // ASCII characters if PcdMaximumAsciiStringLength is not zero. \r
- //\r
- ASSERT ((((Flags & OUTPUT_UNICODE) != 0)) || (AsciiStrSize (OriginalBuffer) != 0));\r
\r
return ((Buffer - OriginalBuffer) / BytesPerOutputCharacter);\r
}\r
\r
/**\r
- Worker function that produces a Null-terminated string in an output buffer \r
+ Worker function that produces a Null-terminated string in an output buffer\r
based on a Null-terminated format string and variable argument list.\r
\r
- VSPrint function to process format and place the results in Buffer. Since a \r
- VA_LIST is used this rountine allows the nesting of Vararg routines. Thus \r
+ VSPrint function to process format and place the results in Buffer. Since a\r
+ VA_LIST is used this routine allows the nesting of Vararg routines. Thus\r
this is the main print working routine\r
\r
- @param StartOfBuffer Character buffer to print the results of the parsing\r
+ @param StartOfBuffer The character buffer to print the results of the parsing\r
of Format into.\r
- @param BufferSize Maximum number of characters to put into buffer.\r
+ @param BufferSize The maximum number of characters to put into buffer.\r
Zero means no limit.\r
- @param Flags Intial flags value.\r
+ @param Flags Initial flags value.\r
Can only have FORMAT_UNICODE and OUTPUT_UNICODE set\r
- @param FormatString Null-terminated format string.\r
+ @param FormatString A Null-terminated format string.\r
@param ... The variable argument list.\r
\r
- @return Number of characters printed.\r
+ @return The number of characters printed.\r
\r
**/\r
UINTN\r
+EFIAPI\r
BasePrintLibSPrint (\r
OUT CHAR8 *StartOfBuffer,\r
IN UINTN BufferSize,\r
)\r
{\r
VA_LIST Marker;\r
+ UINTN NumberOfPrinted;\r
\r
VA_START (Marker, FormatString);\r
- return BasePrintLibVSPrint (StartOfBuffer, BufferSize, Flags, FormatString, Marker);\r
+ NumberOfPrinted = BasePrintLibSPrintMarker (StartOfBuffer, BufferSize, Flags, FormatString, Marker, NULL);\r
+ VA_END (Marker);\r
+ return NumberOfPrinted;\r
}\r