summaryrefslogtreecommitdiff
path: root/kernel/libc
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-06-27 23:29:38 +0200
committerAnton Kling <anton@kling.gg>2024-06-28 12:59:08 +0200
commita376751f6932abd1493845e705112c688ff3e734 (patch)
tree266b4dd72a788eb6263e33e1a6c788368eb43b38 /kernel/libc
parentbe160327599887876684f8ec106bd943f44ff068 (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/libc')
-rw-r--r--kernel/libc/stdio/print.c287
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, ...) {