diff options
author | Anton Kling <anton@kling.gg> | 2024-06-27 23:29:38 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-06-28 12:59:08 +0200 |
commit | a376751f6932abd1493845e705112c688ff3e734 (patch) | |
tree | 266b4dd72a788eb6263e33e1a6c788368eb43b38 /kernel | |
parent | be160327599887876684f8ec106bd943f44ff068 (diff) |
Kernel: Port over libc printf to kernel
Kernel printf had bugs and was poorly written. LibC still has some FILE*
releated stuff that should be cleaned up.
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/libc/stdio/print.c | 287 |
1 files changed, 237 insertions, 50 deletions
diff --git a/kernel/libc/stdio/print.c b/kernel/libc/stdio/print.c index e8b245f..b432364 100644 --- a/kernel/libc/stdio/print.c +++ b/kernel/libc/stdio/print.c @@ -1,100 +1,287 @@ #include <assert.h> #include <drivers/serial.h> #include <stdio.h> +#include <string.h> #define TAB_SIZE 8 -const char HEX_SET[0x10] = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - inline void putc(const char c) { write_serial(c); } -int kprint_hex(u64 num) { - int c = 2; +inline void put_string(const char *s, int l) { + for (; l > 0; l--, s++) { + write_serial(*s); + } +} - if (num == 0) { - putc('0'); - c++; - return c; +#define WRITE(_s, _l, _r) \ + { \ + put_string(_s, _l); \ + *(int *)(_r) += _l; \ } - char str[16] = {0}; +int print_num(long long n, int base, char *char_set, int prefix, + int zero_padding, int right_padding) { + int c = 0; + char str[32]; int i = 0; - for (; num != 0 && i < 16; i++, num /= 16) { - str[i] = HEX_SET[(num % 16)]; + + int is_signed = 0; + + if (n < 0) { + is_signed = 1; + n *= -1; + } + + if (0 == n) { + str[i] = char_set[0]; + i++; + } else { + for (; n != 0 && i < 32; i++, n /= base) { + str[i] = char_set[(n % base)]; + } + } + + if (is_signed) { + str[i] = '-'; + i++; + } + + char t = (zero_padding) ? '0' : ' '; + int orig_i = i; + + if (!right_padding) { + for (; prefix - orig_i > 0; prefix--) { + WRITE(&t, 1, &c); + } } - c += i; for (i--; i >= 0; i--) { - putc(str[i]); + WRITE(&(str[i]), 1, &c); } + if (right_padding) { + for (; prefix - orig_i > 0; prefix--) { + WRITE(&t, 1, &c); + } + } return c; } -int kprint_int(int num) { +int print_int(long long n, int prefix, int zero_padding, int right_padding) { + return print_num(n, 10, "0123456789", prefix, zero_padding, right_padding); +} + +int print_hex(long long n, int prefix, int zero_padding, int right_padding) { + return print_num(n, 16, "0123456789abcdef", prefix, zero_padding, + right_padding); +} + +int print_octal(long long n, int prefix, int zero_padding, int right_padding) { + return print_num(n, 8, "012345678", prefix, zero_padding, right_padding); +} + +int print_string(const char *s, int *rc, int prefix, int right_padding, + int precision) { + int l = strlen(s); + char t = ' '; int c = 0; - if (0 == num) { - putc('0'); - c++; - return c; + if (!right_padding) { + if (prefix) { + assert(-1 == precision); // FIXME: Is this correct? + } + for (; prefix - l > 0; prefix--) { + WRITE(&t, 1, &c); + } } - char str[10]; - int i = 0; - for (; num != 0 && i < 10; i++, num /= 10) { - str[i] = (num % 10) + '0'; + int bl = precision; + for (; *s; s++, (*rc)++) { + if (precision != -1) { + if (0 == bl) { + break; + } + bl--; + } + int r = 0; + WRITE((const unsigned char *)s, 1, &r); + } + if (right_padding) { + assert(-1 == precision); // FIXME: Is this correct? + for (; prefix - l > 0; prefix--) { + WRITE(&t, 1, &c); + } } + (*rc) += c; + return 0; +} - c += i; - for (i--; i >= 0; i--) { - putc(str[i]); +int parse_precision(const char **fmt) { + const char *s = *fmt; + int rc = 0; + for (int i = 0;; i++, s++) { + if ('\0' == *s) { + break; + } + const char c = *s; + if ('*' == c) { + assert(i == 0); + return -1; + } else if (!(c >= '0' && c <= '9')) { + s--; + break; + } + rc *= 10; + rc += c - '0'; } - return c; + *fmt = s; + return rc; } -int vkprintf(const char *format, va_list list) { - int c = 0; - const char *s = format; +int vkprintf(const char *fmt, va_list ap) { + int rc = 0; + const char *s = fmt; + int prefix = 0; + + int long_level = 0; + + int zero_padding = 0; + int right_padding = 0; + + int cont = 0; + int precision = -1; for (; *s; s++) { - if ('%' != *s) { - putc(*s); - c++; + if (!cont && '%' != *s) { + WRITE((const unsigned char *)s, 1, &rc); + continue; + } + if (!cont) { + cont = 1; continue; } - char flag = *(s + 1); - if ('\0' == flag) { + if ('\0' == *s) { break; } - switch (flag) { - case 'c': - putc((char)va_arg(list, int)); - c++; + switch (*s) { + case '.': + s++; + assert('\0' != *s); + precision = parse_precision(&s); + assert('\0' != *s); + if (-1 == precision) { + precision = va_arg(ap, int); + } + cont = 1; + break; + case '0': + prefix *= 10; + if (0 == prefix) { + zero_padding = 1; + } + cont = 1; + break; + case '-': + assert(0 == prefix); + right_padding = 1; + cont = 1; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + prefix *= 10; + prefix += (*s) - '0'; + cont = 1; break; + case 'l': + long_level++; + assert(long_level <= 2); + break; + case 'i': case 'd': - c += kprint_int(va_arg(list, int)); + if (-1 != precision) { + zero_padding = 1; + prefix = precision; + right_padding = 0; + } + if (2 == long_level) { + rc += print_int(va_arg(ap, long long), prefix, zero_padding, + right_padding); + } else if (1 == long_level) { + rc += print_int(va_arg(ap, long long), prefix, zero_padding, + right_padding); + } else { + rc += print_int(va_arg(ap, int), prefix, zero_padding, right_padding); + } + long_level = 0; + cont = 0; + break; + case 'u': + assert(-1 == precision); + rc += print_int(va_arg(ap, unsigned int), prefix, zero_padding, + right_padding); + cont = 0; break; - case 's': - for (char *string = va_arg(list, char *); *string; putc(*string++), c++) - ; + case 's': { + assert(!zero_padding); // this is not supported to strings + char *a = va_arg(ap, char *); + if (!a) { + if (-1 == + print_string("(NULL)", &rc, prefix, right_padding, precision)) { + return -1; + } + cont = 0; + break; + } + if (-1 == print_string(a, &rc, prefix, right_padding, precision)) { + return -1; + } + cont = 0; break; + } + case 'p': // TODO: Print this out in a nicer way case 'x': - c += kprint_hex(va_arg(list, const u32)); + assert(-1 == precision); + rc += + print_hex(va_arg(ap, const u32), prefix, zero_padding, right_padding); + cont = 0; break; - case '%': - putc('%'); - c++; + case 'o': + assert(-1 == precision); + rc += print_octal(va_arg(ap, const u32), prefix, zero_padding, + right_padding); + cont = 0; break; + case '%': { + WRITE((const unsigned char *)"%", 1, &rc); + cont = 0; + break; + } + case 'c': { + char c = va_arg(ap, const int); + WRITE((const unsigned char *)&c, 1, &rc); + cont = 0; + break; + } default: - ASSERT_NOT_REACHED; + kprintf("got %c but that is not supported by printf\n", *s); + assert(0); break; } - s++; + if (!cont) { + prefix = 0; + zero_padding = right_padding = 0; + precision = -1; + } } - return c; + return rc; } int kprintf(const char *format, ...) { |