From 20dd43cdfbf7a875626a39f798b2fa01e685feac Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 7 Jun 2023 22:44:11 -0700 Subject: [PATCH] [libc] Add basic sprintf function --- lib/libc/CMakeLists.txt | 1 + lib/libc/include/stdio.h | 10 +++++ lib/libc/src/stdio.cpp | 90 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 lib/libc/include/stdio.h create mode 100644 lib/libc/src/stdio.cpp diff --git a/lib/libc/CMakeLists.txt b/lib/libc/CMakeLists.txt index ab6f0eb..1f85c1f 100644 --- a/lib/libc/CMakeLists.txt +++ b/lib/libc/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(c STATIC src/malloc.cpp + src/stdio.cpp ) target_include_directories(c diff --git a/lib/libc/include/stdio.h b/lib/libc/include/stdio.h new file mode 100644 index 0000000..e5d6904 --- /dev/null +++ b/lib/libc/include/stdio.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +// int fprintf(FILE *stream, const char *format, ...); +int printf(const char *format, ...); +int sprintf(char *str, const char *format, ...); +// int vfprintf(FILE *stream, const char *format, va_list arg); +int vprintf(const char *format, va_list arg); +int vsprintf(char *str, const char *format, va_list arg); diff --git a/lib/libc/src/stdio.cpp b/lib/libc/src/stdio.cpp new file mode 100644 index 0000000..e523299 --- /dev/null +++ b/lib/libc/src/stdio.cpp @@ -0,0 +1,90 @@ +#include "stdio.h" + +#include + +namespace { + +uint32_t num_chars(uint32_t num, uint8_t base) { + uint32_t width = 0; + while (num > 0) { + num /= base; + width++; + } + return width; +} + +int sprint_base(char *str, uint32_t num, uint32_t base) { + uint32_t width = num_chars(num, base); + if (width == 0) { + *str = '0'; + return 1; + } + + uint64_t place = 1; + while (num > 0) { + // FIXME: We seem to have an issue with loading globals. + const char *kHexChars = "0123456789abcdef"; + str[width - place] = kHexChars[num % base]; + place++; + num /= base; + } + + return width; +} + +} // namespace + +int sprintf(char *str, const char *format, ...) { + va_list arg; + va_start(arg, format); + int ret = vsprintf(str, format, arg); + va_end(arg); + return ret; +} + +int vsprintf(char *str, const char *format, va_list arg) { + uint32_t chars = 0; + while (*format != '\0') { + if (*format != '%') { + *str = *format; + chars++; + str++; + format++; + continue; + } + format++; + switch (*format) { + case '%': + *(str++) = *(format++); + chars++; + break; + case 'x': { + int width = sprint_base(str, va_arg(arg, uint32_t), 16); + if (width == -1) { + return -1; + } + chars += width; + str += width; + format++; + break; + } + case 'u': { + int width = sprint_base(str, va_arg(arg, uint32_t), 10); + if (width == -1) { + return -1; + } + chars += width; + str += width; + format++; + break; + } + default: + *(str++) = *(format++); + chars++; + } + } + *str = '\0'; + chars++; + + return chars; +}