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