1 /** @file
2   CRT wrapper functions for system call,the string operation functions
3   are remodeled after edk2-libc.
4 
5   Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
6   (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR>
7 
8     SPDX-License-Identifier: BSD-2-Clause-Patent
9 
10 **/
11 #include <Uefi.h>
12 #include <Library/RedfishCrtLib.h>
13 #include <Library/MemoryAllocationLib.h>
14 #include <Library/SortLib.h>
15 #include <Library/UefiRuntimeServicesTableLib.h>
16 
17 int  errno = 0;
18 char errnum_message [] = "We don't support to map errnum to the error message on edk2 Redfish\n";
19 
20 // This is required to keep VC++ happy if you use floating-point
21 int _fltused  = 1;
22 
23 /**
24   Determine if a particular character is an alphanumeric character
25   @return  Returns 1 if c is an alphanumeric character, otherwise returns 0.
26 **/
isalnum(int c)27 int isalnum (int c)
28 {
29   //
30   // <alnum> ::= [0-9] | [a-z] | [A-Z]
31   //
32   return ((('0' <= (c)) && ((c) <= '9')) ||
33           (('a' <= (c)) && ((c) <= 'z')) ||
34           (('A' <= (c)) && ((c) <= 'Z')));
35 }
36 
37 /**
38   Determine if a particular character is a digital character
39 
40   @return  Returns 1 if c is an digital character, otherwise returns 0.
41 **/
isdchar(int c)42 int isdchar (int c)
43 {
44   //
45   // [0-9] | [e +-.]
46   //
47   return ((('0' <= (c)) && ((c) <= '9')) ||
48           (c == 'e') || (c == 'E') ||
49           (c == '+') || (c == '-') ||
50           (c == '.'));
51 }
52 
53 /**
54   Determine if a particular character is a space character
55 
56   @return  Returns 1 if c is a space character
57 **/
isspace(int c)58 int isspace (int c)
59 {
60   //
61   // <space> ::= [ ]
62   //
63   return ((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n') || ((c) == '\v')  || ((c) == '\f');
64 }
65 
66 /**
67   Allocates memory blocks
68 */
malloc(size_t size)69 void *malloc (size_t size)
70 {
71   return AllocatePool ((UINTN) size);
72 }
73 
74 /**
75   De-allocates or frees a memory block
76 */
free(void * ptr)77 void free (void *ptr)
78 {
79   //
80   // In Standard C, free() handles a null pointer argument transparently. This
81   // is not true of FreePool() below, so protect it.
82   //
83   if (ptr != NULL) {
84     FreePool (ptr);
85   }
86 }
87 
88 /**
89   NetBSD Compatibility Function strdup creates a duplicate copy of a string.
90 
91   @return  Returns the pointer to duplicated string.
92 **/
strdup(const char * str)93 char * strdup(const char *str)
94 {
95   size_t len;
96   char *copy;
97 
98   len = strlen(str) + 1;
99   if ((copy = malloc(len)) == NULL)
100     return (NULL);
101   memcpy(copy, str, len);
102   return (copy);
103 }
104 
105 /** The toupper function converts a lowercase letter to a corresponding
106     uppercase letter.
107 
108     @param[in]    c   The character to be converted.
109 
110     @return   If the argument is a character for which islower is true and
111               there are one or more corresponding characters, as specified by
112               the current locale, for which isupper is true, the toupper
113               function returns one of the corresponding characters (always the
114               same one for any given locale); otherwise, the argument is
115               returned unchanged.
116 **/
117 int
toupper(IN int c)118 toupper(
119   IN  int c
120   )
121 {
122   if ( (c >= 'a') && (c <= 'z') ) {
123     c = c - ('a' - 'A');
124   }
125   return c;
126 }
127 
128 /**
129   Digit to a value.
130 
131   @return  Returns the value of digit.
132 **/
133 int
Digit2Val(int c)134 Digit2Val( int c)
135 {
136   if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))) {  /* If c is one of [A-Za-z]... */
137     c = toupper(c) - 7;   // Adjust so 'A' is ('9' + 1)
138   }
139   return c - '0';   // Value returned is between 0 and 35, inclusive.
140 }
141 
142 
143 /** The strtoll function converts the initial portion of the string pointed to
144     by nptr to long long int representation.
145 
146     See the description for strtol for more information.
147 
148   @return   The strtoll function returns the converted value, if any. If no
149             conversion could be performed, zero is returned. If the correct
150             value is outside the range of representable values, LLONG_MIN or
151             LLONG_MAX is returned (according to the sign of the value, if any),
152             and the value of the macro ERANGE is stored in errno.
153 **/
154 long long
strtoll(const char * nptr,char ** endptr,int base)155 strtoll(const char * nptr, char ** endptr, int base)
156 {
157   const char *pEnd;
158   long long   Result = 0;
159   long long   Previous;
160   int         temp;
161   BOOLEAN     Negative = FALSE;
162 
163   pEnd = nptr;
164 
165   if((base < 0) || (base == 1) || (base > 36)) {
166     if(endptr != NULL) {
167     *endptr = NULL;
168     }
169     return 0;
170   }
171   // Skip leading spaces.
172   while(isspace(*nptr))   ++nptr;
173 
174   // Process Subject sequence: optional sign followed by digits.
175   if(*nptr == '+') {
176     Negative = FALSE;
177     ++nptr;
178   }
179   else if(*nptr == '-') {
180     Negative = TRUE;
181     ++nptr;
182   }
183 
184   if(*nptr == '0') {  /* Might be Octal or Hex */
185     if(toupper(nptr[1]) == 'X') {   /* Looks like Hex */
186       if((base == 0) || (base == 16)) {
187         nptr += 2;  /* Skip the "0X"      */
188         base = 16;  /* In case base was 0 */
189       }
190     }
191     else {    /* Looks like Octal */
192       if((base == 0) || (base == 8)) {
193         ++nptr;     /* Skip the leading "0" */
194         base = 8;   /* In case base was 0   */
195       }
196     }
197   }
198   if(base == 0) {   /* If still zero then must be decimal */
199     base = 10;
200   }
201   if(*nptr  == '0') {
202     for( ; *nptr == '0'; ++nptr);  /* Skip any remaining leading zeros */
203     pEnd = nptr;
204   }
205 
206   while( isalnum(*nptr) && ((temp = Digit2Val(*nptr)) < base)) {
207     Previous = Result;
208     Result = MultS64x64 (Result, base) + (long long int)temp;
209     if( Result <= Previous) {   // Detect Overflow
210       if(Negative) {
211         Result = LLONG_MIN;
212       }
213       else {
214         Result = LLONG_MAX;
215       }
216       Negative = FALSE;
217       errno = ERANGE;
218       break;
219     }
220     pEnd = ++nptr;
221   }
222   if(Negative) {
223     Result = -Result;
224   }
225 
226   // Save pointer to final sequence
227   if(endptr != NULL) {
228     *endptr = (char *)pEnd;
229   }
230   return Result;
231 }
232 
233 /** The strtol, strtoll, strtoul, and strtoull functions convert the initial
234     portion of the string pointed to by nptr to long int, long long int,
235     unsigned long int, and unsigned long long int representation, respectively.
236     First, they decompose the input string into three parts: an initial,
237     possibly empty, sequence of white-space characters (as specified by the
238     isspace function), a subject sequence resembling an integer represented in
239     some radix determined by the value of base, and a final string of one or
240     more unrecognized characters, including the terminating null character of
241     the input string. Then, they attempt to convert the subject sequence to an
242     integer, and return the result.
243 
244     If the value of base is zero, the expected form of the subject sequence is
245     that of an integer constant, optionally preceded
246     by a plus or minus sign, but not including an integer suffix. If the value
247     of base is between 2 and 36 (inclusive), the expected form of the subject
248     sequence is a sequence of letters and digits representing an integer with
249     the radix specified by base, optionally preceded by a plus or minus sign,
250     but not including an integer suffix. The letters from a (or A) through z
251     (or Z) are ascribed the values 10 through 35; only letters and digits whose
252     ascribed values are less than that of base are permitted. If the value of
253     base is 16, the characters 0x or 0X may optionally precede the sequence of
254     letters and digits, following the sign if present.
255 
256     The subject sequence is defined as the longest initial subsequence of the
257     input string, starting with the first non-white-space character, that is of
258     the expected form. The subject sequence contains no characters if the input
259     string is empty or consists entirely of white space, or if the first
260     non-white-space character is other than a sign or a permissible letter or digit.
261 
262     If the subject sequence has the expected form and the value of base is
263     zero, the sequence of characters starting with the first digit is
264     interpreted as an integer constant. If the subject sequence has the
265     expected form and the value of base is between 2 and 36, it is used as the
266     base for conversion, ascribing to each letter its value as given above. If
267     the subject sequence begins with a minus sign, the value resulting from the
268     conversion is negated (in the return type). A pointer to the final string
269     is stored in the object pointed to by endptr, provided that endptr is
270     not a null pointer.
271 
272     In other than the "C" locale, additional locale-specific subject sequence
273     forms may be accepted.
274 
275     If the subject sequence is empty or does not have the expected form, no
276     conversion is performed; the value of nptr is stored in the object pointed
277     to by endptr, provided that endptr is not a null pointer.
278 
279   @return   The strtol, strtoll, strtoul, and strtoull functions return the
280             converted value, if any. If no conversion could be performed, zero
281             is returned. If the correct value is outside the range of
282             representable values, LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX,
283             ULONG_MAX, or ULLONG_MAX is returned (according to the return type
284             and sign of the value, if any), and the value of the macro ERANGE
285             is stored in errno.
286 **/
287 long
strtol(const char * nptr,char ** endptr,int base)288 strtol(const char * nptr, char ** endptr, int base)
289 {
290   const char *pEnd;
291   long        Result = 0;
292   long        Previous;
293   int         temp;
294   BOOLEAN     Negative = FALSE;
295 
296   pEnd = nptr;
297 
298   if((base < 0) || (base == 1) || (base > 36)) {
299     if(endptr != NULL) {
300     *endptr = NULL;
301     }
302     return 0;
303   }
304   // Skip leading spaces.
305   while(isspace(*nptr))   ++nptr;
306 
307   // Process Subject sequence: optional sign followed by digits.
308   if(*nptr == '+') {
309     Negative = FALSE;
310     ++nptr;
311   }
312   else if(*nptr == '-') {
313     Negative = TRUE;
314     ++nptr;
315   }
316 
317   if(*nptr == '0') {  /* Might be Octal or Hex */
318     if(toupper(nptr[1]) == 'X') {   /* Looks like Hex */
319       if((base == 0) || (base == 16)) {
320         nptr += 2;  /* Skip the "0X"      */
321         base = 16;  /* In case base was 0 */
322       }
323     }
324     else {    /* Looks like Octal */
325       if((base == 0) || (base == 8)) {
326         ++nptr;     /* Skip the leading "0" */
327         base = 8;   /* In case base was 0   */
328       }
329     }
330   }
331   if(base == 0) {   /* If still zero then must be decimal */
332     base = 10;
333   }
334   if(*nptr  == '0') {
335     for( ; *nptr == '0'; ++nptr);  /* Skip any remaining leading zeros */
336     pEnd = nptr;
337   }
338 
339   while( isalnum(*nptr) && ((temp = Digit2Val(*nptr)) < base)) {
340     Previous = Result;
341     Result = (Result * base) + (long int)temp;
342     if( Result <= Previous) {   // Detect Overflow
343       if(Negative) {
344         Result = LONG_MIN;
345       }
346       else {
347         Result = LONG_MAX;
348       }
349       Negative = FALSE;
350       errno = ERANGE;
351       break;
352     }
353     pEnd = ++nptr;
354   }
355   if(Negative) {
356     Result = -Result;
357   }
358 
359   // Save pointer to final sequence
360   if(endptr != NULL) {
361     *endptr = (char *)pEnd;
362   }
363   return Result;
364 }
365 
366 /** The strtoull function converts the initial portion of the string pointed to
367     by nptr to unsigned long long int representation.
368 
369     See the description for strtol for more information.
370 
371   @return   The strtoull function returns the converted value, if any. If no
372             conversion could be performed, zero is returned. If the correct
373             value is outside the range of representable values, ULLONG_MAX is
374             returned and the value of the macro ERANGE is stored in errno.
375 **/
376 unsigned long long
strtoull(const char * nptr,char ** endptr,int base)377 strtoull(const char * nptr, char ** endptr, int base)
378 {
379   const char           *pEnd;
380   unsigned long long    Result = 0;
381   unsigned long long    Previous;
382   int                   temp;
383 
384   pEnd = nptr;
385 
386   if((base < 0) || (base == 1) || (base > 36)) {
387     if(endptr != NULL) {
388     *endptr = NULL;
389     }
390     return 0;
391   }
392   // Skip leading spaces.
393   while(isspace(*nptr))   ++nptr;
394 
395   // Process Subject sequence: optional + sign followed by digits.
396   if(*nptr == '+') {
397     ++nptr;
398   }
399 
400   if(*nptr == '0') {  /* Might be Octal or Hex */
401     if(toupper(nptr[1]) == 'X') {   /* Looks like Hex */
402       if((base == 0) || (base == 16)) {
403         nptr += 2;  /* Skip the "0X"      */
404         base = 16;  /* In case base was 0 */
405       }
406     }
407     else {    /* Looks like Octal */
408       if((base == 0) || (base == 8)) {
409         ++nptr;     /* Skip the leading "0" */
410         base = 8;   /* In case base was 0   */
411       }
412     }
413   }
414   if(base == 0) {   /* If still zero then must be decimal */
415     base = 10;
416   }
417   if(*nptr  == '0') {
418     for( ; *nptr == '0'; ++nptr);  /* Skip any remaining leading zeros */
419     pEnd = nptr;
420   }
421 
422   while( isalnum(*nptr) && ((temp = Digit2Val(*nptr)) < base)) {
423     Previous = Result;
424     Result = DivU64x32 (Result, base) + (unsigned long long)temp;
425     if( Result < Previous)  {   // If we overflowed
426       Result = ULLONG_MAX;
427       errno = ERANGE;
428       break;
429     }
430     pEnd = ++nptr;
431   }
432 
433   // Save pointer to final sequence
434   if(endptr != NULL) {
435     *endptr = (char *)pEnd;
436   }
437   return Result;
438 }
439 
440 /**
441   edk2 Jansson port does not support doubles, simply return 0.
442 
443   These conversion functions convert the initial portion of the string
444   pointed to by nptr to double, float, and long double representation,
445   respectively.
446 
447   The strtod(), strtof(), and strtold() functions return the converted
448   value, if any.
449 
450   If endptr is not NULL, a pointer to the character after the last charac-
451   ter used in the conversion is stored in the location referenced by
452   endptr.
453 
454   If no conversion is performed, zero is returned and the value of nptr is
455   stored in the location referenced by endptr.
456 
457   If the correct value would cause overflow, plus or minus HUGE_VAL,
458   HUGE_VALF, or HUGE_VALL is returned (according to the sign and type of
459   the return value), and ERANGE is stored in errno.  If the correct value
460   would cause underflow, zero is returned and ERANGE is stored in errno.
461 
462   @return  Return 0.
463 **/
464 double
strtod(const char * __restrict nptr,char ** __restrict endptr)465 strtod (const char * __restrict nptr, char ** __restrict endptr) {
466 
467     DEBUG((DEBUG_INFO, "We don't supprot double type on edk2 yet!"));
468     ASSERT(FALSE);
469     return (double)0;
470 }
471 
472 static UINT8  BitMask[] = {
473   0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
474   };
475 
476 #define WHICH8(c)     ((unsigned char)(c) >> 3)
477 #define WHICH_BIT(c)  (BitMask[((c) & 0x7)])
478 #define BITMAP64      ((UINT64 *)bitmap)
479 
480 static
481 void
BuildBitmap(unsigned char * bitmap,const char * s2,int n)482 BuildBitmap(unsigned char * bitmap, const char *s2, int n)
483 {
484   unsigned char bit;
485   int           index;
486 
487   // Initialize bitmap.  Bit 0 is always 1 which corresponds to '\0'
488   for (BITMAP64[0] = index = 1; index < n; index++) {
489     BITMAP64[index] = 0;
490   }
491 
492   // Set bits in bitmap corresponding to the characters in s2
493   for (; *s2 != '\0'; s2++) {
494     index = WHICH8(*s2);
495     bit = WHICH_BIT(*s2);
496     bitmap[index] = bitmap[index] | bit;
497   }
498 }
499 
500 /** The strpbrk function locates the first occurrence in the string pointed to
501     by s1 of any character from the string pointed to by s2.
502 
503     @return   The strpbrk function returns a pointer to the character, or a
504               null pointer if no character from s2 occurs in s1.
505 **/
506 char *
strpbrk(const char * s1,const char * s2)507 strpbrk(const char *s1, const char *s2)
508 {
509   UINT8 bitmap[ (((UCHAR_MAX + 1) / CHAR_BIT) + (CHAR_BIT - 1)) & ~7U];
510   UINT8 bit;
511   int index;
512 
513   BuildBitmap( bitmap, s2, sizeof(bitmap) / sizeof(UINT64));
514 
515   for( ; *s1 != '\0'; ++s1) {
516     index = WHICH8(*s1);
517     bit = WHICH_BIT(*s1);
518     if( (bitmap[index] & bit) != 0) {
519       return (char *)s1;
520     }
521   }
522   return NULL;
523 }
524 
525 /** The strerror function maps the number in errnum to a message string.
526     Typically, the values for errnum come from errno, but strerror shall map
527     any value of type int to a message.
528 
529     The implementation shall behave as if no library function calls the
530     strerror function.
531 
532     @return   The strerror function returns a pointer to the string, the
533               contents of which are locale specific.  The array pointed to
534               shall not be modified by the program, but may be overwritten by
535               a subsequent call to the strerror function.
536 **/
537 char *
strerror(int errnum)538 strerror(int errnum)
539 {
540   return errnum_message;
541 }
542 
543 /**
544   Allocate and zero-initialize array.
545 **/
546 void *
calloc(size_t Num,size_t Size)547 calloc(size_t Num, size_t Size)
548 {
549   void       *RetVal;
550   size_t      NumSize;
551 
552   NumSize = Num * Size;
553   RetVal  = NULL;
554   if (NumSize != 0) {
555   RetVal = malloc(NumSize);
556   if( RetVal != NULL) {
557     (VOID)ZeroMem( RetVal, NumSize);
558   }
559   }
560   DEBUG((DEBUG_POOL, "0x%p = calloc(%d, %d)\n", RetVal, Num, Size));
561 
562   return RetVal;
563 }
564 
565 //
566 //  The arrays give the cumulative number of days up to the first of the
567 //  month number used as the index (1 -> 12) for regular and leap years.
568 //  The value at index 13 is for the whole year.
569 //
570 UINTN CumulativeDays[2][14] = {
571   {
572     0,
573     0,
574     31,
575     31 + 28,
576     31 + 28 + 31,
577     31 + 28 + 31 + 30,
578     31 + 28 + 31 + 30 + 31,
579     31 + 28 + 31 + 30 + 31 + 30,
580     31 + 28 + 31 + 30 + 31 + 30 + 31,
581     31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
582     31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
583     31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
584     31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
585     31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31
586   },
587   {
588     0,
589     0,
590     31,
591     31 + 29,
592     31 + 29 + 31,
593     31 + 29 + 31 + 30,
594     31 + 29 + 31 + 30 + 31,
595     31 + 29 + 31 + 30 + 31 + 30,
596     31 + 29 + 31 + 30 + 31 + 30 + 31,
597     31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
598     31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
599     31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
600     31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
601     31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31
602   }
603 };
604 
605 #define IsLeap(y)   (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
606 #define SECSPERMIN  (60)
607 #define SECSPERHOUR (60 * 60)
608 #define SECSPERDAY  (24 * SECSPERHOUR)
609 
610 /**
611   Get the system time as seconds elapsed since midnight, January 1, 1970.
612 **/
time(time_t * timer)613 time_t time (time_t *timer)
614 {
615   EFI_TIME  Time;
616   time_t    CalTime;
617   UINTN     Year;
618 
619   //
620   // Get the current time and date information
621   //
622   gRT->GetTime (&Time, NULL);
623 
624   //
625   // Years Handling
626   // UTime should now be set to 00:00:00 on Jan 1 of the current year.
627   //
628   for (Year = 1970, CalTime = 0; Year != Time.Year; Year++) {
629     CalTime = CalTime + (time_t)(CumulativeDays[IsLeap(Year)][13] * SECSPERDAY);
630   }
631 
632   //
633   // Add in number of seconds for current Month, Day, Hour, Minute, Seconds, and TimeZone adjustment
634   //
635   CalTime = CalTime +
636             (time_t)((Time.TimeZone != EFI_UNSPECIFIED_TIMEZONE) ? (Time.TimeZone * 60) : 0) +
637             (time_t)(CumulativeDays[IsLeap(Time.Year)][Time.Month] * SECSPERDAY) +
638             (time_t)(((Time.Day > 0) ? Time.Day - 1 : 0) * SECSPERDAY) +
639             (time_t)(Time.Hour * SECSPERHOUR) +
640             (time_t)(Time.Minute * 60) +
641             (time_t)Time.Second;
642 
643   if (timer != NULL) {
644     *timer = CalTime;
645   }
646 
647   return CalTime;
648 }
649 
650 /**
651   Performs a quick sort
652 **/
qsort(void * base,size_t num,size_t width,int (* compare)(const void *,const void *))653 void qsort (void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
654 {
655 
656   ASSERT (base    != NULL);
657   ASSERT (compare != NULL);
658 
659   PerformQuickSort (base, (UINTN)num, (UINTN)width, (SORT_COMPARE)compare);
660   return;
661 }
662 
663 /**
664   Get character from stream, we don't support file operastion on edk2 JSON library.
665 
666   @return Returns the character currently pointed by the internal file position indicator of the specified stream
667 
668 **/
fgetc(FILE * _File)669 int fgetc(FILE * _File){
670    return EOF;
671 }
672 /**
673   Open stream file, we don't support file operastion on edk2 JSON library.
674 
675   @return 0 Unsupported
676 
677 **/
fopen(const char * filename,const char * mode)678 FILE *fopen (const char *filename, const char *mode) {
679   return NULL;
680 }
681 /**
682   Read stream from file, we don't support file operastion on edk2 JSON library.
683 
684   @return 0 Unsupported
685 
686 **/
fread(void * ptr,size_t size,size_t count,FILE * stream)687 size_t fread (void * ptr, size_t size, size_t count, FILE * stream) {
688   return 0;
689 }
690 /**
691   Write stream from file, we don't support file operastion on edk2 JSON library.
692 
693   @return 0 Unsupported
694 
695 **/
fwrite(const void * ptr,size_t size,size_t count,FILE * stream)696 size_t fwrite (const void * ptr, size_t size, size_t count, FILE * stream) {
697   return 0;
698 }
699 /**
700   Close file, we don't support file operastion on edk2 JSON library.
701 
702   @return 0 Unsupported
703 
704 **/
fclose(FILE * stream)705 int fclose (FILE * stream) {
706   return EOF;
707 }
708 /**
709   Write the formatted string to file, we don't support file operastion on edk2 JSON library.
710 
711   @return 0 Unsupported
712 
713 **/
fprintf(FILE * stream,const char * format,...)714 int fprintf (FILE * stream, const char * format, ...) {
715   return -1;
716 }
717 /**
718   This function check if this is the formating string specifier.
719 
720   @param[in]      FormatString     A Null-terminated ASCII format string.
721   @param[in,out]  CurrentPosition  The starting position at the given string to check for
722                                    "[flags][width][.precision][length]s" string specifier.
723   @param[in]      StrLength        Maximum string length.
724 
725   @return BOOLEAN   TRUE means this is the formating string specifier. CurrentPosition is
726                     returned at the position of "s".
727                     FALSE means this is not the formating string specifier.. CurrentPosition is
728                     returned at the position of failed character.
729 
730 **/
731 BOOLEAN
CheckFormatingString(IN CONST CHAR8 * FormatString,IN OUT UINTN * CurrentPosition,IN UINTN StrLength)732 CheckFormatingString (
733   IN     CONST CHAR8 *FormatString,
734   IN OUT UINTN       *CurrentPosition,
735   IN     UINTN       StrLength
736   )
737 {
738   CHAR8 FormatStringParamater;
739 
740   while (*(FormatString + *CurrentPosition) != 's') {
741     //
742     // Loop until reach character 's' if the formating string is
743     // compliant with "[flags][width][.precision][length]" format for
744     // the string specifier.
745     //
746     FormatStringParamater = *(FormatString + *CurrentPosition);
747     if ((FormatStringParamater != '-') &&
748         (FormatStringParamater != '+') &&
749         (FormatStringParamater != '*') &&
750         (FormatStringParamater != '.') &&
751         !(((UINTN)FormatStringParamater >= (UINTN)'0') && ((UINTN)FormatStringParamater <= (UINTN)'9'))
752         ) {
753       return FALSE;
754     }
755     (*CurrentPosition)++;
756     if (*CurrentPosition >= StrLength) {
757       return FALSE;
758     }
759   };
760   return TRUE;
761 }
762 
763 /**
764   This function clones *FormatString however replaces "%s" with "%a" in the
765   returned string.
766 
767   @param[in] A Null-terminated ASCII format string.
768 
769   @return The new format string. Caller has to free the memory of this string
770           using FreePool().
771 
772 **/
773 CHAR8 *
ReplaceUnicodeToAsciiStrFormat(IN CONST CHAR8 * FormatString)774 ReplaceUnicodeToAsciiStrFormat (
775   IN CONST CHAR8 *FormatString
776 )
777 {
778   UINTN FormatStrSize;
779   UINTN FormatStrIndex;
780   UINTN FormatStrSpecifier;
781   BOOLEAN PercentageMark;
782   CHAR8 *TempFormatBuffer;
783   BOOLEAN IsFormatString;
784 
785   //
786   // Error checking.
787   //
788   if (FormatString == NULL) {
789     return NULL;
790   }
791   FormatStrSize = AsciiStrSize(FormatString);
792   if (FormatStrSize == 0) {
793     return NULL;
794   }
795   TempFormatBuffer = AllocatePool(FormatStrSize); // Allocate memory for the
796                                                   // new string.
797   if (TempFormatBuffer== NULL) {
798     return NULL;
799   }
800   //
801   // Clone *FormatString but replace "%s" wih "%a".
802   // "%%" is not considered as the format tag.
803   //
804   PercentageMark = FALSE;
805   FormatStrIndex = 0;
806   while (FormatStrIndex < FormatStrSize) {
807     if (PercentageMark == TRUE) {
808       //
809       // Previous character is "%".
810       //
811       PercentageMark = FALSE;
812       if (*(FormatString + FormatStrIndex) != '%') { // Check if this is double "%".
813         FormatStrSpecifier = FormatStrIndex;
814         //
815         // Check if this is the formating string specifier.
816         //
817         IsFormatString = CheckFormatingString (FormatString, &FormatStrSpecifier, FormatStrSize);
818         if ((FormatStrSpecifier - FormatStrIndex) != 0) {
819           CopyMem((VOID *)(TempFormatBuffer + FormatStrIndex),
820                   (VOID *)(FormatString + FormatStrIndex),
821                   FormatStrSpecifier - FormatStrIndex
822                   );
823         }
824         FormatStrIndex = FormatStrSpecifier;
825         if (IsFormatString == TRUE) {
826           //
827           // Replace 's' with 'a' which is printed in ASCII
828           // format on edk2 environment.
829           //
830           *(TempFormatBuffer + FormatStrSpecifier) = 'a';
831           FormatStrIndex ++;
832         }
833         continue;
834       }
835       goto ContinueCheck;
836     }
837     if (*(FormatString + FormatStrIndex) == '%') {
838       //
839       // This character is "%", set the flag.
840       //
841       PercentageMark = TRUE;
842     }
843 ContinueCheck:
844     //
845     // Clone character to the new string and advance FormatStrIndex
846     // to process next character.
847     //
848     *(TempFormatBuffer + FormatStrIndex) = *(FormatString + FormatStrIndex);
849     FormatStrIndex++;
850   };
851   return TempFormatBuffer;
852 }
853 
854 /**
855   This is the Redfish version of CRT vsnprintf function, this function replaces "%s" to
856   "%a" before invoking AsciiVSPrint(). That is because "%s" is unicode base on edk2
857   environment however "%s" is ascii code base on vsnprintf().
858   See definitions of AsciiVSPrint() for the details.
859 
860   @param  StartOfBuffer   A pointer to the output buffer for the produced Null-terminated
861                           ASCII string.
862   @param  BufferSize      The size, in bytes, of the output buffer specified by StartOfBuffer.
863   @param  FormatString    A Null-terminated ASCII format string.
864   @param  Marker          VA_LIST marker for the variable argument list.
865 
866   @return The number of ASCII characters in the produced output buffer not including the
867           Null-terminator.
868 
869 **/
870 UINTN
871 EFIAPI
RedfishAsciiVSPrint(OUT CHAR8 * StartOfBuffer,IN UINTN BufferSize,IN CONST CHAR8 * FormatString,IN VA_LIST Marker)872 RedfishAsciiVSPrint (
873   OUT CHAR8         *StartOfBuffer,
874   IN  UINTN         BufferSize,
875   IN  CONST CHAR8   *FormatString,
876   IN  VA_LIST       Marker
877   )
878 {
879   CHAR8 *TempFormatBuffer;
880   UINTN LenStrProduced;
881 
882   //
883   // Looking for "%s" in the format string and replace it
884   // with "%a" for printing ASCII code characters on edk2
885   // environment.
886   //
887   TempFormatBuffer = ReplaceUnicodeToAsciiStrFormat (FormatString);
888   if (TempFormatBuffer == NULL) {
889     return 0;
890   }
891   LenStrProduced = AsciiVSPrint (StartOfBuffer, BufferSize, (CONST CHAR8 *)TempFormatBuffer, Marker);
892   FreePool (TempFormatBuffer);
893   return LenStrProduced;
894 }
895 
896 /**
897   This is the Redfish version of CRT snprintf function, this function replaces "%s" to
898   "%a" before invoking AsciiSPrint(). That is because "%s" is unicode base on edk2
899   environment however "%s" is ascii code base on snprintf().
900   See definitions of AsciiSPrint() for the details.
901 
902   @param  StartOfBuffer   A pointer to the output buffer for the produced Null-terminated
903                           ASCII string.
904   @param  BufferSize      The size, in bytes, of the output buffer specified by StartOfBuffer.
905   @param  FormatString    A Null-terminated ASCII format string.
906   @param  ...             Variable argument list whose contents are accessed based on the
907                           format string specified by FormatString.
908 
909   @return The number of ASCII characters in the produced output buffer not including the
910           Null-terminator.
911 
912 **/
913 UINTN
914 EFIAPI
RedfishAsciiSPrint(OUT CHAR8 * StartOfBuffer,IN UINTN BufferSize,IN CONST CHAR8 * FormatString,...)915 RedfishAsciiSPrint (
916   OUT CHAR8        *StartOfBuffer,
917   IN  UINTN        BufferSize,
918   IN  CONST CHAR8  *FormatString,
919   ...
920   )
921 {
922   VA_LIST Marker;
923   UINTN LenStrProduced;
924 
925   VA_START(Marker, FormatString);
926   LenStrProduced = RedfishAsciiVSPrint (StartOfBuffer, BufferSize, FormatString, Marker);
927   return LenStrProduced;
928 }
929 
930