/** @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; | |
char errnum_message [] = "We don't support to map errnum to the error message on edk2 Redfish\n"; | |
// This is required to keep VC++ happy if you use floating-point | |
int _fltused = 1; | |
/** | |
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; | |
} | |
static UINT8 BitMask[] = { | |
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 | |
}; | |
#define WHICH8(c) ((unsigned char)(c) >> 3) | |
#define WHICH_BIT(c) (BitMask[((c) & 0x7)]) | |
#define BITMAP64 ((UINT64 *)bitmap) | |
static | |
void | |
BuildBitmap(unsigned char * bitmap, const char *s2, int n) | |
{ | |
unsigned char bit; | |
int index; | |
// Initialize bitmap. Bit 0 is always 1 which corresponds to '\0' | |
for (BITMAP64[0] = index = 1; index < n; index++) { | |
BITMAP64[index] = 0; | |
} | |
// Set bits in bitmap corresponding to the characters in s2 | |
for (; *s2 != '\0'; s2++) { | |
index = WHICH8(*s2); | |
bit = WHICH_BIT(*s2); | |
bitmap[index] = bitmap[index] | bit; | |
} | |
} | |
/** The strpbrk function locates the first occurrence in the string pointed to | |
by s1 of any character from the string pointed to by s2. | |
@return The strpbrk function returns a pointer to the character, or a | |
null pointer if no character from s2 occurs in s1. | |
**/ | |
char * | |
strpbrk(const char *s1, const char *s2) | |
{ | |
UINT8 bitmap[ (((UCHAR_MAX + 1) / CHAR_BIT) + (CHAR_BIT - 1)) & ~7U]; | |
UINT8 bit; | |
int index; | |
BuildBitmap( bitmap, s2, sizeof(bitmap) / sizeof(UINT64)); | |
for( ; *s1 != '\0'; ++s1) { | |
index = WHICH8(*s1); | |
bit = WHICH_BIT(*s1); | |
if( (bitmap[index] & bit) != 0) { | |
return (char *)s1; | |
} | |
} | |
return NULL; | |
} | |
/** The strerror function maps the number in errnum to a message string. | |
Typically, the values for errnum come from errno, but strerror shall map | |
any value of type int to a message. | |
The implementation shall behave as if no library function calls the | |
strerror function. | |
@return The strerror function returns a pointer to the string, the | |
contents of which are locale specific. The array pointed to | |
shall not be modified by the program, but may be overwritten by | |
a subsequent call to the strerror function. | |
**/ | |
char * | |
strerror(int errnum) | |
{ | |
return errnum_message; | |
} | |
/** | |
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 EOF; | |
} | |
/** | |
Open stream file, we don't support file operastion on edk2 JSON library. | |
@return 0 Unsupported | |
**/ | |
FILE *fopen (const char *filename, const char *mode) { | |
return NULL; | |
} | |
/** | |
Read stream from file, we don't support file operastion on edk2 JSON library. | |
@return 0 Unsupported | |
**/ | |
size_t fread (void * ptr, size_t size, size_t count, FILE * stream) { | |
return 0; | |
} | |
/** | |
Write stream from file, we don't support file operastion on edk2 JSON library. | |
@return 0 Unsupported | |
**/ | |
size_t fwrite (const void * ptr, size_t size, size_t count, FILE * stream) { | |
return 0; | |
} | |
/** | |
Close file, we don't support file operastion on edk2 JSON library. | |
@return 0 Unsupported | |
**/ | |
int fclose (FILE * stream) { | |
return EOF; | |
} | |
/** | |
Write the formatted string to file, we don't support file operastion on edk2 JSON library. | |
@return 0 Unsupported | |
**/ | |
int fprintf (FILE * stream, const char * format, ...) { | |
return -1; | |
} | |
/** | |
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; | |
} | |