From 99da70deba62de235454ef1852745610a9c9f741 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Fri, 29 Jul 2022 21:33:15 +0200 Subject: user/libc: properly implement snprintf; the v*printf family --- src/user/app/tests/tests.c | 10 ++++++++ src/user/lib/include/stdio.h | 10 ++++++-- src/user/lib/printf.c | 59 ++++++++++++++++++++++++++++++-------------- 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/src/user/app/tests/tests.c b/src/user/app/tests/tests.c index 1d1156e..4390747 100644 --- a/src/user/app/tests/tests.c +++ b/src/user/app/tests/tests.c @@ -237,6 +237,15 @@ 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 */ } @@ -254,6 +263,7 @@ int main(void) { run_forked(test_semaphore); run_forked(test_efault); run_forked(test_execbuf); + run_forked(test_snprintf); run_forked(test_misc); return 1; } diff --git a/src/user/lib/include/stdio.h b/src/user/lib/include/stdio.h index bf9e09e..fe754da 100644 --- a/src/user/lib/include/stdio.h +++ b/src/user/lib/include/stdio.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include #define EOF (-1) @@ -8,8 +9,13 @@ #define SEEK_CUR 2 #define SEEK_END 3 -int printf(const char *fmt, ...); -int snprintf(char *str, size_t len, const char *fmt, ...); +int printf(const char *restrict fmt, ...); +int fprintf(FILE *restrict f, const char *restrict fmt, ...); +int snprintf(char *restrict str, size_t len, const char *restrict fmt, ...); + +int vprintf(const char *restrict fmt, va_list ap); +int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap); +int vsnprintf(char *restrict str, size_t len, const char *restrict fmt, va_list ap); int _klogf(const char *fmt, ...); // for kernel debugging only diff --git a/src/user/lib/printf.c b/src/user/lib/printf.c index 443c424..53b1140 100644 --- a/src/user/lib/printf.c +++ b/src/user/lib/printf.c @@ -5,47 +5,70 @@ static void backend_file(void *arg, const char *buf, size_t len) { - fwrite(buf, 1, len, (FILE *)arg); + fwrite(buf, 1, len, arg); } -int printf(const char *fmt, ...) { - int ret = 0; - va_list argp; - va_start(argp, fmt); - ret = __printf_internal(fmt, argp, backend_file, (void*)stdout); - va_end(argp); - return ret; +int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) { + return __printf_internal(fmt, ap, backend_file, f); } static void backend_buf(void *arg, const char *buf, size_t len) { char **ptrs = arg; size_t space = ptrs[1] - ptrs[0]; if (len > space) len = space; + memcpy(ptrs[0], buf, len); ptrs[0] += len; + /* ptrs[1] is the last byte of the buffer, it must be 0. + * on overflow: + * ptrs[0] + (ptrs[1] - ptrs[0]) = ptrs[1] */ + *ptrs[0] = '\0'; +} + +int vsnprintf(char *restrict str, size_t len, const char *restrict fmt, va_list ap) { + char *ptrs[2] = {str, str + len - 1}; + return __printf_internal(fmt, ap, backend_buf, &ptrs); +} + + +int printf(const char *restrict fmt, ...) { + int ret; + va_list argp; + va_start(argp, fmt); + ret = vprintf(fmt, argp); + va_end(argp); + return ret; } -int snprintf(char *str, size_t len, const char *fmt, ...) { - int ret = 0; - char *ptrs[2] = {str, str + len}; +int fprintf(FILE *restrict f, const char *restrict fmt, ...) { + int ret; va_list argp; va_start(argp, fmt); - ret = __printf_internal(fmt, argp, backend_buf, &ptrs); + ret = vfprintf(f, fmt, argp); va_end(argp); - if (ptrs[0] < ptrs[1]) *ptrs[0] = '\0'; return ret; } +int snprintf(char *restrict str, size_t len, const char *restrict fmt, ...) { + int ret; + va_list argp; + va_start(argp, fmt); + ret = vsnprintf(str, len, fmt, argp); + va_end(argp); + return ret; +} + +int vprintf(const char *restrict fmt, va_list ap) { + return vfprintf(stdout, fmt, ap); +} + int _klogf(const char *fmt, ...) { - // idiotic. however, this hack won't matter anyways char buf[256]; - int ret = 0; - char *ptrs[2] = {buf, buf + sizeof buf}; + int ret; va_list argp; va_start(argp, fmt); - ret = __printf_internal(fmt, argp, backend_buf, &ptrs); + ret = vsnprintf(buf, sizeof buf, fmt, argp); va_end(argp); - if (ptrs[0] < ptrs[1]) *ptrs[0] = '\0'; _syscall_debug_klog(buf, ret); return ret; } -- cgit v1.2.3