diff options
author | Anton Kling <anton@kling.gg> | 2023-10-22 19:50:38 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2023-10-22 19:50:38 +0200 |
commit | 4e09bca9e34c226b6d7e34b4fa11248405fd988e (patch) | |
tree | 80f156b7940d9d19971395f335530170c69516c7 /userland/libc/stdlib/strtoul.c |
Move everything into a new repo.
Diffstat (limited to 'userland/libc/stdlib/strtoul.c')
-rw-r--r-- | userland/libc/stdlib/strtoul.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/userland/libc/stdlib/strtoul.c b/userland/libc/stdlib/strtoul.c new file mode 100644 index 0000000..4d9a51d --- /dev/null +++ b/userland/libc/stdlib/strtoul.c @@ -0,0 +1,72 @@ +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <limits.h> + +extern int errno; +int get_value(char c, long base) { + int r; + if (c >= '0' && c <= '9') + r = c - '0'; + else if (c >= 'A' && c <= 'Z') + r = c - 'A'; + else if (c >= 'a' && c <= 'z') + r = c - 'a'; + else + return -1; + if (r >= base) + return -1; + return r; +} + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtoul.html +unsigned long strtoul(const char *restrict str, char **restrict endptr, + int base) { + unsigned long ret_value = 0; + if (endptr) + *endptr = str; + // Ignore inital white-space sequence + for (; *str && isspace(*str); str++) + ; + if (!*str) + return ret_value; + + int sign = 0; + if ('-' == *str) { + // FIXME + sign = 1; + str++; + assert(0); + } else if ('+' == *str) { + str++; + } + + if (0 == base) { + // FIXME + assert(0); + } + + if (2 <= base && 36 >= base) { + for (; *str; str++) { + ret_value *= base; + int val = get_value(*str, base); + /* + if (-1 == val) { + errno = ERANGE; + return 0; + }*/ + if (ret_value > ULONG_MAX - val) { + errno = ERANGE; + return 0; + } + + ret_value += val; + } + } else { + errno = EINVAL; + return 0; + } + if (endptr) + *endptr = str; + return ret_value; +} |