summaryrefslogtreecommitdiff
path: root/kernel/printf.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/printf.c')
-rw-r--r--kernel/printf.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/kernel/printf.c b/kernel/printf.c
new file mode 100644
index 0000000..4b3a632
--- /dev/null
+++ b/kernel/printf.c
@@ -0,0 +1,96 @@
+#include "printf.h"
+#include "types.h"
+
+#define outb(port, value) asm volatile("out %b0,%w1" : : "a" (value), "d" (port));
+
+void putchar(char c) {
+ if(c == '\n') {
+ outb(0x3f8, '\r');
+ }
+ outb(0x3f8, c);
+}
+
+int printf(const char* format, ...) {
+ int32_t* argp = (int32_t*)&format;
+ int num;
+
+ while(*format) {
+ if(*format != '%') {
+ putchar(*format++);
+ num++;
+ continue;
+ }
+ format++;
+
+ bool is_signed = false;
+ bool zero_pad = false;
+ int radix = 16;
+ int min_len = 0;
+
+ if(*format == '0') {
+ zero_pad = true;
+ }
+
+ while(*format >= '0' && *format <= '9') {
+ min_len = min_len * 10 + *format++ - '0';
+ }
+
+ switch(*format++) {
+ case '%':
+ putchar('%');
+ num++;
+ break;
+
+ case 'c':
+ putchar((char)*++argp);
+ num++;
+ break;
+
+ case 's':
+ ;
+ char* str = (char*)*++argp;
+ while(*str) {
+ putchar(*str++);
+ num++;
+ }
+ break;
+
+ case 'd':
+ is_signed = true;
+ case 'u':
+ radix = 10;
+ case 'x':
+ ;
+ uint32_t x = (uint32_t)*(++argp);
+ if(is_signed && (int32_t)x < 0) {
+ x = -x;
+ putchar('-');
+ min_len--;
+ }
+
+ char buf[11];
+ char* bufp = &buf[sizeof(buf)];
+ *--bufp = 0;
+
+ do {
+ int d = x % radix;
+ *--bufp = d < 10 ? '0' + d : 'a' - 10 + d;
+ x /= radix;
+ min_len--;
+ } while(x);
+
+ while(min_len > 0) {
+ putchar(zero_pad ? '0' : ' ');
+ num++;
+ min_len--;
+ }
+
+ while(*bufp) {
+ putchar(*bufp++);
+ num++;
+ }
+ break;
+ }
+ }
+ return num;
+}