summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kernel/arch/amd64/boot.c3
-rw-r--r--src/shared/printf.c172
-rw-r--r--src/user/app/iostress/iostress.c2
-rw-r--r--src/user/app/shell/shell.c2
-rw-r--r--src/user/app/testelf/main.c4
-rw-r--r--src/user/app/tests/printf.c32
-rw-r--r--src/user/app/tests/tests.c11
-rw-r--r--src/user/app/tests/tests.h4
8 files changed, 158 insertions, 72 deletions
diff --git a/src/kernel/arch/amd64/boot.c b/src/kernel/arch/amd64/boot.c
index 301df52..570cebb 100644
--- a/src/kernel/arch/amd64/boot.c
+++ b/src/kernel/arch/amd64/boot.c
@@ -53,8 +53,7 @@ void kmain_early(struct multiboot_info *multiboot) {
vid.height = multiboot->framebuffer_height;
vid.bpp = multiboot->framebuffer_bpp;
- // TODO printf decimal
- kprintf("framebuffer at 0x%x, %xx%x bpp 0x%x\n", vid.b, vid.width, vid.height, vid.bpp);
+ kprintf("framebuffer at 0x%x, %ux%u bpp %u\n", vid.b, vid.width, vid.height, vid.bpp);
video_init(vid);
diff --git a/src/shared/printf.c b/src/shared/printf.c
index b50d4ef..47d56f8 100644
--- a/src/shared/printf.c
+++ b/src/shared/printf.c
@@ -1,71 +1,133 @@
+#include <stdbool.h>
#include <shared/mem.h>
#include <shared/printf.h>
+struct out_state {
+ void (*back)(void *, const char *, size_t);
+ void *backarg;
+ int written;
+};
+
+static int output(struct out_state *os, const char *buf, size_t len) {
+ if (len) os->back(os->backarg, buf, len);
+ os->written += len;
+ return os->written;
+}
+
+static void output_c(struct out_state *os, char c) {
+ output(os, &c, 1);
+}
+
+
+struct mods {
+ char fill_char;
+ size_t field_width;
+};
+
+static void pad(struct out_state *os, struct mods *m, size_t len) {
+ for (size_t i = 0; len + i < m->field_width; i++)
+ output(os, &m->fill_char, 1);
+}
+
+static void output_uint(struct out_state *os, struct mods *m, unsigned long long n) {
+ // TODO static assert sizeof(unsigned long long) <= 8
+ char buf[20];
+ size_t pos = sizeof(buf);
+
+ if (!n) {
+ buf[--pos] = '0';
+ } else while (n) {
+ unsigned long long q = n / 10, r = n % 10;
+ buf[--pos] = r + '0';
+ n = q;
+ }
+ pad(os, m, sizeof(buf) - pos);
+ output(os, buf + pos, sizeof(buf) - pos);
+}
+
+
int __printf_internal(const char *fmt, va_list argp,
- void (*back)(void*, const char*, size_t), void *back_arg)
+ void (*back)(void*, const char*, size_t), void *backarg)
{
- const char *seg = fmt; // beginning of the current segment
- int total = 0;
+ const char *seg = fmt; /* beginning of the current non-modifier streak */
+ struct out_state os = {
+ .back = back,
+ .backarg = backarg,
+ };
for (;;) {
char c = *fmt++;
+ if (c == '\0') {
+ return output(&os, seg, fmt - seg - 1);
+ }
+ if (c != '%') continue;
+ output(&os, seg, fmt - seg - 1);
+
+ struct mods m = {
+ .fill_char = ' ',
+ .field_width = 0,
+ };
+
+ for (bool modifier = true; modifier;) {
+ c = *fmt++;
+ switch (c) {
+ case '0':
+ m.fill_char = '0';
+ break;
+ default:
+ modifier = false;
+ break;
+ }
+ }
+
+ while ('0' <= c && c <= '9') {
+ m.field_width *= 10;
+ m.field_width += c - '0';
+ c = *fmt++;
+ }
+
+ // TODO length modifiers
+
switch (c) {
- case '\0':
- back(back_arg, seg, fmt - seg - 1);
- return total + (fmt - seg - 1);
+ unsigned long n, len;
- case '%':
- back(back_arg, seg, fmt - seg - 1);
- total += fmt - seg - 1;
- size_t pad_len = 0;
-
- c = *fmt++;
- while (1) {
- switch (c) {
- case '0':
- pad_len = *fmt++ - '0'; // can skip over the null byte, idc
- break;
- default:
- goto modifier_break;
- }
- c = *fmt++;
+ case 'c':
+ output_c(&os, va_arg(argp, int));
+ break;
+
+ case 's':
+ const char *s = va_arg(argp, char*);
+ if (s) {
+ len = strlen(s);
+ pad(&os, &m, len);
+ output(&os, s, len);
+ } else {
+ pad(&os, &m, 0);
}
-modifier_break:
- switch (c) {
- case 'c':
- char c = va_arg(argp, int);
- back(back_arg, &c, 1);
- total += 1;
- break;
-
- case 's':
- const char *s = va_arg(argp, char*);
- if (s) {
- back(back_arg, s, strlen(s));
- total += strlen(s);
- }
- break;
-
- case 'x':
- unsigned long n = va_arg(argp, long);
- size_t i = 4; // nibbles * 4
- while (n >> i && i < (sizeof(n) * 8))
- i += 4;
-
- if (i < pad_len * 4)
- i = pad_len * 4;
-
- while (i > 0) {
- i -= 4;
- char h = '0' + ((n >> i) & 0xf);
- if (h > '9') h += 'a' - '9' - 1;
- back(back_arg, &h, 1);
- total++;
- }
- break;
+ break;
+
+ case 'x':
+ n = va_arg(argp, unsigned long);
+ len = 1;
+ while (n >> (len * 4) && (len * 4) < (sizeof(n) * 8))
+ len++;
+ pad(&os, &m, len);
+ while (len-- > 0) {
+ char h = '0' + ((n >> (len * 4)) & 0xf);
+ if (h > '9') h += 'a' - '9' - 1;
+ output_c(&os, h);
}
- seg = fmt;
+ break;
+
+ case 'u':
+ n = va_arg(argp, unsigned long);
+ output_uint(&os, &m, n);
+ break;
+
+ case '%':
+ output(&os, "%", 1);
break;
}
+ seg = fmt;
}
}
diff --git a/src/user/app/iostress/iostress.c b/src/user/app/iostress/iostress.c
index 843a19a..27e9d33 100644
--- a/src/user/app/iostress/iostress.c
+++ b/src/user/app/iostress/iostress.c
@@ -18,7 +18,7 @@ int main(void) {
}
for (int i = 0; i < NUM_RUNS; i++) {
- printf("run %x: %x\n", i, results[i] / 3000);
+ printf("run %u: %u\n", i, results[i] / 3000);
}
return 0;
diff --git a/src/user/app/shell/shell.c b/src/user/app/shell/shell.c
index 6eb328f..66725a1 100644
--- a/src/user/app/shell/shell.c
+++ b/src/user/app/shell/shell.c
@@ -51,7 +51,7 @@ static void run_args(int argc, char **argv, struct redir *redir) {
uint64_t div = 3000;
run_args(argc - 1, argv + 1, redir);
time = __rdtsc() - time;
- printf("0x%x ns (assuming 3GHz)\n", time / div);
+ printf("%u ns (assuming 3GHz)\n", time / div);
return;
} else if (!strcmp(argv[0], "exit")) {
exit(0);
diff --git a/src/user/app/testelf/main.c b/src/user/app/testelf/main.c
index 5111791..aa1f596 100644
--- a/src/user/app/testelf/main.c
+++ b/src/user/app/testelf/main.c
@@ -5,8 +5,8 @@ const char *str = "Hello!", *str2 = "World.";
int main(int argc, char **argv, char **envp) {
printf("elftest's &main == 0x%x\n", &main);
printf("%s %s\n", str, str2);
- printf("argc == 0x%x\n", argc);
+ printf("argc == %u\n", argc);
for (int i = 0; i < argc; i++)
- printf("argv[0x%x] == 0x%x == \"%s\"\n", i, argv[i], argv[i]);
+ printf("argv[%u] == 0x%x == \"%s\"\n", i, argv[i], argv[i]);
return 0;
}
diff --git a/src/user/app/tests/printf.c b/src/user/app/tests/printf.c
new file mode 100644
index 0000000..6c6c609
--- /dev/null
+++ b/src/user/app/tests/printf.c
@@ -0,0 +1,32 @@
+#define TEST_MACROS
+#include "tests.h"
+#include <stdio.h>
+#include <string.h>
+
+void test_printf(void) {
+ char buf[64];
+ memset(buf, '?', 64);
+
+ /* test proper overflow handling in snprintf */
+ assert(13 == snprintf(buf, 15, "That's 0x%x", 0x1337));
+ assert(!memcmp(buf, "That's 0x1337\0??", 16));
+ assert(17 == snprintf(buf, 15, "%05x %05x %05x", 0, 0, 0));
+ assert(!memcmp(buf, "00000 00000 00\0?", 16));
+
+ /* all the other stuff */
+ snprintf(buf, sizeof buf, "%010x", 0x1BABE);
+ assert(!strcmp(buf, "000001babe"));
+ snprintf(buf, sizeof buf, "%10x", 0x1BABE);
+ assert(!strcmp(buf, " 1babe"));
+ snprintf(buf, sizeof buf, "%10s", "hello");
+ assert(!strcmp(buf, " hello"));
+
+ snprintf(buf, sizeof buf, "%s%%%s", "ab", "cd");
+ assert(!strcmp(buf, "ab%cd"));
+
+ snprintf(buf, sizeof buf, "%05u %05u", 1234, 56789);
+ assert(!strcmp(buf, "01234 56789"));
+
+ snprintf(buf, sizeof buf, "%u %x", 0, 0);
+ assert(!strcmp(buf, "0 0"));
+}
diff --git a/src/user/app/tests/tests.c b/src/user/app/tests/tests.c
index 4390747..f8abc49 100644
--- a/src/user/app/tests/tests.c
+++ b/src/user/app/tests/tests.c
@@ -237,15 +237,6 @@ static void test_execbuf(void) {
test_fail();
}
-static void test_snprintf(void) {
- char buf[16];
- memset(buf, '?', 16);
- assert(13 == snprintf(buf, 15, "That's 0x%x", 0x1337));
- assert(!memcmp(buf, "That's 0x1337\0??", 16));
- assert(17 == snprintf(buf, 15, "%05x %05x %05x", 0, 0, 0));
- assert(!memcmp(buf, "00000 00000 00\0?", 16));
-}
-
static void test_misc(void) {
assert(_syscall(~0, 0, 0, 0, 0, 0) < 0); /* try making an invalid syscall */
}
@@ -263,7 +254,7 @@ int main(void) {
run_forked(test_semaphore);
run_forked(test_efault);
run_forked(test_execbuf);
- run_forked(test_snprintf);
+ run_forked(test_printf);
run_forked(test_misc);
return 1;
}
diff --git a/src/user/app/tests/tests.h b/src/user/app/tests/tests.h
index 39294eb..5f36fe0 100644
--- a/src/user/app/tests/tests.h
+++ b/src/user/app/tests/tests.h
@@ -1,18 +1,20 @@
#pragma once
#include <camellia/syscalls.h>
#include <stdio.h>
+#include <unistd.h>
void stress_all(void);
void test_all(void);
void test_pipe(void);
+void test_printf(void);
void test_semaphore(void);
#ifdef TEST_MACROS
#define argify(str) str, sizeof(str) - 1
#define test_fail() do { \
- printf("\033[31m" "TEST FAILED: %s:%xh\n" "\033[0m", __func__, __LINE__); \
+ printf("\033[31m" "TEST FAILED: %s():%u\n" "\033[0m", __func__, __LINE__); \
exit(0); \
} while (0)
#define assert(cond) if (!(cond)) test_fail();