X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=rpikern;a=blobdiff_plain;f=src%2Flibc%2Fstdio.c;fp=src%2Flibc%2Fstdio.c;h=4c721140db01af2a194bfdc50a3d8b6889218bc2;hp=0000000000000000000000000000000000000000;hb=32ccc707bc0821d7ff4248fe9f58e92e9c6ebef9;hpb=203b43a75a028e9238307bd6e73768eb8e942071 diff --git a/src/libc/stdio.c b/src/libc/stdio.c new file mode 100644 index 0000000..4c72114 --- /dev/null +++ b/src/libc/stdio.c @@ -0,0 +1,393 @@ +#include +#include +#include +#include +#include "contty.h" +#include "serial.h" +#include "panic.h" + +enum { + OUT_DEF, + OUT_BUF, + OUT_SCR, + OUT_SER +}; + +static int intern_printf(int out, char *buf, size_t sz, const char *fmt, va_list ap); +static int intern_scanf(const char *instr, FILE *infile, const char *fmt, va_list ap); +static void bwrite(int out, char *buf, size_t buf_sz, char *str, int sz); +/*static int readchar(const char *str, FILE *fp);*/ + +int putchar(int c) +{ + con_putchar(c); + return c; +} + +int puts(const char *s) +{ + while(*s) { + putchar(*s++); + } + putchar('\n'); + return 0; +} + +/* -- printf and friends -- */ + +int printf(const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = intern_printf(OUT_DEF, 0, 0, fmt, ap); + va_end(ap); + return res; +} + +int vprintf(const char *fmt, va_list ap) +{ + return intern_printf(OUT_DEF, 0, 0, fmt, ap); +} + +int sprintf(char *buf, const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = intern_printf(OUT_BUF, buf, 0, fmt, ap); + va_end(ap); + return res; +} + +int vsprintf(char *buf, const char *fmt, va_list ap) +{ + return intern_printf(OUT_BUF, 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(OUT_BUF, 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(OUT_BUF, buf, sz, fmt, ap); +} + +int fprintf(FILE *fp, const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = vfprintf(fp, fmt, ap); + va_end(ap); + return res; +} + +int vfprintf(FILE *fp, const char *fmt, va_list ap) +{ + if(fp == stdout || fp == stderr) { + return vprintf(fmt, ap); + } + + panic("*fprintf for anything other than stdout/stderr, not implemented yet\n"); + return 0; +} + +int ser_printf(const char *fmt, ...) +{ + int res; + va_list ap; + + va_start(ap, fmt); + res = intern_printf(OUT_SER, 0, 0, fmt, ap); + va_end(ap); + return res; +} + +int ser_vprintf(const char *fmt, va_list ap) +{ + return intern_printf(OUT_SER, 0, 0, fmt, ap); +} + +void perror(const char *s) +{ + printf("%s: %s\n", s, strerror(errno)); +} + +int getchar(void) +{ + return con_getchar(); +} + +/* 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. + */ +static char *convc = "dioxXucsfeEgGpn%"; + +#define IS_CONV(c) strchr(convc, c) + +#define BUF(x) ((x) ? (x) + cnum : (x)) +#define SZ(x) ((x) ? (x) - cnum : (x)) + +static int intern_printf(int out, 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; + int hex_caps = 0; + int unsig = 0; + int num, unum; + + 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(out, BUF(buf), SZ(sz), "0x", 2); + cnum += 2; + } + + case 'u': + unsig = 1; + + if(0) { + case 'o': + base = 8; + + if(alt) { + bwrite(out, BUF(buf), SZ(sz), "0", 1); + cnum++; + } + } + + case 'd': + case 'i': + if(unsig) { + unum = va_arg(ap, unsigned int); + utoa(unum, conv_buf, base); + } else { + num = va_arg(ap, int); + itoa(num, conv_buf, base); + } + if(hex_caps) { + for(i=0; conv_buf[i]; i++) { + conv_buf[i] = toupper(conv_buf[i]); + } + } + + slen = strlen(conv_buf); + + if(left_align) { + if(!unsig && sign && num >= 0) { + bwrite(out, BUF(buf), SZ(sz), "+", 1); + cnum++; + } + bwrite(out, BUF(buf), SZ(sz), conv_buf, slen); + cnum += slen; + padc = ' '; + } + for(i=slen; i= 0) { + bwrite(out, BUF(buf), SZ(sz), "+", 1); + cnum++; + } + bwrite(out, BUF(buf), SZ(sz), conv_buf, slen); + cnum += slen; + } + break; + + case 'c': + { + char c = va_arg(ap, int); + bwrite(out, BUF(buf), SZ(sz), &c, 1); + cnum++; + } + break; + + case 's': + str = va_arg(ap, char*); + slen = strlen(str); + + if(left_align) { + bwrite(out, BUF(buf), SZ(sz), str, slen); + cnum += slen; + padc = ' '; + } + for(i=slen; i