X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FLibraries%2Flibc.so_src%2Fstdlib.c;h=e15f49b420a7f32f68c9bdd61b05ca5090d86038;hb=05c45f4a7cf476f6e5d76df2307710d15cd18eb9;hp=ce5a8d0c4492ea73f2a63269d317aa0f1bf5fa67;hpb=466eda7c917791866a29c253c6c22197faf41bf7;p=tpg%2Facess2.git diff --git a/Usermode/Libraries/libc.so_src/stdlib.c b/Usermode/Libraries/libc.so_src/stdlib.c index ce5a8d0c..e15f49b4 100644 --- a/Usermode/Libraries/libc.so_src/stdlib.c +++ b/Usermode/Libraries/libc.so_src/stdlib.c @@ -2,28 +2,42 @@ * AcessOS Basic C Library * stdlib.c */ -/** - * \todo Move half of these to stdio - */ #include #include #include +#include +#include +#include #include "lib.h" #define _stdout 1 #define _stdin 0 +extern void *_crt0_exit_handler; + // === PROTOTYPES === EXPORT int atoi(const char *str); EXPORT void exit(int status); +// === GLOBALS === +void (*g_stdlib_exithandler)(void); + // === CODE === +void atexit(void (*__func)(void)) +{ + g_stdlib_exithandler = __func; + // TODO: Replace with meta-function to allow multiple atexit() handlers + _crt0_exit_handler = __func; +} + /** * \fn EXPORT void exit(int status) * \brief Exit */ EXPORT void exit(int status) { + if( g_stdlib_exithandler ) + g_stdlib_exithandler(); _exit(status); } @@ -34,7 +48,7 @@ EXPORT void exit(int status) */ EXPORT void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)) { - int i, j, min; + size_t i, j, min; // With 0 items, there's nothing to do and with 1 its already sorted if(nmemb == 0 || nmemb == 1) return; @@ -57,66 +71,125 @@ EXPORT void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void } } -/** - * \fn EXPORT int atoi(const char *str) - * \brief Convert a string to an integer - */ -EXPORT int atoi(const char *str) +EXPORT unsigned long long strtoull(const char *str, char **end, int base) { - int neg = 0; - int ret = 0; - - // NULL Check - if(!str) return 0; + long long ret = 0; - while(*str == ' ' || *str == '\t') str++; - - // Check for negative - if(*str == '-') { - neg = 1; + if( !str || base < 0 || base > 36 || base == 1 ) { + if(end) + *end = (char*)str; + errno = EINVAL; + return 0; + } + + while( isspace(*str) ) str++; + + if( base == 0 || base == 16 ) { + if( *str == '0' && str[1] == 'x' ) { + str += 2; + base = 16; + } } - if(*str == '0') { + if( base == 0 && *str == '0' ) { str ++; - if(*str == 'x') { - str++; - // Hex - while( ('0' <= *str && *str <= '9') - || ('A' <= *str && *str <= 'F' ) - || ('a' <= *str && *str <= 'f' ) - ) - { - ret *= 16; - if(*str <= '9') { - ret += *str - '0'; - } else if (*str <= 'F') { - ret += *str - 'A' + 10; - } else { - ret += *str - 'a' + 10; - } - str++; - } - } else { - // Octal - while( '0' <= *str && *str <= '7' ) - { - ret *= 8; - ret += *str - '0'; - str++; - } + base = 8; + } + + if( base == 0 ) + base = 10; + + while( *str ) + { + int next = -1; + if( base <= 10 ) { + if( '0' <= *str && *str <= '0'+base-1 ) + next = *str - '0'; } - } else { - // Decimal - while( '0' <= *str && *str <= '9' ) - { - ret *= 10; - ret += *str - '0'; - str++; + else { + if( '0' <= *str && *str <= '9' ) + next = *str - '0'; + if( 'A' <= *str && *str <= 'A'+base-10-1 ) + next = *str - 'A'; + if( 'a' <= *str && *str <= 'a'+base-10-1 ) + next = *str - 'a'; } + if( next < 0 ) + break; + ret *= base; + ret += next; + str ++; } - - // Negate if needed - if(neg) ret = -ret; + + if(end) + *end = (char*)str; return ret; } + +EXPORT unsigned long strtoul(const char *ptr, char **end, int base) +{ + unsigned long long tmp = strtoull(ptr, end, base); + + if( tmp > ULONG_MAX ) { + errno = ERANGE; + return ULONG_MAX; + } + + return tmp; +} + +EXPORT long long strtoll(const char *str, char **end, int base) +{ + int neg = 0; + unsigned long long ret; + + if( !str ) { + errno = EINVAL; + return 0; + } + + while( isspace(*str) ) + str++; + + // Check for negative (or positive) sign + if(*str == '-' || *str == '+') { + neg = (*str == '-'); + str++; + } + + ret = strtoull(str, end, base); + + if( neg ) + return -ret; + else + return ret; +} + +EXPORT long strtol(const char *str, char **end, int base) +{ + long long tmp = strtoll(str, end, base); + if( tmp > LONG_MAX || tmp < LONG_MIN ) { + errno = ERANGE; + return (tmp > LONG_MAX) ? LONG_MAX : LONG_MIN; + } + return tmp; +} + +/** + * \fn EXPORT int atoi(const char *str) + * \brief Convert a string to an integer + */ +EXPORT int atoi(const char *str) +{ + long long tmp = strtoll(str, NULL, 0); + if( tmp > INT_MAX || tmp < INT_MIN ) { + errno = ERANGE; + return (tmp > INT_MAX) ? INT_MAX : INT_MIN; + } + return tmp; +} + +int abs(int j) { return j < 0 ? -j : j; } +long int labs(long int j) { return j < 0 ? -j : j; } +