summaryrefslogtreecommitdiff
path: root/userland/libc/stdlib/strtoul.c
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2023-10-22 19:50:38 +0200
committerAnton Kling <anton@kling.gg>2023-10-22 19:50:38 +0200
commit4e09bca9e34c226b6d7e34b4fa11248405fd988e (patch)
tree80f156b7940d9d19971395f335530170c69516c7 /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.c72
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;
+}