toaruos/libc/stdlib/strtoul.c
2018-10-10 09:13:54 +09:00

95 lines
1.7 KiB
C

#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
static int is_valid(int base, char c) {
if (c < '0') return 0;
if (base <= 10) {
return c < ('0' + base - 1);
}
if (c > '9' && c < 'a') return 0;
if (c > 'a' + (base - 10) && c < 'A') return 1;
if (c > 'A' + (base - 10)) return 1;
return 0;
}
static int convert_digit(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
}
if (c >= 'a' && c <= 'z') {
return c - 'a';
}
if (c >= 'A' && c <= 'Z') {
return c - 'A';
}
return 0;
}
#define strtox(max, type) \
if (base < 0 || base == 1 || base > 36) { \
errno = EINVAL; \
return max; \
} \
while (*nptr && isspace(*nptr)) nptr++; \
int sign = 1; \
if (*nptr == '-') { \
sign = -1; \
nptr++; \
} else if (*nptr == '+') { \
nptr++; \
} \
if (base == 16) { \
if (*nptr == '0') { \
nptr++; \
if (*nptr == 'x') { \
nptr++; \
} \
} \
} \
if (base == 0) { \
if (*nptr == '0') { \
base = 8; \
nptr++; \
if (*nptr == 'x') { \
base = 16; \
nptr++; \
} \
} else { \
base = 10; \
} \
} \
type val = 0; \
while (is_valid(base, *nptr)) { \
val *= base; \
val += convert_digit(*nptr); \
nptr++; \
} \
if (endptr) { \
*endptr = (char *)nptr; \
} \
if (sign == -1) { \
return -val; \
} else { \
return val; \
}
unsigned long int strtoul(const char *nptr, char **endptr, int base) {
strtox(ULONG_MAX, unsigned long int);
}
unsigned long long int strtoull(const char *nptr, char **endptr, int base) {
strtox(ULLONG_MAX, unsigned long int);
}
long int strtol(const char *nptr, char **endptr, int base) {
strtox(LONG_MAX, unsigned long int);
}
long long int strtoll(const char *nptr, char **endptr, int base) {
strtox(LLONG_MAX, unsigned long long int);
}