mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-14 05:00:41 +02:00
141 lines
4.0 KiB
C
141 lines
4.0 KiB
C
// SPDX-License-Identifier: MIT
|
|
// SPDX-FileCopyrightText: Copyright © 2005-2011 Rich Felker, et al.
|
|
// NOTE: From an older musl release that avoids stdio usage
|
|
|
|
#include <inttypes.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
|
|
/* Lookup table for digit values. -1==255>=36 -> invalid */
|
|
static const unsigned char digits[] = {
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
|
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
|
|
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
};
|
|
|
|
uintmax_t strtoumax(const char* s1, char** p, int base) {
|
|
const unsigned char* s = s1;
|
|
size_t x1, z1;
|
|
uintmax_t x, z = 0;
|
|
int sign = 0;
|
|
int shift;
|
|
|
|
if (!p) {
|
|
p = (char**)&s1;
|
|
}
|
|
|
|
/* Initial whitespace */
|
|
for (; isspace(*s); s++)
|
|
;
|
|
|
|
/* Optional sign */
|
|
if (*s == '-') {
|
|
sign = *s++;
|
|
} else if (*s == '+') {
|
|
s++;
|
|
}
|
|
|
|
/* Default base 8, 10, or 16 depending on prefix */
|
|
if (base == 0) {
|
|
if (s[0] == '0') {
|
|
if ((s[1] | 32) == 'x') {
|
|
base = 16;
|
|
} else {
|
|
base = 8;
|
|
}
|
|
} else {
|
|
base = 10;
|
|
}
|
|
}
|
|
|
|
if ((unsigned)base - 2 > 36 - 2 || digits[*s] >= base) {
|
|
*p = (char*)s1;
|
|
errno = EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
/* Main loops. Only use big types if we have to. */
|
|
if (base == 10) {
|
|
for (x1 = 0; isdigit(*s) && x1 <= SIZE_MAX / 10 - 10; s++) {
|
|
x1 = 10 * x1 + *s - '0';
|
|
}
|
|
for (x = x1; isdigit(*s) && x <= UINTMAX_MAX / 10 - 10; s++) {
|
|
x = 10 * x + *s - '0';
|
|
}
|
|
if (isdigit(*s)) {
|
|
if (isdigit(s[1]) || 10 * x > UINTMAX_MAX - (*s - '0')) {
|
|
goto overflow;
|
|
}
|
|
x = 10 * x + *s - '0';
|
|
}
|
|
} else if (!(base & base / 2)) {
|
|
if (base == 16) {
|
|
if (s[0] == '0' && (s[1] | 32) == 'x' && digits[s[2]] < 16) {
|
|
s += 2;
|
|
}
|
|
shift = 4;
|
|
z1 = SIZE_MAX / 16;
|
|
z = UINTMAX_MAX / 16;
|
|
} else if (base == 8) {
|
|
shift = 3;
|
|
z1 = SIZE_MAX / 8;
|
|
z = UINTMAX_MAX / 8;
|
|
} else if (base == 2) {
|
|
shift = 1;
|
|
z1 = SIZE_MAX / 2;
|
|
z = UINTMAX_MAX / 2;
|
|
} else if (base == 4) {
|
|
shift = 2;
|
|
z1 = SIZE_MAX / 4;
|
|
z = UINTMAX_MAX / 4;
|
|
} else /* if (base == 32) */ {
|
|
shift = 5;
|
|
z1 = SIZE_MAX / 32;
|
|
z = UINTMAX_MAX / 32;
|
|
}
|
|
for (x1 = 0; digits[*s] < base && x1 <= z1; s++) {
|
|
x1 = (x1 << shift) + digits[*s];
|
|
}
|
|
for (x = x1; digits[*s] < base && x <= z; s++) {
|
|
x = (x << shift) + digits[*s];
|
|
}
|
|
if (digits[*s] < base) {
|
|
goto overflow;
|
|
}
|
|
} else {
|
|
z1 = SIZE_MAX / base - base;
|
|
for (x1 = 0; digits[*s] < base && x1 <= z1; s++) {
|
|
x1 = x1 * base + digits[*s];
|
|
}
|
|
if (digits[*s] < base) {
|
|
z = UINTMAX_MAX / base - base;
|
|
}
|
|
for (x = x1; digits[*s] < base && x <= z; s++) {
|
|
x = x * base + digits[*s];
|
|
}
|
|
if (digits[*s] < base) {
|
|
if (digits[s[1]] < base || x * base > UINTMAX_MAX - digits[*s]) {
|
|
goto overflow;
|
|
}
|
|
x = x * base + digits[*s];
|
|
}
|
|
}
|
|
|
|
*p = (char*)s;
|
|
return sign ? -x : x;
|
|
|
|
overflow:
|
|
for (; digits[*s] < base; s++)
|
|
;
|
|
*p = (char*)s;
|
|
errno = ERANGE;
|
|
return UINTMAX_MAX;
|
|
}
|