summaryrefslogtreecommitdiffstats
path: root/RedfishPkg/PrivateLibrary
diff options
context:
space:
mode:
authorAbner Chang <abner.chang@hpe.com>2020-12-04 12:30:05 +0800
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2021-01-09 03:08:51 +0000
commit6e9233f968735219b2038c5dd23a46be2c021807 (patch)
treeb670be263c6cb774c6c9714501fba286cc10d3f4 /RedfishPkg/PrivateLibrary
parenta88731d5453fedaa389827139abc3c22a99ec460 (diff)
downloadedk2-6e9233f968735219b2038c5dd23a46be2c021807.tar.gz
edk2-6e9233f968735219b2038c5dd23a46be2c021807.tar.bz2
edk2-6e9233f968735219b2038c5dd23a46be2c021807.zip
RedfishPkg/RedfishCrtLib: Redfish C runtime library
Redfish CRT library is currently used by edk2 JsonLib (open source jansson project) and edk2 RedfishLib (libredfish open source project). Redfish CrtLib library provides the necessary C runtime equivalent edk2 functions for open source projects. Signed-off-by: Abner Chang <abner.chang@hpe.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Nickle Wang <nickle.wang@hpe.com> Cc: Peter O'Hanley <peter.ohanley@hpe.com> Reviewed-by: Nickle Wang <nickle.wang@hpe.com> Acked-by: Leif Lindholm <leif@nuviainc.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
Diffstat (limited to 'RedfishPkg/PrivateLibrary')
-rw-r--r--RedfishPkg/PrivateLibrary/RedfishCrtLib/RedfishCrtLib.c809
-rw-r--r--RedfishPkg/PrivateLibrary/RedfishCrtLib/RedfishCrtLib.inf38
2 files changed, 847 insertions, 0 deletions
diff --git a/RedfishPkg/PrivateLibrary/RedfishCrtLib/RedfishCrtLib.c b/RedfishPkg/PrivateLibrary/RedfishCrtLib/RedfishCrtLib.c
new file mode 100644
index 0000000000..0696341bc0
--- /dev/null
+++ b/RedfishPkg/PrivateLibrary/RedfishCrtLib/RedfishCrtLib.c
@@ -0,0 +1,809 @@
+/** @file
+ CRT wrapper functions for system call,the string operation functions
+ are remodeled after edk2-libc.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Uefi.h>
+#include <Library/RedfishCrtLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SortLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+int errno = 0;
+
+/**
+ Determine if a particular character is an alphanumeric character
+ @return Returns 1 if c is an alphanumeric character, otherwise returns 0.
+**/
+int isalnum (int c)
+{
+ //
+ // <alnum> ::= [0-9] | [a-z] | [A-Z]
+ //
+ return ((('0' <= (c)) && ((c) <= '9')) ||
+ (('a' <= (c)) && ((c) <= 'z')) ||
+ (('A' <= (c)) && ((c) <= 'Z')));
+}
+
+/**
+ Determine if a particular character is a digital character
+
+ @return Returns 1 if c is an digital character, otherwise returns 0.
+**/
+int isdchar (int c)
+{
+ //
+ // [0-9] | [e +-.]
+ //
+ return ((('0' <= (c)) && ((c) <= '9')) ||
+ (c == 'e') || (c == 'E') ||
+ (c == '+') || (c == '-') ||
+ (c == '.'));
+}
+
+/**
+ Determine if a particular character is a space character
+
+ @return Returns 1 if c is a space character
+**/
+int isspace (int c)
+{
+ //
+ // <space> ::= [ ]
+ //
+ return ((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n') || ((c) == '\v') || ((c) == '\f');
+}
+
+/**
+ Allocates memory blocks
+*/
+void *malloc (size_t size)
+{
+ return AllocatePool ((UINTN) size);
+}
+
+/**
+ De-allocates or frees a memory block
+*/
+void free (void *ptr)
+{
+ //
+ // In Standard C, free() handles a null pointer argument transparently. This
+ // is not true of FreePool() below, so protect it.
+ //
+ if (ptr != NULL) {
+ FreePool (ptr);
+ }
+}
+
+/**
+ NetBSD Compatibility Function strdup creates a duplicate copy of a string.
+
+ @return Returns the pointer to duplicated string.
+**/
+char * strdup(const char *str)
+{
+ size_t len;
+ char *copy;
+
+ len = strlen(str) + 1;
+ if ((copy = malloc(len)) == NULL)
+ return (NULL);
+ memcpy(copy, str, len);
+ return (copy);
+}
+
+/** The toupper function converts a lowercase letter to a corresponding
+ uppercase letter.
+
+ @param[in] c The character to be converted.
+
+ @return If the argument is a character for which islower is true and
+ there are one or more corresponding characters, as specified by
+ the current locale, for which isupper is true, the toupper
+ function returns one of the corresponding characters (always the
+ same one for any given locale); otherwise, the argument is
+ returned unchanged.
+**/
+int
+toupper(
+ IN int c
+ )
+{
+ if ( (c >= 'a') && (c <= 'z') ) {
+ c = c - ('a' - 'A');
+ }
+ return c;
+}
+
+/**
+ Digit to a value.
+
+ @return Returns the value of digit.
+**/
+int
+Digit2Val( int c)
+{
+ if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) { /* If c is one of [A-Za-z]... */
+ c = toupper(c) - 7; // Adjust so 'A' is ('9' + 1)
+ }
+ return c - '0'; // Value returned is between 0 and 35, inclusive.
+}
+
+
+/** The strtoll function converts the initial portion of the string pointed to
+ by nptr to long long int representation.
+
+ See the description for strtol for more information.
+
+ @return The strtoll function returns the converted value, if any. If no
+ conversion could be performed, zero is returned. If the correct
+ value is outside the range of representable values, LLONG_MIN or
+ LLONG_MAX is returned (according to the sign of the value, if any),
+ and the value of the macro ERANGE is stored in errno.
+**/
+long long
+strtoll(const char * nptr, char ** endptr, int base)
+{
+ const char *pEnd;
+ long long Result = 0;
+ long long Previous;
+ int temp;
+ BOOLEAN Negative = FALSE;
+
+ pEnd = nptr;
+
+ if((base < 0) || (base == 1) || (base > 36)) {
+ if(endptr != NULL) {
+ *endptr = NULL;
+ }
+ return 0;
+ }
+ // Skip leading spaces.
+ while(isspace(*nptr)) ++nptr;
+
+ // Process Subject sequence: optional sign followed by digits.
+ if(*nptr == '+') {
+ Negative = FALSE;
+ ++nptr;
+ }
+ else if(*nptr == '-') {
+ Negative = TRUE;
+ ++nptr;
+ }
+
+ if(*nptr == '0') { /* Might be Octal or Hex */
+ if(toupper(nptr[1]) == 'X') { /* Looks like Hex */
+ if((base == 0) || (base == 16)) {
+ nptr += 2; /* Skip the "0X" */
+ base = 16; /* In case base was 0 */
+ }
+ }
+ else { /* Looks like Octal */
+ if((base == 0) || (base == 8)) {
+ ++nptr; /* Skip the leading "0" */
+ base = 8; /* In case base was 0 */
+ }
+ }
+ }
+ if(base == 0) { /* If still zero then must be decimal */
+ base = 10;
+ }
+ if(*nptr == '0') {
+ for( ; *nptr == '0'; ++nptr); /* Skip any remaining leading zeros */
+ pEnd = nptr;
+ }
+
+ while( isalnum(*nptr) && ((temp = Digit2Val(*nptr)) < base)) {
+ Previous = Result;
+ Result = MultS64x64 (Result, base) + (long long int)temp;
+ if( Result <= Previous) { // Detect Overflow
+ if(Negative) {
+ Result = LLONG_MIN;
+ }
+ else {
+ Result = LLONG_MAX;
+ }
+ Negative = FALSE;
+ errno = ERANGE;
+ break;
+ }
+ pEnd = ++nptr;
+ }
+ if(Negative) {
+ Result = -Result;
+ }
+
+ // Save pointer to final sequence
+ if(endptr != NULL) {
+ *endptr = (char *)pEnd;
+ }
+ return Result;
+}
+
+/** The strtol, strtoll, strtoul, and strtoull functions convert the initial
+ portion of the string pointed to by nptr to long int, long long int,
+ unsigned long int, and unsigned long long int representation, respectively.
+ First, they decompose the input string into three parts: an initial,
+ possibly empty, sequence of white-space characters (as specified by the
+ isspace function), a subject sequence resembling an integer represented in
+ some radix determined by the value of base, and a final string of one or
+ more unrecognized characters, including the terminating null character of
+ the input string. Then, they attempt to convert the subject sequence to an
+ integer, and return the result.
+
+ If the value of base is zero, the expected form of the subject sequence is
+ that of an integer constant, optionally preceded
+ by a plus or minus sign, but not including an integer suffix. If the value
+ of base is between 2 and 36 (inclusive), the expected form of the subject
+ sequence is a sequence of letters and digits representing an integer with
+ the radix specified by base, optionally preceded by a plus or minus sign,
+ but not including an integer suffix. The letters from a (or A) through z
+ (or Z) are ascribed the values 10 through 35; only letters and digits whose
+ ascribed values are less than that of base are permitted. If the value of
+ base is 16, the characters 0x or 0X may optionally precede the sequence of
+ letters and digits, following the sign if present.
+
+ The subject sequence is defined as the longest initial subsequence of the
+ input string, starting with the first non-white-space character, that is of
+ the expected form. The subject sequence contains no characters if the input
+ string is empty or consists entirely of white space, or if the first
+ non-white-space character is other than a sign or a permissible letter or digit.
+
+ If the subject sequence has the expected form and the value of base is
+ zero, the sequence of characters starting with the first digit is
+ interpreted as an integer constant. If the subject sequence has the
+ expected form and the value of base is between 2 and 36, it is used as the
+ base for conversion, ascribing to each letter its value as given above. If
+ the subject sequence begins with a minus sign, the value resulting from the
+ conversion is negated (in the return type). A pointer to the final string
+ is stored in the object pointed to by endptr, provided that endptr is
+ not a null pointer.
+
+ In other than the "C" locale, additional locale-specific subject sequence
+ forms may be accepted.
+
+ If the subject sequence is empty or does not have the expected form, no
+ conversion is performed; the value of nptr is stored in the object pointed
+ to by endptr, provided that endptr is not a null pointer.
+
+ @return The strtol, strtoll, strtoul, and strtoull functions return the
+ converted value, if any. If no conversion could be performed, zero
+ is returned. If the correct value is outside the range of
+ representable values, LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX,
+ ULONG_MAX, or ULLONG_MAX is returned (according to the return type
+ and sign of the value, if any), and the value of the macro ERANGE
+ is stored in errno.
+**/
+long
+strtol(const char * nptr, char ** endptr, int base)
+{
+ const char *pEnd;
+ long Result = 0;
+ long Previous;
+ int temp;
+ BOOLEAN Negative = FALSE;
+
+ pEnd = nptr;
+
+ if((base < 0) || (base == 1) || (base > 36)) {
+ if(endptr != NULL) {
+ *endptr = NULL;
+ }
+ return 0;
+ }
+ // Skip leading spaces.
+ while(isspace(*nptr)) ++nptr;
+
+ // Process Subject sequence: optional sign followed by digits.
+ if(*nptr == '+') {
+ Negative = FALSE;
+ ++nptr;
+ }
+ else if(*nptr == '-') {
+ Negative = TRUE;
+ ++nptr;
+ }
+
+ if(*nptr == '0') { /* Might be Octal or Hex */
+ if(toupper(nptr[1]) == 'X') { /* Looks like Hex */
+ if((base == 0) || (base == 16)) {
+ nptr += 2; /* Skip the "0X" */
+ base = 16; /* In case base was 0 */
+ }
+ }
+ else { /* Looks like Octal */
+ if((base == 0) || (base == 8)) {
+ ++nptr; /* Skip the leading "0" */
+ base = 8; /* In case base was 0 */
+ }
+ }
+ }
+ if(base == 0) { /* If still zero then must be decimal */
+ base = 10;
+ }
+ if(*nptr == '0') {
+ for( ; *nptr == '0'; ++nptr); /* Skip any remaining leading zeros */
+ pEnd = nptr;
+ }
+
+ while( isalnum(*nptr) && ((temp = Digit2Val(*nptr)) < base)) {
+ Previous = Result;
+ Result = (Result * base) + (long int)temp;
+ if( Result <= Previous) { // Detect Overflow
+ if(Negative) {
+ Result = LONG_MIN;
+ }
+ else {
+ Result = LONG_MAX;
+ }
+ Negative = FALSE;
+ errno = ERANGE;
+ break;
+ }
+ pEnd = ++nptr;
+ }
+ if(Negative) {
+ Result = -Result;
+ }
+
+ // Save pointer to final sequence
+ if(endptr != NULL) {
+ *endptr = (char *)pEnd;
+ }
+ return Result;
+}
+
+/** The strtoull function converts the initial portion of the string pointed to
+ by nptr to unsigned long long int representation.
+
+ See the description for strtol for more information.
+
+ @return The strtoull function returns the converted value, if any. If no
+ conversion could be performed, zero is returned. If the correct
+ value is outside the range of representable values, ULLONG_MAX is
+ returned and the value of the macro ERANGE is stored in errno.
+**/
+unsigned long long
+strtoull(const char * nptr, char ** endptr, int base)
+{
+ const char *pEnd;
+ unsigned long long Result = 0;
+ unsigned long long Previous;
+ int temp;
+
+ pEnd = nptr;
+
+ if((base < 0) || (base == 1) || (base > 36)) {
+ if(endptr != NULL) {
+ *endptr = NULL;
+ }
+ return 0;
+ }
+ // Skip leading spaces.
+ while(isspace(*nptr)) ++nptr;
+
+ // Process Subject sequence: optional + sign followed by digits.
+ if(*nptr == '+') {
+ ++nptr;
+ }
+
+ if(*nptr == '0') { /* Might be Octal or Hex */
+ if(toupper(nptr[1]) == 'X') { /* Looks like Hex */
+ if((base == 0) || (base == 16)) {
+ nptr += 2; /* Skip the "0X" */
+ base = 16; /* In case base was 0 */
+ }
+ }
+ else { /* Looks like Octal */
+ if((base == 0) || (base == 8)) {
+ ++nptr; /* Skip the leading "0" */
+ base = 8; /* In case base was 0 */
+ }
+ }
+ }
+ if(base == 0) { /* If still zero then must be decimal */
+ base = 10;
+ }
+ if(*nptr == '0') {
+ for( ; *nptr == '0'; ++nptr); /* Skip any remaining leading zeros */
+ pEnd = nptr;
+ }
+
+ while( isalnum(*nptr) && ((temp = Digit2Val(*nptr)) < base)) {
+ Previous = Result;
+ Result = DivU64x32 (Result, base) + (unsigned long long)temp;
+ if( Result < Previous) { // If we overflowed
+ Result = ULLONG_MAX;
+ errno = ERANGE;
+ break;
+ }
+ pEnd = ++nptr;
+ }
+
+ // Save pointer to final sequence
+ if(endptr != NULL) {
+ *endptr = (char *)pEnd;
+ }
+ return Result;
+}
+
+/**
+ edk2 Jansson port does not support doubles, simply return 0.
+
+ These conversion functions convert the initial portion of the string
+ pointed to by nptr to double, float, and long double representation,
+ respectively.
+
+ The strtod(), strtof(), and strtold() functions return the converted
+ value, if any.
+
+ If endptr is not NULL, a pointer to the character after the last charac-
+ ter used in the conversion is stored in the location referenced by
+ endptr.
+
+ If no conversion is performed, zero is returned and the value of nptr is
+ stored in the location referenced by endptr.
+
+ If the correct value would cause overflow, plus or minus HUGE_VAL,
+ HUGE_VALF, or HUGE_VALL is returned (according to the sign and type of
+ the return value), and ERANGE is stored in errno. If the correct value
+ would cause underflow, zero is returned and ERANGE is stored in errno.
+
+ @return Return 0.
+**/
+double
+strtod (const char * __restrict nptr, char ** __restrict endptr) {
+
+ DEBUG((DEBUG_INFO, "We don't supprot double type on edk2 yet!"));
+ ASSERT(FALSE);
+ return (double)0;
+}
+
+/**
+ Allocate and zero-initialize array.
+**/
+void *
+calloc(size_t Num, size_t Size)
+{
+ void *RetVal;
+ size_t NumSize;
+
+ NumSize = Num * Size;
+ RetVal = NULL;
+ if (NumSize != 0) {
+ RetVal = malloc(NumSize);
+ if( RetVal != NULL) {
+ (VOID)ZeroMem( RetVal, NumSize);
+ }
+ }
+ DEBUG((DEBUG_POOL, "0x%p = calloc(%d, %d)\n", RetVal, Num, Size));
+
+ return RetVal;
+}
+
+//
+// The arrays give the cumulative number of days up to the first of the
+// month number used as the index (1 -> 12) for regular and leap years.
+// The value at index 13 is for the whole year.
+//
+UINTN CumulativeDays[2][14] = {
+ {
+ 0,
+ 0,
+ 31,
+ 31 + 28,
+ 31 + 28 + 31,
+ 31 + 28 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31
+ },
+ {
+ 0,
+ 0,
+ 31,
+ 31 + 29,
+ 31 + 29 + 31,
+ 31 + 29 + 31 + 30,
+ 31 + 29 + 31 + 30 + 31,
+ 31 + 29 + 31 + 30 + 31 + 30,
+ 31 + 29 + 31 + 30 + 31 + 30 + 31,
+ 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
+ 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+ 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+ 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+ 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31
+ }
+};
+
+#define IsLeap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+#define SECSPERMIN (60)
+#define SECSPERHOUR (60 * 60)
+#define SECSPERDAY (24 * SECSPERHOUR)
+
+/**
+ Get the system time as seconds elapsed since midnight, January 1, 1970.
+**/
+time_t time (time_t *timer)
+{
+ EFI_TIME Time;
+ time_t CalTime;
+ UINTN Year;
+
+ //
+ // Get the current time and date information
+ //
+ gRT->GetTime (&Time, NULL);
+
+ //
+ // Years Handling
+ // UTime should now be set to 00:00:00 on Jan 1 of the current year.
+ //
+ for (Year = 1970, CalTime = 0; Year != Time.Year; Year++) {
+ CalTime = CalTime + (time_t)(CumulativeDays[IsLeap(Year)][13] * SECSPERDAY);
+ }
+
+ //
+ // Add in number of seconds for current Month, Day, Hour, Minute, Seconds, and TimeZone adjustment
+ //
+ CalTime = CalTime +
+ (time_t)((Time.TimeZone != EFI_UNSPECIFIED_TIMEZONE) ? (Time.TimeZone * 60) : 0) +
+ (time_t)(CumulativeDays[IsLeap(Time.Year)][Time.Month] * SECSPERDAY) +
+ (time_t)(((Time.Day > 0) ? Time.Day - 1 : 0) * SECSPERDAY) +
+ (time_t)(Time.Hour * SECSPERHOUR) +
+ (time_t)(Time.Minute * 60) +
+ (time_t)Time.Second;
+
+ if (timer != NULL) {
+ *timer = CalTime;
+ }
+
+ return CalTime;
+}
+
+/**
+ Performs a quick sort
+**/
+void qsort (void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
+{
+
+ ASSERT (base != NULL);
+ ASSERT (compare != NULL);
+
+ PerformQuickSort (base, (UINTN)num, (UINTN)width, (SORT_COMPARE)compare);
+ return;
+}
+
+/**
+ Get character from stream, we don't support file operastion on edk2 JSON library.
+
+ @return Returns the character currently pointed by the internal file position indicator of the specified stream
+
+**/
+int fgetc(FILE * _File){
+ return 0;
+}
+/**
+ This function check if this is the formating string specifier.
+
+ @param[in] FormatString A Null-terminated ASCII format string.
+ @param[in,out] CurrentPosition The starting position at the given string to check for
+ "[flags][width][.precision][length]s" string specifier.
+ @param[in] StrLength Maximum string length.
+
+ @return BOOLEAN TRUE means this is the formating string specifier. CurrentPosition is
+ returned at the position of "s".
+ FALSE means this is not the formating string specifier.. CurrentPosition is
+ returned at the position of failed character.
+
+**/
+BOOLEAN
+CheckFormatingString (
+ IN CONST CHAR8 *FormatString,
+ IN OUT UINTN *CurrentPosition,
+ IN UINTN StrLength
+ )
+{
+ CHAR8 FormatStringParamater;
+
+ while (*(FormatString + *CurrentPosition) != 's') {
+ //
+ // Loop until reach character 's' if the formating string is
+ // compliant with "[flags][width][.precision][length]" format for
+ // the string specifier.
+ //
+ FormatStringParamater = *(FormatString + *CurrentPosition);
+ if ((FormatStringParamater != '-') &&
+ (FormatStringParamater != '+') &&
+ (FormatStringParamater != '*') &&
+ (FormatStringParamater != '.') &&
+ !(((UINTN)FormatStringParamater >= (UINTN)'0') && ((UINTN)FormatStringParamater <= (UINTN)'9'))
+ ) {
+ return FALSE;
+ }
+ (*CurrentPosition)++;
+ if (*CurrentPosition >= StrLength) {
+ return FALSE;
+ }
+ };
+ return TRUE;
+}
+
+/**
+ This function clones *FormatString however replaces "%s" with "%a" in the
+ returned string.
+
+ @param[in] A Null-terminated ASCII format string.
+
+ @return The new format string. Caller has to free the memory of this string
+ using FreePool().
+
+**/
+CHAR8 *
+ReplaceUnicodeToAsciiStrFormat (
+ IN CONST CHAR8 *FormatString
+)
+{
+ UINTN FormatStrSize;
+ UINTN FormatStrIndex;
+ UINTN FormatStrSpecifier;
+ BOOLEAN PercentageMark;
+ CHAR8 *TempFormatBuffer;
+ BOOLEAN IsFormatString;
+
+ //
+ // Error checking.
+ //
+ if (FormatString == NULL) {
+ return NULL;
+ }
+ FormatStrSize = AsciiStrSize(FormatString);
+ if (FormatStrSize == 0) {
+ return NULL;
+ }
+ TempFormatBuffer = AllocatePool(FormatStrSize); // Allocate memory for the
+ // new string.
+ if (TempFormatBuffer== NULL) {
+ return NULL;
+ }
+ //
+ // Clone *FormatString but replace "%s" wih "%a".
+ // "%%" is not considered as the format tag.
+ //
+ PercentageMark = FALSE;
+ FormatStrIndex = 0;
+ while (FormatStrIndex < FormatStrSize) {
+ if (PercentageMark == TRUE) {
+ //
+ // Previous character is "%".
+ //
+ PercentageMark = FALSE;
+ if (*(FormatString + FormatStrIndex) != '%') { // Check if this is double "%".
+ FormatStrSpecifier = FormatStrIndex;
+ //
+ // Check if this is the formating string specifier.
+ //
+ IsFormatString = CheckFormatingString (FormatString, &FormatStrSpecifier, FormatStrSize);
+ if ((FormatStrSpecifier - FormatStrIndex) != 0) {
+ CopyMem((VOID *)(TempFormatBuffer + FormatStrIndex),
+ (VOID *)(FormatString + FormatStrIndex),
+ FormatStrSpecifier - FormatStrIndex
+ );
+ }
+ FormatStrIndex = FormatStrSpecifier;
+ if (IsFormatString == TRUE) {
+ //
+ // Replace 's' with 'a' which is printed in ASCII
+ // format on edk2 environment.
+ //
+ *(TempFormatBuffer + FormatStrSpecifier) = 'a';
+ FormatStrIndex ++;
+ }
+ continue;
+ }
+ goto ContinueCheck;
+ }
+ if (*(FormatString + FormatStrIndex) == '%') {
+ //
+ // This character is "%", set the flag.
+ //
+ PercentageMark = TRUE;
+ }
+ContinueCheck:
+ //
+ // Clone character to the new string and advance FormatStrIndex
+ // to process next character.
+ //
+ *(TempFormatBuffer + FormatStrIndex) = *(FormatString + FormatStrIndex);
+ FormatStrIndex++;
+ };
+ return TempFormatBuffer;
+}
+
+/**
+ This is the Redfish version of CRT vsnprintf function, this function replaces "%s" to
+ "%a" before invoking AsciiVSPrint(). That is because "%s" is unicode base on edk2
+ environment however "%s" is ascii code base on vsnprintf().
+ See definitions of AsciiVSPrint() for the details.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param Marker VA_LIST marker for the variable argument list.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+RedfishAsciiVSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ IN VA_LIST Marker
+ )
+{
+ CHAR8 *TempFormatBuffer;
+ UINTN LenStrProduced;
+
+ //
+ // Looking for "%s" in the format string and replace it
+ // with "%a" for printing ASCII code characters on edk2
+ // environment.
+ //
+ TempFormatBuffer = ReplaceUnicodeToAsciiStrFormat (FormatString);
+ if (TempFormatBuffer == NULL) {
+ return 0;
+ }
+ LenStrProduced = AsciiVSPrint (StartOfBuffer, BufferSize, (CONST CHAR8 *)TempFormatBuffer, Marker);
+ FreePool (TempFormatBuffer);
+ return LenStrProduced;
+}
+
+/**
+ This is the Redfish version of CRT snprintf function, this function replaces "%s" to
+ "%a" before invoking AsciiSPrint(). That is because "%s" is unicode base on edk2
+ environment however "%s" is ascii code base on snprintf().
+ See definitions of AsciiSPrint() for the details.
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+
+ @return The number of ASCII characters in the produced output buffer not including the
+ Null-terminator.
+
+**/
+UINTN
+EFIAPI
+RedfishAsciiSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ ...
+ )
+{
+ VA_LIST Marker;
+ UINTN LenStrProduced;
+
+ VA_START(Marker, FormatString);
+ LenStrProduced = RedfishAsciiVSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
+ return LenStrProduced;
+}
+
diff --git a/RedfishPkg/PrivateLibrary/RedfishCrtLib/RedfishCrtLib.inf b/RedfishPkg/PrivateLibrary/RedfishCrtLib/RedfishCrtLib.inf
new file mode 100644
index 0000000000..5c1c7cffa6
--- /dev/null
+++ b/RedfishPkg/PrivateLibrary/RedfishCrtLib/RedfishCrtLib.inf
@@ -0,0 +1,38 @@
+## @file
+# Redfish C Runtime Library for opensource projects.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001b
+ BASE_NAME = RedfishCrtLib
+ FILE_GUID = 8263B8AC-D021-425D-B337-3EC96F5DC19B
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RedfishCrtLib|DXE_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 RISCV64
+#
+
+[Sources]
+ RedfishCrtLib.c
+
+[LibraryClasses]
+ BaseLib
+ BaseSortLib
+ DebugLib
+ MemoryAllocationLib
+ UefiRuntimeServicesTableLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ RedfishPkg/RedfishPkg.dec
+
+