From d82c6c233746d05148d8616be7c1a29310ababe2 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Mon, 15 May 2023 22:02:33 +0300 Subject: [PATCH] LibC: fix bugs with printf --- libc/printf_impl.cpp | 92 ++++++++++++++++++++++++-------------------- libc/stdio.cpp | 21 +++++++--- 2 files changed, 66 insertions(+), 47 deletions(-) diff --git a/libc/printf_impl.cpp b/libc/printf_impl.cpp index 6d19fb7ab..bd059c6a0 100644 --- a/libc/printf_impl.cpp +++ b/libc/printf_impl.cpp @@ -26,17 +26,14 @@ struct format_options_t }; template -static void integer_to_string(char* buffer, T value, int base, bool upper, const format_options_t options) +static void integer_to_string(char* buffer, T value, int base, bool upper, format_options_t options) { - int width = 1; - bool zero_padded = options.zero_padded; + int digits = 1; if (options.percision != -1) { - width = options.percision; - zero_padded = false; + digits = options.percision; + options.zero_padded = false; } - else if (options.width != -1) - width = options.width; auto digit_char = [](int digit, bool upper) { @@ -45,51 +42,57 @@ static void integer_to_string(char* buffer, T value, int base, bool upper, const return (upper ? 'A' : 'a') + (digit - 10); }; - bool sign = false; int offset = 0; - if (value < 0) + + int prefix_length = 0; + char prefix[2] {}; + if constexpr(BAN::is_signed_v) { - sign = true; - buffer[offset++] = digit_char(-(value % base), upper); - value = -(value / base); + prefix_length = 1; + if (value < 0) + { + prefix[0] = '-'; + buffer[offset++] = digit_char(-(value % base), upper); + value = -(value / base); + } + else if (options.show_plus_sign) + prefix[0] = '+'; + else if (options.show_plus_sign_as_space) + prefix[0] = ' '; + else + prefix_length = 0; } - - if (value == 0 && width > 0) - buffer[offset++] = '0'; - - while (value) + else + { + if (options.alternate_form && base == 8) + { + prefix_length = 1; + prefix[0] = '0'; + } + else if (options.alternate_form && base == 16) + { + prefix_length = 2; + prefix[0] = '0'; + prefix[1] = 'x'; + } + } + + while (value || offset < digits) { buffer[offset++] = digit_char(value % base, upper); value /= base; } - int prefix_length = 0; - - if (sign || options.show_plus_sign || options.show_plus_sign_as_space) - prefix_length++; - if (base == 8 && options.alternate_form) - prefix_length++; - if (base == 16 && options.alternate_form) - prefix_length += 2; - - while (offset < width - prefix_length) - buffer[offset++] = (zero_padded ? '0' : ' '); - - if (sign) - buffer[offset++] = '-'; - else if (options.show_plus_sign) - buffer[offset++] = '+'; - else if (options.show_plus_sign_as_space) - buffer[offset++] = ' '; - - if (base == 8 && options.alternate_form) - buffer[offset++] = '0'; - if (base == 16 && options.alternate_form) + if (options.zero_padded) { - buffer[offset++] = 'x'; - buffer[offset++] = '0'; + int zeroes = options.width - prefix_length; + for (int i = offset; i < zeroes; i++) + buffer[offset++] = '0'; } + if (prefix[1]) buffer[offset++] = prefix[1]; + if (prefix[0]) buffer[offset++] = prefix[0]; + for (int i = 0; i < offset / 2; i++) { char temp = buffer[i]; @@ -273,6 +276,13 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun format++; } } + else if (*format == '-') + { + percision = -1; + format++; + while (isdigit(*format)) + format++; + } else if (*format == '*') { percision = va_arg(arguments, int); diff --git a/libc/stdio.cpp b/libc/stdio.cpp index 0cc003579..a425ec43c 100644 --- a/libc/stdio.cpp +++ b/libc/stdio.cpp @@ -476,7 +476,6 @@ int vprintf(const char* format, va_list arguments) // TODO int vscanf(const char*, va_list); -// TODO int vsnprintf(char* buffer, size_t max_size, const char* format, va_list arguments) { if (buffer == nullptr) @@ -489,34 +488,44 @@ int vsnprintf(char* buffer, size_t max_size, const char* format, va_list argumen }; print_info info { buffer, max_size }; - return printf_impl(format, arguments, + int ret = printf_impl(format, arguments, [](int c, void* _info) { print_info* info = (print_info*)_info; - if (info->remaining) + if (info->remaining == 1) { - *info->buffer = (info->remaining == 1 ? '\0' : c); + *info->buffer = '\0'; + info->remaining = 0; + } + else if (info->remaining) + { + *info->buffer = c; info->buffer++; info->remaining--; } return 0; }, &info ); + + *info.buffer = '\0'; + return ret; } -// TODO int vsprintf(char* buffer, const char* format, va_list arguments) { if (buffer == nullptr) return printf_impl(format, arguments, [](int, void*) { return 0; }, nullptr); - return printf_impl(format, arguments, + int ret = printf_impl(format, arguments, [](int c, void* _buffer) { *(*(char**)_buffer)++ = c; return 0; }, &buffer ); + + *buffer = '\0'; + return ret; } // TODO