# HG changeset patch # User John Tsiombikas # Date 1292764027 -7200 # Node ID 633e35c64772740186895372bbf6d1509a9e9698 # Parent 0489a34ab348d9c41f4651f2a5940027ec68a2cf - added printf family in stdio.c - added atoi/atol in stdlib.c - added nonstandard itoa/utoa in stdlib.c - added strlen/strchr/strrchr in string.c diff -r 0489a34ab348 -r 633e35c64772 src/klibc/stdio.c --- a/src/klibc/stdio.c Fri Dec 10 03:44:34 2010 +0200 +++ b/src/klibc/stdio.c Sun Dec 19 15:07:07 2010 +0200 @@ -1,4 +1,9 @@ #include +#include +#include + +static void bwrite(char *buf, size_t buf_sz, char *str, int sz); +static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap); /* putchar is defined in term.c */ @@ -10,3 +15,243 @@ putchar('\n'); return 0; } + +/* -- printf and friends -- */ + +static char *convc = "dioxXucsfeEgGpn%"; + +#define IS_CONV(c) strchr(convc, c) + +int printf(const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = intern_printf(0, 0, fmt, ap); + va_end(ap); + return res; +} + +int vprintf(const char *fmt, va_list ap) +{ + return intern_printf(0, 0, fmt, ap); +} + +int sprintf(char *buf, const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = intern_printf(buf, 0, fmt, ap); + va_end(ap); + return res; +} + +int vsprintf(char *buf, const char *fmt, va_list ap) +{ + return intern_printf(buf, 0, fmt, ap); +} + +int snprintf(char *buf, size_t sz, const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = intern_printf(buf, sz, fmt, ap); + va_end(ap); + return res; +} + +int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap) +{ + return intern_printf(buf, sz, fmt, ap); +} + + +/* intern_printf provides all the functionality needed by all the printf + * variants. + * - buf: optional buffer onto which the formatted results are written. If null + * then the output goes to the terminal through putchar calls. This is used + * by the (v)sprintf variants which write to an array of char. + * - sz: optional maximum size of the output, 0 means unlimited. This is used + * by the (v)snprintf variants to avoid buffer overflows. + * The rest are obvious, format string and variable argument list. + */ + +#define BUF(x) ((x) ? (x) + cnum : (x)) +#define SZ(x) ((x) ? (x) - cnum : (x)) + +static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap) +{ + char conv_buf[32]; + char *str; + int i, slen; + const char *fstart = 0; + + /* state */ + int cnum = 0; + int base = 10; + int alt = 0; + int fwidth = 0; + int padc = ' '; + int sign = 0; + int left_align = 0; /* not implemented yet */ + int hex_caps = 0; + int unsig = 0; + + while(*fmt) { + if(*fmt == '%') { + fstart = fmt++; + continue; + } + + if(fstart) { + if(IS_CONV(*fmt)) { + switch(*fmt) { + case 'X': + hex_caps = 1; + + case 'x': + case 'p': + base = 16; + + if(alt) { + bwrite(BUF(buf), SZ(sz), "0x", 2); + } + + case 'u': + unsig = 1; + + if(0) { + case 'o': + base = 8; + + if(alt) { + bwrite(BUF(buf), SZ(sz), "0", 1); + } + } + + case 'd': + case 'i': + if(unsig) { + utoa(va_arg(ap, unsigned int), conv_buf, base); + } else { + itoa(va_arg(ap, int), conv_buf, base); + } + if(hex_caps) { + for(i=0; conv_buf[i]; i++) { + conv_buf[i] = toupper(conv_buf[i]); + } + } + + slen = strlen(conv_buf); + for(i=slen; i +#include + int putchar(int c); int puts(const char *s); +int printf(const char *fmt, ...); +int vprintf(const char *fmt, va_list ap); + +int sprintf(char *buf, const char *fmt, ...); +int vsprintf(char *buf, const char *fmt, va_list ap); + +int snprintf(char *buf, size_t sz, const char *fmt, ...); +int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap); + #endif /* STDIO_H_ */ diff -r 0489a34ab348 -r 633e35c64772 src/klibc/stdlib.h --- a/src/klibc/stdlib.h Fri Dec 10 03:44:34 2010 +0200 +++ b/src/klibc/stdlib.h Sun Dec 19 15:07:07 2010 +0200 @@ -6,4 +6,10 @@ typedef int32_t ssize_t; typedef uint32_t size_t; +int atoi(const char *str); +long atol(const char *str); + +void itoa(int val, char *buf, int base); +void utoa(unsigned int val, char *buf, int base); + #endif /* STDLIB_H_ */ diff -r 0489a34ab348 -r 633e35c64772 src/klibc/string.c --- a/src/klibc/string.c Fri Dec 10 03:44:34 2010 +0200 +++ b/src/klibc/string.c Sun Dec 19 15:07:07 2010 +0200 @@ -54,3 +54,37 @@ return dest; } + +size_t strlen(const char *s) +{ + size_t len = 0; + while(*s++) len++; + return len; +} + +char *strchr(const char *s, int c) +{ + while(*s) { + if(*s == c) { + return s; + } + s++; + } + return 0; +} + +char *strrchr(const char *s, int c) +{ + char *ptr = s; + + /* find the end */ + while(*ptr) ptr++; + + /* go back checking for c */ + while(*--ptr >= s) { + if(*ptr == c) { + return ptr; + } + } + return 0; +} diff -r 0489a34ab348 -r 633e35c64772 src/klibc/string.h --- a/src/klibc/string.h Fri Dec 10 03:44:34 2010 +0200 +++ b/src/klibc/string.h Sun Dec 19 15:07:07 2010 +0200 @@ -9,4 +9,9 @@ void *memcpy(void *dest, const void *src, size_t n); void *memmove(void *dest, const void *src, size_t n); +size_t strlen(const char *s); + +char *strchr(const char *s, int c); +char *strrchr(const char *s, int c); + #endif /* STRING_H_ */