X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FLibraries%2Flibc.so_src%2Fstdlib.c;h=e15f49b420a7f32f68c9bdd61b05ca5090d86038;hb=05c45f4a7cf476f6e5d76df2307710d15cd18eb9;hp=44dc55fa7308f881b1eb62d99a59d668cb13c0c1;hpb=17e16b3110b4c5124b0707435e0427993d696545;p=tpg%2Facess2.git diff --git a/Usermode/Libraries/libc.so_src/stdlib.c b/Usermode/Libraries/libc.so_src/stdlib.c index 44dc55fa..e15f49b4 100644 --- a/Usermode/Libraries/libc.so_src/stdlib.c +++ b/Usermode/Libraries/libc.so_src/stdlib.c @@ -1,409 +1,195 @@ /* -AcessOS Basic C Library - -stdlib.c -*/ + * AcessOS Basic C Library + * stdlib.c + */ #include #include +#include +#include +#include +#include #include "lib.h" -int _stdout = 1; -int _stdin = 2; +#define _stdout 1 +#define _stdin 0 + +extern void *_crt0_exit_handler; -EXPORT int puts(const char *str); -EXPORT void itoa(char *buf, unsigned long num, int base, int minLength, char pad); +// === PROTOTYPES === EXPORT int atoi(const char *str); -EXPORT int puts(const char *str); -EXPORT int ssprintfv(char *format, va_list args); -EXPORT void sprintfv(char *buf, char *format, va_list args); -EXPORT int printf(const char *format, ...); -EXPORT int strlen(const char *str); -EXPORT int strcmp(char *str1, char *str2); -EXPORT int strncmp(char *str1, char *str2, size_t len); -EXPORT char *strcpy(char *dst, const char *src); +EXPORT void exit(int status); + +// === GLOBALS === +void (*g_stdlib_exithandler)(void); // === CODE === -EXPORT int putchar(int ch) +void atexit(void (*__func)(void)) { - return write(_stdout, 1, (char*)&ch); + g_stdlib_exithandler = __func; + // TODO: Replace with meta-function to allow multiple atexit() handlers + _crt0_exit_handler = __func; } -EXPORT int puts(const char *str) +/** + * \fn EXPORT void exit(int status) + * \brief Exit + */ +EXPORT void exit(int status) { - int len; - - if(!str) return 0; - len = strlen(str); - - len = write(_stdout, len, (char*)str); - write(_stdout, 1, "\n"); - return len; + if( g_stdlib_exithandler ) + g_stdlib_exithandler(); + _exit(status); } -//sprintfv /** - \fn EXPORT void sprintfv(char *buf, char *format, va_list args) - \brief Prints a formatted string to a buffer - \param buf Pointer - Destination Buffer - \param format String - Format String - \param args VarArgs List - Arguments -*/ -EXPORT void sprintfv(char *buf, char *format, va_list args) + * \fn EXPORT void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)) + * \brief Sort an array + * \note Uses a selection sort + */ +EXPORT void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)) { - char tmp[33]; - int c, arg, minSize; - int pos = 0; - char *p; - char pad; - - tmp[32] = '\0'; + 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; - while((c = *format++) != 0) + // SORT! + for( i = 0; i < (nmemb-1); i++ ) { - //SysDebug("c = '%c'\n", c); - if (c != '%') { - buf[pos++] = c; - continue; - } - - c = *format++; - if(c == '%') { - buf[pos++] = '%'; - continue; - } - - // Padding - if(c == '0') { - pad = '0'; - c = *format++; - } else - pad = ' '; - minSize = 0; - if('1' <= c && c <= '9') + min = i; + for( j = i+1; j < nmemb; j++ ) { - while('0' <= c && c <= '9') - { - minSize *= 10; - minSize += c - '0'; - c = *format++; + if(compar(base+size*j, base + size*min) < 0) { + min = j; } } - - p = tmp; - - // Get Argument - arg = va_arg(args, int); - // Get Type - switch (c) { - case 'd': - case 'i': - if(arg < 0) { - buf[pos++] = '-'; - arg = -arg; - } - itoa(tmp, arg, 10, minSize, pad); - goto sprintf_puts; - // break; - case 'u': - itoa(tmp, arg, 10, minSize, pad); - goto sprintf_puts; - // break; - case 'x': - itoa(tmp, arg, 16, minSize, pad); - goto sprintf_puts; - // break; - case 'o': - itoa(tmp, arg, 8, minSize, pad); - goto sprintf_puts; - // break; - case 'b': - itoa(tmp, arg, 2, minSize, pad); - goto sprintf_puts; - // break; - - case 's': - p = (void*)arg; - sprintf_puts: - if(!p) p = "(null)"; - while(*p) buf[pos++] = *p++; - break; - - default: - buf[pos++] = arg; - break; + if (i != min) { + char swap[size]; + memcpy(swap, base+size*i, size); + memcpy(base+size*i, base+size*min, size); + memcpy(base+size*i, swap, size); } - } - buf[pos++] = '\0'; + } } -/* -ssprintfv -- Size, Stream, Print Formated, Variable Argument List -*/ -/** - \fn EXPORT int ssprintfv(char *format, va_list args) - \brief Gets the total character count from a formatted string - \param format String - Format String - \param args VarArgs - Argument List -*/ -EXPORT int ssprintfv(char *format, va_list args) + +EXPORT unsigned long long strtoull(const char *str, char **end, int base) { - char tmp[33]; - int c, arg, minSize; - int len = 0; - char *p; - char pad; + long long ret = 0; + + if( !str || base < 0 || base > 36 || base == 1 ) { + if(end) + *end = (char*)str; + errno = EINVAL; + return 0; + } - tmp[32] = '\0'; + while( isspace(*str) ) + str++; + + if( base == 0 || base == 16 ) { + if( *str == '0' && str[1] == 'x' ) { + str += 2; + base = 16; + } + } - while((c = *format++) != 0) + if( base == 0 && *str == '0' ) { + str ++; + base = 8; + } + + if( base == 0 ) + base = 10; + + while( *str ) { - if (c != '%') { - len++; - continue; + int next = -1; + if( base <= 10 ) { + if( '0' <= *str && *str <= '0'+base-1 ) + next = *str - '0'; } - - c = *format++; - - // Literal '%' - if(c == '%') { - len++; - continue; + 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'; } - - // Padding - if(c == '0') { - pad = '0'; - c = *format++; - } else - pad = ' '; - minSize = 0; - if('1' <= c && c <= '9') - { - while('0' <= c && c <= '9') - { - minSize *= 10; - minSize += c - '0'; - c = *format++; - } - } - - p = tmp; - arg = va_arg(args, int); - switch (c) { - case 'd': - case 'i': - if(arg < 0) { - len ++; - arg = -arg; - } - itoa(tmp, arg, 10, minSize, pad); - goto sprintf_puts; - case 'u': - itoa(tmp, arg, 10, minSize, pad); - goto sprintf_puts; - case 'x': - itoa(tmp, arg, 16, minSize, pad); - goto sprintf_puts; - case 'o': - itoa(tmp, arg, 8, minSize, pad); - p = tmp; - goto sprintf_puts; - case 'b': - itoa(tmp, arg, 2, minSize, pad); - goto sprintf_puts; - - case 's': - p = (char*)arg; - sprintf_puts: - if(!p) p = "(null)"; - while(*p) len++, p++; + if( next < 0 ) break; + ret *= base; + ret += next; + str ++; + } - default: - len ++; - break; - } - } - return len; + if(end) + *end = (char*)str; + return ret; } -const char cUCDIGITS[] = "0123456789ABCDEF"; -/** - * \fn static void itoa(char *buf, unsigned long num, int base, int minLength, char pad) - * \brief Convert an integer into a character string - */ -EXPORT void itoa(char *buf, unsigned long num, int base, int minLength, char pad) +EXPORT unsigned long strtoul(const char *ptr, char **end, int base) { - char tmpBuf[32]; - int pos=0, i; - - if(!buf) return; - if(base > 16) { - buf[0] = 0; - return; - } + unsigned long long tmp = strtoull(ptr, end, base); - while(num > base-1) { - tmpBuf[pos] = cUCDIGITS[ num % base ]; - num = (long) num / base; //Shift {number} right 1 digit - pos++; + if( tmp > ULONG_MAX ) { + errno = ERANGE; + return ULONG_MAX; } - - tmpBuf[pos++] = cUCDIGITS[ num % base ]; //Last digit of {number} - i = 0; - minLength -= pos; - while(minLength-- > 0) buf[i++] = pad; - while(pos-- > 0) buf[i++] = tmpBuf[pos]; //Reverse the order of characters - buf[i] = 0; + + return tmp; } -/** - */ -EXPORT int atoi(const char *str) +EXPORT long long strtoll(const char *str, char **end, int base) { int neg = 0; - int ret = 0; - - // NULL Check - if(!str) return 0; - - while(*str == ' ' || *str == '\t') str++; + unsigned long long ret; + + if( !str ) { + errno = EINVAL; + return 0; + } - // Check for negative - if(*str == '-') { - neg = 1; + while( isspace(*str) ) str++; - } - if(*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++; - } - } - } else { - // Decimal - while( '0' <= *str && *str <= '9' ) - { - ret *= 10; - ret += *str - '0'; - str++; - } + // Check for negative (or positive) sign + if(*str == '-' || *str == '+') { + neg = (*str == '-'); + str++; } - - // Negate if needed - if(neg) ret = -ret; - return ret; -} -//printf -EXPORT int printf(const char *format, ...) -{ - int size; - char *buf; - va_list args; - - va_start(args, format); - size = ssprintfv((char*)format, args); - va_end(args); - - buf = (char*)malloc(size+1); - buf[size] = '\0'; - - va_start(args, format); - sprintfv(buf, (char*)format, args); - va_end(args); - - - write(_stdout, size+1, buf); - - free(buf); - return size; -} + ret = strtoull(str, end, base); -EXPORT int sprintf(const char *buf, char *format, ...) -{ - va_list args; - va_start(args, format); - sprintfv((char*)buf, (char*)format, args); - va_end(args); - return 1; + if( neg ) + return -ret; + else + return ret; } - -//MEMORY -EXPORT int strcmp(char *s1, char *s2) -{ - while(*s1 == *s2 && *s1 != '\0' && *s2 != '\0') { - s1++; s2++; - } - return (int)*s1 - (int)*s2; -} -EXPORT char *strcpy(char *dst, const char *src) +EXPORT long strtol(const char *str, char **end, int base) { - char *_dst = dst; - while(*src) { - *dst = *src; - src++; dst++; + long long tmp = strtoll(str, end, base); + if( tmp > LONG_MAX || tmp < LONG_MIN ) { + errno = ERANGE; + return (tmp > LONG_MAX) ? LONG_MAX : LONG_MIN; } - *dst = '\0'; - return _dst; -} -EXPORT int strlen(const char *str) -{ - int retval; - for(retval = 0; *str != '\0'; str++) - retval++; - return retval; + return tmp; } -EXPORT int strncmp(char *s1, char *s2, size_t len) +/** + * \fn EXPORT int atoi(const char *str) + * \brief Convert a string to an integer + */ +EXPORT int atoi(const char *str) { - while(--len && *s1 == *s2 && *s1 != '\0' && *s2 != '\0') { - s1++; s2++; + 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 (int)*s1 - (int)*s2; + return tmp; } -EXPORT void *memcpy(void *dest, void *src, unsigned int count) -{ - char *sp = (char *)src; - char *dp = (char *)dest; - for(;count--;) *dp++ = *sp++; - return dest; -} +int abs(int j) { return j < 0 ? -j : j; } +long int labs(long int j) { return j < 0 ? -j : j; } -EXPORT void *memmove(void *dest, void *src, unsigned int count) -{ - char *sp = (char *)src; - char *dp = (char *)dest; - // Check if corruption will happen - if( (unsigned int)dest > (unsigned int)src && (unsigned int)dest < (unsigned int)src+count ) - for(;count--;) dp[count] = sp[count]; - else - for(;count--;) *dp++ = *sp++; - return dest; -}