diff options
Diffstat (limited to 'printf.c')
-rw-r--r-- | printf.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/printf.c b/printf.c new file mode 100644 index 0000000..a171d24 --- /dev/null +++ b/printf.c @@ -0,0 +1,256 @@ +#include "bios.h" +#include "stdio.h" +#include "string.h" +#include "stdlib.h" +#include "ioport.h" + +typedef struct pstream { + char *buffer; + int remain; + int added; +} pstream_t; + +typedef struct strprops { + char pad; + int npad; +} strprops_t; + +static void addchar(pstream_t *p, char c) +{ + if (p->remain) { + *p->buffer++ = c; + --p->remain; + } + ++p->added; +} + +int puts(const char *c) +{ + int n = 0; + while (c[n]) + outb(0x3f8, c[n++]); + return n; +} + +void print_str(pstream_t *p, const char *s, strprops_t props) +{ + const char *s_orig = s; + int npad = props.npad; + + if (npad > 0) { + npad -= strlen(s_orig); + while (npad > 0) { + addchar(p, props.pad); + --npad; + } + } + + while (*s) + addchar(p, *s++); + + if (npad < 0) { + props.pad = ' '; /* ignore '0' flag with '-' flag */ + npad += strlen(s_orig); + while (npad < 0) { + addchar(p, props.pad); + ++npad; + } + } +} + +static char digits[16] = "0123456789abcdef"; + +void print_int(pstream_t *ps, long n, int base, strprops_t props) +{ + char buf[sizeof(long) * 3 + 2], *p = buf; + int s = 0, i; + + if (n < 0) { + n = -n; + s = 1; + } + + while (n) { + *p++ = digits[n % base]; + n /= base; + } + + if (s) + *p++ = '-'; + + if (p == buf) + *p++ = '0'; + + for (i = 0; i < (p - buf) / 2; ++i) { + char tmp; + + tmp = buf[i]; + buf[i] = p[-1-i]; + p[-1-i] = tmp; + } + + *p = 0; + + print_str(ps, buf, props); +} + +void print_unsigned(pstream_t *ps, unsigned long n, int base, + strprops_t props) +{ + char buf[sizeof(long) * 3 + 1], *p = buf; + int i; + + while (n) { + *p++ = digits[n % base]; + n /= base; + } + + if (p == buf) + *p++ = '0'; + + for (i = 0; i < (p - buf) / 2; ++i) { + char tmp; + + tmp = buf[i]; + buf[i] = p[-1-i]; + p[-1-i] = tmp; + } + + *p = 0; + + print_str(ps, buf, props); +} + +static int fmtnum(const char **fmt) +{ + const char *f = *fmt; + int len = 0, num; + + if (*f == '-') + ++f, ++len; + + while (*f >= '0' && *f <= '9') + ++f, ++len; + + num = atol(*fmt); + *fmt += len; + return num; +} + +int vsnprintf(char *buf, int size, const char *fmt, va_list va) +{ + pstream_t s; + + s.buffer = buf; + s.remain = size - 1; + s.added = 0; + while (*fmt) { + char f = *fmt++; + int nlong = 0; + strprops_t props; + memset(&props, 0, sizeof(props)); + props.pad = ' '; + + if (f != '%') { + addchar(&s, f); + continue; + } + morefmt: + f = *fmt++; + do { + if (f == '%') { + addchar(&s, '%'); + break; + } + if (f == 'c') { + addchar(&s, va_arg(va, int)); + break; + } + if (f == '\0') { + --fmt; + break; + } + if (f == '0') { + props.pad = '0'; + ++fmt; + /* fall through */ + } + if ((f >= '1' && f <= '9') || f == '-') { + --fmt; + props.npad = fmtnum(&fmt); + goto morefmt; + } + if (f == 'l') { + ++nlong; + goto morefmt; + } + if (f == 'd') { + switch (nlong) { + case 0: + print_int(&s, va_arg(va, int), 10, props); + break; + case 1: + print_int(&s, va_arg(va, long), 10, props); + break; + default: + panic(); + break; + } + break; + } + if (f == 'x') { + switch (nlong) { + case 0: + print_unsigned(&s, va_arg(va, unsigned), 16, props); + break; + case 1: + print_unsigned(&s, va_arg(va, unsigned long), 16, props); + break; + default: + panic(); + break; + } + break; + } + if (f == 'p') { + print_str(&s, "0x", props); + print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props); + break; + } + if (f == 's') { + print_str(&s, va_arg(va, const char *), props); + break; + } + addchar(&s, f); + break; + } while(0); + } + *s.buffer = 0; + ++s.added; + return s.added; +} + + +int snprintf(char *buf, int size, const char *fmt, ...) +{ + va_list va; + int r; + + va_start(va, fmt); + r = vsnprintf(buf, size, fmt, va); + va_end(va); + return r; +} + +int printf(const char *fmt, ...) +{ + va_list va; + char buf[2000]; + int r; + + va_start(va, fmt); + r = vsnprintf(buf, sizeof buf, fmt, va); + va_end(va); + puts(buf); + return r; +} |