From cd0a4d84497fe89a8680ac0b881007ab6e97f44d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 4 Aug 2011 08:03:03 +0800 Subject: [PATCH] Usermode/libc - Fixed implementation of atexit and printf - *printf now supports string precision and padding - atexit implemented fully, but may not actually work --- Usermode/Libraries/crt0.o_src/crt0.asm | 11 +++ Usermode/Libraries/libc.so_src/fileIO.c | 113 ++++++++++++++++-------- Usermode/Libraries/libc.so_src/stdlib.c | 4 + Usermode/Libraries/libc.so_src/string.c | 20 +++-- Usermode/include/string.h | 3 +- 5 files changed, 108 insertions(+), 43 deletions(-) diff --git a/Usermode/Libraries/crt0.o_src/crt0.asm b/Usermode/Libraries/crt0.o_src/crt0.asm index b8f52703..81400c50 100644 --- a/Usermode/Libraries/crt0.o_src/crt0.asm +++ b/Usermode/Libraries/crt0.o_src/crt0.asm @@ -15,5 +15,16 @@ _start: start: call main push eax + + mov eax, [_crt0_exit_handler] + test eax, eax + jz .exit + call [eax] + +.exit: call _exit jmp $ ; This should never be reached +[section .bss] +[global _crt0_exit_handler] +_crt0_exit_handler: + resd 1 diff --git a/Usermode/Libraries/libc.so_src/fileIO.c b/Usermode/Libraries/libc.so_src/fileIO.c index 4117b02f..b588f246 100644 --- a/Usermode/Libraries/libc.so_src/fileIO.c +++ b/Usermode/Libraries/libc.so_src/fileIO.c @@ -299,12 +299,18 @@ EXPORT int vsprintf(char * __s, const char *__format, va_list __args) EXPORT int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list args) { char tmp[65]; - int c, minSize; + int c, minSize, precision, len; int pos = 0; char *p; char pad; uint64_t arg; - int bLongLong; + int bLongLong, bPadLeft; + + void _addchar(char ch) + { + if(buf && pos < __maxlen) buf[pos] = ch; + pos ++; + } tmp[32] = '\0'; @@ -312,34 +318,64 @@ EXPORT int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list arg { // Non-control character if (c != '%') { - if(buf && pos < __maxlen) buf[pos] = c; - pos ++; + _addchar(c); continue; } // Control Character c = *format++; if(c == '%') { // Literal % - if(buf && pos < __maxlen) buf[pos] = '%'; - pos ++; + _addchar('%'); continue; } - // Padding + bPadLeft = 0; + bLongLong = 0; + minSize = 0; + precision = -1; + pad = ' '; + + // Padding Character if(c == '0') { pad = '0'; c = *format++; - } else - pad = ' '; - minSize = 0; - if('1' <= c && c <= '9') - { - while('0' <= c && c <= '9') + } + // Padding length + if( c == '*' ) { + // Variable length + minSize = va_arg(args, size_t); + c = *format++; + } + else { + if('1' <= c && c <= '9') { - minSize *= 10; - minSize += c - '0'; + minSize = 0; + while('0' <= c && c <= '9') + { + minSize *= 10; + minSize += c - '0'; + c = *format++; + } + } + } + + // Precision + if(c == '.') { + c = *format++; + if(c == '*') { + precision = va_arg(args, size_t); c = *format++; } + else if('1' <= c && c <= '9') + { + precision = 0; + while('0' <= c && c <= '9') + { + precision *= 10; + precision += c - '0'; + c = *format++; + } + } } // Check for long long @@ -351,7 +387,8 @@ EXPORT int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list arg bLongLong = 1; } } - + + // Just help things along later p = tmp; // Get Type @@ -363,6 +400,7 @@ EXPORT int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list arg if(bLongLong) arg = va_arg(args, int64_t); else arg = va_arg(args, int32_t); itoa(tmp, arg, 10, minSize, pad, 1); + precision = -1; goto sprintf_puts; // Unsigned Integer @@ -371,25 +409,24 @@ EXPORT int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list arg if(bLongLong) arg = va_arg(args, uint64_t); else arg = va_arg(args, uint32_t); itoa(tmp, arg, 10, minSize, pad, 0); + precision = -1; goto sprintf_puts; // Pointer case 'p': - if(buf && pos+2 < __maxlen) { - buf[pos] = '*'; - buf[pos+1] = '0'; - buf[pos+2] = 'x'; - } - pos += 3; + _addchar('*'); + _addchar('0'); + _addchar('x'); arg = va_arg(args, uint32_t); itoa(tmp, arg, 16, minSize, pad, 0); + precision = -1; goto sprintf_puts; - // Fall through to hex // Unsigned Hexadecimal case 'x': if(bLongLong) arg = va_arg(args, uint64_t); else arg = va_arg(args, uint32_t); itoa(tmp, arg, 16, minSize, pad, 0); + precision = -1; goto sprintf_puts; // Unsigned Octal @@ -397,6 +434,7 @@ EXPORT int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list arg if(bLongLong) arg = va_arg(args, uint64_t); else arg = va_arg(args, uint32_t); itoa(tmp, arg, 8, minSize, pad, 0); + precision = -1; goto sprintf_puts; // Unsigned binary @@ -404,6 +442,7 @@ EXPORT int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list arg if(bLongLong) arg = va_arg(args, uint64_t); else arg = va_arg(args, uint32_t); itoa(tmp, arg, 2, minSize, pad, 0); + precision = -1; goto sprintf_puts; // String @@ -413,28 +452,28 @@ EXPORT int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list arg sprintf_puts: if(!p) p = "(null)"; //_SysDebug("vsnprintf: p = '%s'", p); - if(buf) { - while(*p) { - if(pos < __maxlen) buf[pos] = *p; - pos ++; p ++; - } - } - else { - while(*p) { - pos++; p++; - } + if(precision >= 0) + len = strnlen(p, precision); + else + len = strlen(p); + if(bPadLeft) while(minSize > len++) _addchar(pad); + while( *p ) { + if(precision >= 0 && precision -- == 0) + break; + _addchar(*p++); } + if(!bPadLeft) while(minSize > len++) _addchar(pad); break; // Unknown, just treat it as a character default: arg = va_arg(args, uint32_t); - if(buf && pos < __maxlen) buf[pos] = arg; - pos ++; + _addchar(arg); break; } - } - if(buf && pos < __maxlen) buf[pos] = '\0'; + } + _addchar('\0'); + pos --; //_SysDebug("vsnprintf: buf = '%s'", buf); diff --git a/Usermode/Libraries/libc.so_src/stdlib.c b/Usermode/Libraries/libc.so_src/stdlib.c index 94d9d1dc..191f5261 100644 --- a/Usermode/Libraries/libc.so_src/stdlib.c +++ b/Usermode/Libraries/libc.so_src/stdlib.c @@ -13,6 +13,8 @@ #define _stdout 1 #define _stdin 0 +extern void *_crt0_exit_handler; + // === PROTOTYPES === EXPORT int atoi(const char *str); EXPORT void exit(int status); @@ -24,6 +26,8 @@ void (*g_stdlib_exithandler)(void); void atexit(void (*__func)(void)) { g_stdlib_exithandler = __func; + // TODO: Replace with meta-function to allow multiple atexit() handlers + _crt0_exit_handler = __func; } /** diff --git a/Usermode/Libraries/libc.so_src/string.c b/Usermode/Libraries/libc.so_src/string.c index 607039ed..1c052366 100644 --- a/Usermode/Libraries/libc.so_src/string.c +++ b/Usermode/Libraries/libc.so_src/string.c @@ -77,17 +77,27 @@ EXPORT char *strcat(char *dst, const char *src) } /** - * \fn EXPORT int strlen(const char *str) * \brief Get the length of a string */ -EXPORT int strlen(const char *str) +EXPORT size_t strlen(const char *str) { - int retval; - for(retval = 0; *str != '\0'; str++) - retval++; + size_t retval; + for(retval = 0; *str != '\0'; str++, retval++); return retval; } +/** + * \brief Get the length of a string, with a maximum of \a maxlen + * + * Gets the length of a string (excluding the terminating \0 byte) + */ +EXPORT size_t strnlen(const char *str, size_t maxlen) +{ + size_t len; + for( len = 0; maxlen -- && *str; str ++, len ++ ); + return len; +} + /** * \fn EXPORT char *strdup(const char *str) * \brief Duplicate a string using heap memory diff --git a/Usermode/include/string.h b/Usermode/include/string.h index 00f748dd..611dacbb 100644 --- a/Usermode/include/string.h +++ b/Usermode/include/string.h @@ -8,7 +8,8 @@ #include // Strings -extern int strlen(const char *string); +extern size_t strlen(const char *string); +extern size_t strnlen(const char *string, size_t maxlen); extern int strcmp(const char *str1, const char *str2); extern int strncmp(const char *str1, const char *str2, size_t len); extern char *strcpy(char *dst, const char *src); -- 2.20.1