diff options
-rw-r--r-- | src/shared/include/camellia/errno.h | 1 | ||||
-rw-r--r-- | src/user/app/shell/parser.c | 4 | ||||
-rw-r--r-- | src/user/app/tests/tests.c | 21 | ||||
-rw-r--r-- | src/user/lib/include/string.h | 5 | ||||
-rw-r--r-- | src/user/lib/string.c | 51 |
5 files changed, 78 insertions, 4 deletions
diff --git a/src/shared/include/camellia/errno.h b/src/shared/include/camellia/errno.h index 3ff735a..6ed9aa3 100644 --- a/src/shared/include/camellia/errno.h +++ b/src/shared/include/camellia/errno.h @@ -4,3 +4,4 @@ #define EBADF 3 /* Invalid file descriptor. */ #define EINVAL 4 #define ENOSYS 5 /* Unsupported. */ +#define ERANGE 6 diff --git a/src/user/app/shell/parser.c b/src/user/app/shell/parser.c index 31c45d1..072c720 100644 --- a/src/user/app/shell/parser.c +++ b/src/user/app/shell/parser.c @@ -2,10 +2,6 @@ #include <stdbool.h> #include <string.h> -static bool isspace(char c) { - return c == ' ' || c == '\t' || c == '\n'; -} - static char skipspace(char **sp) { char *s = *sp; while (*s && isspace(*s)) s++; diff --git a/src/user/app/tests/tests.c b/src/user/app/tests/tests.c index f8abc49..d655ab9 100644 --- a/src/user/app/tests/tests.c +++ b/src/user/app/tests/tests.c @@ -237,6 +237,26 @@ static void test_execbuf(void) { test_fail(); } +static void test_strtol(void) { + char *end; + assert(1234 == strtol("1234", NULL, 10)); + assert(1234 == strtol("+1234", NULL, 10)); + assert(-1234 == strtol("-1234", NULL, 10)); + + assert(1234 == strtol("1234", &end, 10)); + assert(!strcmp("", end)); + assert(1234 == strtol(" 1234hello", &end, 10)); + assert(!strcmp("hello", end)); + + assert(1234 == strtol(" 1234hello", &end, 0)); + assert(!strcmp("hello", end)); + assert(0xCAF3 == strtol(" 0xCaF3hello", &end, 0)); + assert(!strcmp("hello", end)); + assert(01234 == strtol(" 01234hello", &end, 0)); + assert(!strcmp("hello", end)); + +} + static void test_misc(void) { assert(_syscall(~0, 0, 0, 0, 0, 0) < 0); /* try making an invalid syscall */ } @@ -255,6 +275,7 @@ int main(void) { run_forked(test_efault); run_forked(test_execbuf); run_forked(test_printf); + run_forked(test_strtol); run_forked(test_misc); return 1; } diff --git a/src/user/lib/include/string.h b/src/user/lib/include/string.h index e5c0255..8930bee 100644 --- a/src/user/lib/include/string.h +++ b/src/user/lib/include/string.h @@ -1 +1,6 @@ +#pragma once #include <shared/mem.h> + +int isspace(char c); + +long strtol(const char *restrict s, char **restrict end, int base); diff --git a/src/user/lib/string.c b/src/user/lib/string.c new file mode 100644 index 0000000..77b996c --- /dev/null +++ b/src/user/lib/string.c @@ -0,0 +1,51 @@ +#include <errno.h> +#include <string.h> + +int isspace(char c) { + return c == ' ' || c == '\t' || c == '\n'; +} + +long strtol(const char *restrict s, char **restrict end, int base) { + long res = 0; + int sign = 1; + + while (isspace(*s)) s++; + + if (*s == '+') { + s++; + } else if (*s == '-') { + s++; + sign = -1; + } + + if (base == 0) { + if (*s == '0') { + s++; + if (*s == 'x' || *s == 'X') { + s++; + base = 16; + } else { + base = 8; + } + } else { + base = 10; + } + } + + for (;;) { + unsigned char digit = *s; + if ('0' <= digit && digit <= '9') digit -= '0'; + else if ('a' <= digit && digit <= 'z') digit -= 'a' - 10; + else if ('A' <= digit && digit <= 'Z') digit -= 'A' - 10; + else break; + + if (digit >= base) break; + // TODO overflow check + res *= base; + res += digit; + + s++; + } + if (end) *end = (void*)s; + return res * sign; +} |