From 4f39858d2a61c089589e7e93857e436eb045141d Mon Sep 17 00:00:00 2001 From: Max Wash Date: Tue, 12 Jan 2021 20:41:01 +0000 Subject: [PATCH] Implemented getenv(), atexit(), number parsing, and more --- photon/libc/include/stdint.h | 3 -- photon/libc/include/stdlib.h | 6 ++- photon/libc/stdlib/atexit.c | 21 +++++++++++ photon/libc/stdlib/getenv.c | 6 +++ photon/libc/stdlib/strtof.c | 33 ++++++++++++++++ photon/libc/stdlib/strtol.c | 58 ++++++++++++----------------- photon/libc/stdlib/strtoul.c | 9 +++++ photon/libc/string/memcmp.c | 14 +++++++ photon/libc/string/memmove.c | 27 ++++++++++++++ photon/libc/string/strcmp.c | 18 ++++++--- photon/libc/sys/magenta/environ.c | 35 +++++++++++++++++ photon/libc/sys/magenta/init.c | 17 ++++++++- photon/libc/sys/magenta/sys/types.h | 4 +- 13 files changed, 202 insertions(+), 49 deletions(-) create mode 100644 photon/libc/stdlib/atexit.c create mode 100644 photon/libc/stdlib/getenv.c create mode 100644 photon/libc/stdlib/strtof.c create mode 100644 photon/libc/stdlib/strtoul.c create mode 100644 photon/libc/string/memcmp.c create mode 100644 photon/libc/string/memmove.c create mode 100644 photon/libc/sys/magenta/environ.c diff --git a/photon/libc/include/stdint.h b/photon/libc/include/stdint.h index cd1252d..0a4c64b 100644 --- a/photon/libc/include/stdint.h +++ b/photon/libc/include/stdint.h @@ -45,7 +45,4 @@ typedef __uint_fast64_t uint_fast64_t; typedef __intmax_t intmax_t; typedef __uintmax_t uintmax_t; -typedef __intptr_t intptr_t; -typedef __uintptr_t uintptr_t; - #endif /* STDINT_H_ */ diff --git a/photon/libc/include/stdlib.h b/photon/libc/include/stdlib.h index 72755fb..1c161bc 100644 --- a/photon/libc/include/stdlib.h +++ b/photon/libc/include/stdlib.h @@ -19,9 +19,13 @@ extern void srand(unsigned int seed); extern int atoi(const char *str); extern double atof(const char *str); -extern long int strtol(const char *str, char **endptr, int base); +extern long strtol(const char *str, char **endptr, int base); +extern unsigned long strtoul(const char *str, char **endptr, int base); +extern float strtof(const char *str, char **endptr); extern double strtod(const char *str, char **endptr); +extern char *getenv(const char *name); + #if defined(__cplusplus) } /* extern "C" */ #endif diff --git a/photon/libc/stdlib/atexit.c b/photon/libc/stdlib/atexit.c new file mode 100644 index 0000000..5b51fa7 --- /dev/null +++ b/photon/libc/stdlib/atexit.c @@ -0,0 +1,21 @@ +#define MAX_FN 32 + +static void(*atexit_fn[MAX_FN])(void); +static int atexit_fn_count = 0; + +int atexit(void(*fn)(void)) +{ + if (atexit_fn_count == MAX_FN) { + return -1; + } + + atexit_fn[atexit_fn_count++] = fn; + return 0; +} + +void __crt_run_atexit() +{ + for (int i = 0; i < atexit_fn_count; i++) { + atexit_fn[i](); + } +} diff --git a/photon/libc/stdlib/getenv.c b/photon/libc/stdlib/getenv.c new file mode 100644 index 0000000..4bf6c1f --- /dev/null +++ b/photon/libc/stdlib/getenv.c @@ -0,0 +1,6 @@ +extern char *__crt_sys_getenv(const char *name); + +char *getenv(const char *name) +{ + return __crt_sys_getenv(name); +} diff --git a/photon/libc/stdlib/strtof.c b/photon/libc/stdlib/strtof.c new file mode 100644 index 0000000..03bf82f --- /dev/null +++ b/photon/libc/stdlib/strtof.c @@ -0,0 +1,33 @@ +#include + +float strtof(const char *str, char **endptr) +{ + float res = 0.0F; + char *ptr = (char*)str; + int after_dot = 0; + float div = 1; + + while (*ptr != '\0') { + if (isdigit(*ptr)) { + if (!after_dot) { + res *= 10; + res += *ptr - '0'; + } else { + div *= 10; + res += (float)(*ptr - '0') / div; + } + } else if (*ptr == '.') { + after_dot = 1; + } else { + break; + } + + ptr++; + } + + if (endptr) { + *endptr = ptr; + } + + return res; +} diff --git a/photon/libc/stdlib/strtol.c b/photon/libc/stdlib/strtol.c index 40f5cc2..a687495 100644 --- a/photon/libc/stdlib/strtol.c +++ b/photon/libc/stdlib/strtol.c @@ -10,11 +10,6 @@ long strtol(const char *nptr, char **endptr, int base) unsigned long cutoff; int neg = 0, any, cutlim; - /* - * Skip white space and pick up leading +/- sign if any. - * If base is 0, allow 0x for hex and 0 for octal, else - * assume decimal; if base is already 16, allow 0x. - */ do { c = *s++; } while (isspace(c)); @@ -22,9 +17,9 @@ long strtol(const char *nptr, char **endptr, int base) if (c == '-') { neg = 1; c = *s++; - } else if (c == '+') + } else if (c == '+') { c = *s++; - if ((base == 0 || base == 16) && + } if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { c = s[1]; s += 2; @@ -35,51 +30,44 @@ long strtol(const char *nptr, char **endptr, int base) s += 2; base = 2; } - if (base == 0) - base = c == '0' ? 8 : 10; - /* - * Compute the cutoff value between legal numbers and illegal - * numbers. That is the largest legal value, divided by the - * base. An input number that is greater than this value, if - * followed by a legal input character, is too big. One that - * is equal to this value may be valid or not; the limit - * between valid and invalid numbers is then based on the last - * digit. For instance, if the range for longs is - * [-2147483648..2147483647] and the input base is 10, - * cutoff will be set to 214748364 and cutlim to either - * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated - * a value > 214748364, or equal but the next digit is > 7 (or 8), - * the number is too big, and we will return a range error. - * - * Set any if any `digits' consumed; make it negative to indicate - * overflow. - */ + if (base == 0) { + base = c == '0' ? 8 : 10; + } + cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; cutlim = cutoff % (unsigned long)base; cutoff /= (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { - if (isdigit(c)) + if (isdigit(c)) { c -= '0'; - else if (isalpha(c)) + } else if (isalpha(c)) { c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else + } else { break; - if (c >= base) + } + + if (c >= base) { break; - if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) + } if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) { any = -1; - else { + } else { any = 1; acc *= base; acc += c; } } + if (any < 0) { acc = neg ? LONG_MIN : LONG_MAX; - } else if (neg) + } else if (neg) { acc = -acc; - if (endptr != 0) + } + + if (endptr != 0) { *endptr = (char *)(any ? s - 1 : nptr); - return (acc); + } + + return acc; } diff --git a/photon/libc/stdlib/strtoul.c b/photon/libc/stdlib/strtoul.c new file mode 100644 index 0000000..8f43e65 --- /dev/null +++ b/photon/libc/stdlib/strtoul.c @@ -0,0 +1,9 @@ +#include +#include +#include +#include + +unsigned long strtoul(const char *nptr, char **endptr, int base) +{ + return (unsigned long)strtol(nptr, endptr, base); +} diff --git a/photon/libc/string/memcmp.c b/photon/libc/string/memcmp.c new file mode 100644 index 0000000..d74ea41 --- /dev/null +++ b/photon/libc/string/memcmp.c @@ -0,0 +1,14 @@ +#include + +int memcmp(const void *a, const void *b, size_t n) +{ + const unsigned char *s1 = a, *s2 = b; + + for (size_t i = 0; i < n; i++) { + if (s1[i] != s2[i]) { + return ((s1[i] < s2[i]) ? -1 : 1); + } + } + + return 0; +} diff --git a/photon/libc/string/memmove.c b/photon/libc/string/memmove.c new file mode 100644 index 0000000..d17be26 --- /dev/null +++ b/photon/libc/string/memmove.c @@ -0,0 +1,27 @@ +#include + +#define ALIGNED(p) (!((long)p & (sizeof(long) - 1))) +#define QUADBLOCKSIZE (sizeof(long) << 2) +#define BLOCKSIZE (sizeof(long)) + +static void *memcpy_r(void *dest, const void *src, size_t sz) +{ + unsigned char *d = dest; + const unsigned char *s = src; + + for (size_t i = 0; i < sz; i++) { + size_t b = sz - i - 1; + d[b] = s[b]; + } + + return dest; +} + +void *memmove(void *dest, const void *src, size_t n) +{ + if (dest > src) { + return memcpy(dest, src, n); + } else { + return memcpy_r(dest, src, n); + } +} diff --git a/photon/libc/string/strcmp.c b/photon/libc/string/strcmp.c index 42aea66..f640449 100644 --- a/photon/libc/string/strcmp.c +++ b/photon/libc/string/strcmp.c @@ -1,19 +1,25 @@ +#include + int strcmp(const char *s1, const char *s2) { int i; - for (i = 0; s1[i] == s2[i]; i++) - if (s1[i] == '\0') + for (i = 0; s1[i] == s2[i]; i++) { + if (s1[i] == '\0') { return 0; + } + } return s1[i] - s2[i]; } -int strncmp(const char *s1, const char *s2, unsigned int n) +int strncmp(const char *s1, const char *s2, size_t n) { - for (; n > 0; s1++, s2++, --n) - if (*s1 != *s2) + for (; n > 0; s1++, s2++, --n) { + if (*s1 != *s2) { return ((*(unsigned char *)s1 < *(unsigned char *)s2) ? -1 : 1); - else if (*s1 == '\0') + } else if (*s1 == '\0') { return 0; + } + } return 0; } diff --git a/photon/libc/sys/magenta/environ.c b/photon/libc/sys/magenta/environ.c new file mode 100644 index 0000000..3d5cbc5 --- /dev/null +++ b/photon/libc/sys/magenta/environ.c @@ -0,0 +1,35 @@ +#include +#include + +extern const char **__crt_environ(); + +char *__crt_sys_getenv(const char *name) +{ + const char **envp = __crt_environ(); + + for (int i = 0; envp[i] != NULL; i++) { + int equal = -1; + const char *env = envp[i]; + + for (int ii = 0; env[ii] != '\0'; ii++) { + if (env[ii] == '=') { + equal = ii; + break; + } + } + + if (equal == -1) { + continue; + } + + char env_name[equal]; + memcpy(env_name, env, equal - 1); + env_name[equal - 1] = '\0'; + + if (!strcmp(env_name, name)) { + return (char *)(env + equal + 1); + } + } + + return NULL; +} diff --git a/photon/libc/sys/magenta/init.c b/photon/libc/sys/magenta/init.c index a7e63f6..6038af5 100644 --- a/photon/libc/sys/magenta/init.c +++ b/photon/libc/sys/magenta/init.c @@ -22,7 +22,15 @@ struct handles { static struct handles rt_handles; +static const char **environ = NULL; + +const char **__crt_environ() +{ + return environ; +} + extern int main(int, const char **); +extern void __crt_run_atexit(); static void parse_args( mx_bootstrap_msg_t *args, mx_handle_t *handles, @@ -124,13 +132,18 @@ int __crt_init(mx_handle_t bootstrap) mx_bootstrap_msg_t *msg = (mx_bootstrap_msg_t *)msg_buf; - const char *argv[msg->args_num]; - const char *envp[msg->environ_num]; + const char *argv[msg->args_num + 1]; + const char *envp[msg->environ_num + 1]; + argv[msg->args_num] = NULL; + envp[msg->environ_num] = NULL; + environ = envp; parse_args(msg, handles, argv, envp, nr_handles, &rt_handles); rt_handles.bootstrap = bootstrap; int ret = main(msg->args_num, argv); + + __crt_run_atexit(); mx_task_kill(rt_handles.task_self, ret); /* unreachable */ diff --git a/photon/libc/sys/magenta/sys/types.h b/photon/libc/sys/magenta/sys/types.h index 19912c9..8845593 100644 --- a/photon/libc/sys/magenta/sys/types.h +++ b/photon/libc/sys/magenta/sys/types.h @@ -24,9 +24,9 @@ typedef unsigned int uid_t; typedef unsigned long useconds_t; typedef unsigned long long dev_t; -#ifndef __size_t_DEFINED +#ifndef __size_t_defined +#define __size_t_defined typedef __uintptr_t size_t; -#define __size_t_DEFINED #endif #ifndef __ssize_t_defined