diff --git a/apps/app.c b/apps/app.c index 4f1419f1..30759530 100644 --- a/apps/app.c +++ b/apps/app.c @@ -1,9 +1,16 @@ #include #include +void bye() +{ + console_print("byeee!\n"); +} + int main() { - for (int i = 0; i < strtol("010", NULL, 0); i++) { console_print("."); } + atexit(bye); + + for (int i = 0; i < atoi("8"); i++) { console_print("."); } console_print("\n"); } diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index cb407399..331380c0 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -7,6 +7,7 @@ set(SOURCES src/unistd.cpp src/errno.cpp src/string.cpp + src/atexit.cpp ) if(${ARCH} STREQUAL "x86_64") diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h index 7e6a0f56..736c2f93 100644 --- a/libc/include/stdlib.h +++ b/libc/include/stdlib.h @@ -1,21 +1,26 @@ +/* stdlib.h: General utilities header. */ + #ifndef _STDLIB_H #define _STDLIB_H #include #include +/* The result of a division operation on two integers. */ typedef struct { int quot; int rem; } div_t; +/* The result of a division operation on two long integers. */ typedef struct { long quot; long rem; } ldiv_t; +/* The result of a division operation on two long long integers. */ typedef struct { long long quot; @@ -27,12 +32,22 @@ extern "C" { #endif - int abs(int); - long labs(long); - long long llabs(long long); + /* Returns the absolute value of v. */ + int abs(int v); - div_t div(int, int); + /* Returns the absolute value of v. */ + long labs(long v); + + /* Returns the absolute value of v. */ + long long llabs(long long v); + + /* Returns the result of dividing num by den, including the remainder. */ + div_t div(int num, int den); + + /* Returns the result of dividing num by den, including the remainder. */ ldiv_t ldiv(long, long); + + /* Returns the result of dividing num by den, including the remainder. */ lldiv_t lldiv(long long, long long); void* malloc(size_t); @@ -40,25 +55,42 @@ extern "C" void* realloc(void*, size_t); void free(void*); + /* Aborts the program without performing any normal cleanup. */ __noreturn void abort(); - int atexit(void (*)(void)); - int atoi(const char*); - long atol(const char*); - long long atoll(const char*); + /* Registers a handler to be run at normal program termination. */ + int atexit(void (*func)(void)); + + /* Parses a decimal integer from the provided string. */ + int atoi(const char* s); + + /* Parses a decimal integer from the provided string. */ + long atol(const char* s); + + /* Parses a decimal integer from the provided string. */ + long long atoll(const char* s); double atof(const char*); double strtod(const char*, char**); - long strtol(const char*, char**, int); - unsigned long strtoul(const char*, char**, int); + /* Parses an integer of the specified base from the string str, storing the first non-number character in endptr if + * nonnull. */ + long strtol(const char* str, char** endptr, int base); + + /* Parses an unsigned integer of the specified base from the string str, storing the first non-number character in + * endptr if nonnull. */ + unsigned long strtoul(const char* str, char** endptr, int base); int rand(); void srand(int); + /* Exits the program normally, performing any registered cleanup actions. */ __noreturn void exit(int); + /* Exits the program abnormally, without performing any registered cleanup actions. */ + __noreturn void _Exit(int); + int system(const char*); char* getenv(const char*); diff --git a/libc/src/atexit.cpp b/libc/src/atexit.cpp new file mode 100644 index 00000000..94f86e08 --- /dev/null +++ b/libc/src/atexit.cpp @@ -0,0 +1,28 @@ +#include + +typedef void (*atexit_func_t)(void); + +const int ATEXIT_MAX_FUNCS = 48; + +int atexit_registered_funcs = 0; + +atexit_func_t atexit_funcs[ATEXIT_MAX_FUNCS]; + +extern "C" +{ + int atexit(atexit_func_t func) + { + if (atexit_registered_funcs == ATEXIT_MAX_FUNCS) return -1; + + atexit_funcs[atexit_registered_funcs++] = func; + + return 0; + } + + __noreturn void exit(int status) + { + while (atexit_registered_funcs--) { atexit_funcs[atexit_registered_funcs](); } + + _Exit(status); + } +} diff --git a/libc/src/stdlib.cpp b/libc/src/stdlib.cpp index 87fb244d..12f338a4 100644 --- a/libc/src/stdlib.cpp +++ b/libc/src/stdlib.cpp @@ -1,19 +1,91 @@ +#include #include #include #include #include +template static inline ResultT __generic_div(ArgT a, ArgT b) +{ + ResultT result; + result.quot = a / b; + result.rem = a % b; + + if (a >= 0 && result.rem < 0) + { + result.quot++; + result.rem -= b; + } + + return result; +} + extern "C" { - // FIXME: Check for overflow in both strtol() and strtoul(). + int abs(int v) + { + return __builtin_abs(v); + } + + long labs(long v) + { + return __builtin_labs(v); + } + + long long llabs(long long v) + { + return __builtin_llabs(v); + } + + div_t div(int num, int den) + { + return __generic_div(num, den); + } + + ldiv_t ldiv(long num, long den) + { + return __generic_div(num, den); + } + + lldiv_t lldiv(long long num, long long den) + { + return __generic_div(num, den); + } + + int atoi(const char* s) + { + return (int)strtol(s, NULL, 10); + } + + long atol(const char* s) + { + return strtol(s, NULL, 10); + } + + // Assuming LP64, long long == long. + long long atoll(const char* s) + { + return (long long)strtol(s, NULL, 10); + } + + // These checks are only necessary on LLP64 platforms, where long won't match size_t/ssize_t. Probably redundant + // then (since Luna follows the regular LP64 model), but oh well... long strtol(const char* str, char** endptr, int base) { - return (long)parse_signed_integer(str, const_cast(endptr), base); + isize rc = parse_signed_integer(str, const_cast(endptr), base); + + if (rc > (isize)LONG_MAX) return LONG_MAX; + if (rc < (isize)LONG_MIN) return LONG_MIN; + + return rc; } unsigned long strtoul(const char* str, char** endptr, int base) { - return (unsigned long)parse_unsigned_integer(str, const_cast(endptr), base); + usize rc = parse_unsigned_integer(str, const_cast(endptr), base); + + if (rc > (usize)ULONG_MAX) return ULONG_MAX; + + return rc; } __noreturn void abort() @@ -22,7 +94,7 @@ extern "C" __builtin_unreachable(); } - __noreturn void exit(int) + __noreturn void _Exit(int) { syscall(SYS_exit); __builtin_unreachable();