diff options
author | dzwdz | 2022-08-03 00:23:50 +0200 |
---|---|---|
committer | dzwdz | 2022-08-03 00:23:50 +0200 |
commit | a2a1e4bbfcda8c1314b592c8c940e96e95cb68d4 (patch) | |
tree | 200f63d71eb07b9f9c53ab4f14b58b7b15b2f4bf | |
parent | b4447c1c7bc8639774df6bd74428977908bff61e (diff) |
shared: clean up printf, %u support (amongst other things)
-rw-r--r-- | src/kernel/arch/amd64/boot.c | 3 | ||||
-rw-r--r-- | src/shared/printf.c | 172 | ||||
-rw-r--r-- | src/user/app/iostress/iostress.c | 2 | ||||
-rw-r--r-- | src/user/app/shell/shell.c | 2 | ||||
-rw-r--r-- | src/user/app/testelf/main.c | 4 | ||||
-rw-r--r-- | src/user/app/tests/printf.c | 32 | ||||
-rw-r--r-- | src/user/app/tests/tests.c | 11 | ||||
-rw-r--r-- | src/user/app/tests/tests.h | 4 |
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(); |