| /** @file | |
| ISO C implementations of strchr, strrchr and strtoul. | |
| Copyright (c) 2023, Intel Corporation. All rights reserved.<BR> | |
| Copyright (c) 2023 Pedro Falcato All rights reserved. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Base.h> | |
| #define ULONG_MAX 0xFFFFFFFF /* Maximum unsigned long value */ | |
| // Very quick notes: | |
| // We only go through the string once for both functions | |
| // They are minimal implementations (not speed optimized) of ISO C semantics | |
| // strchr and strrchr also include the null terminator as part of the string | |
| // so the code gets a bit clunky to handle that case specifically. | |
| char * | |
| strchr ( | |
| const char *Str, | |
| int Char | |
| ) | |
| { | |
| char *S; | |
| S = (char *)Str; | |
| for ( ; ; S++) { | |
| if (*S == Char) { | |
| return S; | |
| } | |
| if (*S == '\0') { | |
| return NULL; | |
| } | |
| } | |
| } | |
| char * | |
| strrchr ( | |
| const char *Str, | |
| int Char | |
| ) | |
| { | |
| char *S, *last; | |
| S = (char *)Str; | |
| last = NULL; | |
| for ( ; ; S++) { | |
| if (*S == Char) { | |
| last = S; | |
| } | |
| if (*S == '\0') { | |
| return last; | |
| } | |
| } | |
| } | |
| STATIC | |
| int | |
| __isspace ( | |
| int ch | |
| ) | |
| { | |
| // basic ASCII ctype.h:isspace(). Not efficient | |
| return ch == '\r' || ch == '\n' || ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f'; | |
| } | |
| unsigned long | |
| strtoul ( | |
| const char *Nptr, | |
| char **EndPtr, | |
| int Base | |
| ) | |
| { | |
| BOOLEAN Negate; | |
| BOOLEAN Overflow; | |
| unsigned long Val; | |
| Negate = FALSE; | |
| Overflow = FALSE; | |
| Val = 0; | |
| // Reject bad numeric bases | |
| if ((Base < 0) || (Base == 1) || (Base > 36)) { | |
| return 0; | |
| } | |
| // Skip whitespace | |
| while (__isspace (*Nptr)) { | |
| Nptr++; | |
| } | |
| // Check for + or - prefixes | |
| if (*Nptr == '-') { | |
| Negate = TRUE; | |
| Nptr++; | |
| } else if (*Nptr == '+') { | |
| Nptr++; | |
| } | |
| // Consume the start, autodetecting base if needed | |
| if ((Nptr[0] == '0') && ((Nptr[1] == 'x') || (Nptr[1] == 'X')) && ((Base == 0) || (Base == 16))) { | |
| // Hex | |
| Nptr += 2; | |
| Base = 16; | |
| } else if ((Nptr[0] == '0') && ((Nptr[1] == 'b') || (Nptr[1] == 'B')) && ((Base == 0) || (Base == 2))) { | |
| // Binary (standard pending C23) | |
| Nptr += 2; | |
| Base = 2; | |
| } else if ((Nptr[0] == '0') && ((Base == 0) || (Base == 8))) { | |
| // Octal | |
| Nptr++; | |
| Base = 8; | |
| } else { | |
| if (Base == 0) { | |
| // Assume decimal | |
| Base = 10; | |
| } | |
| } | |
| while (TRUE) { | |
| int Digit; | |
| char C; | |
| unsigned long NewVal; | |
| C = *Nptr; | |
| Digit = -1; | |
| if ((C >= '0') && (C <= '9')) { | |
| Digit = C - '0'; | |
| } else if ((C >= 'a') && (C <= 'z')) { | |
| Digit = C - 'a' + 10; | |
| } else if ((C >= 'A') && (C <= 'Z')) { | |
| Digit = C - 'A' + 10; | |
| } | |
| if ((Digit == -1) || (Digit >= Base)) { | |
| // Note that this case also handles the \0 | |
| if (EndPtr) { | |
| *EndPtr = (char *)Nptr; | |
| } | |
| break; | |
| } | |
| NewVal = Val * Base + Digit; | |
| if (NewVal < Val) { | |
| // Overflow | |
| Overflow = TRUE; | |
| } | |
| Val = NewVal; | |
| Nptr++; | |
| } | |
| if (Negate) { | |
| Val = -Val; | |
| } | |
| if (Overflow) { | |
| Val = ULONG_MAX; | |
| } | |
| // TODO: We're lacking errno here. | |
| return Val; | |
| } |