LibC: fix bugs with printf

This commit is contained in:
Bananymous 2023-05-15 22:02:33 +03:00
parent 632b699475
commit d82c6c2337
2 changed files with 66 additions and 47 deletions

View File

@ -26,17 +26,14 @@ struct format_options_t
}; };
template<BAN::integral T> template<BAN::integral T>
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; int digits = 1;
bool zero_padded = options.zero_padded;
if (options.percision != -1) if (options.percision != -1)
{ {
width = options.percision; digits = options.percision;
zero_padded = false; options.zero_padded = false;
} }
else if (options.width != -1)
width = options.width;
auto digit_char = [](int digit, bool upper) 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); return (upper ? 'A' : 'a') + (digit - 10);
}; };
bool sign = false;
int offset = 0; int offset = 0;
int prefix_length = 0;
char prefix[2] {};
if constexpr(BAN::is_signed_v<T>)
{
prefix_length = 1;
if (value < 0) if (value < 0)
{ {
sign = true; prefix[0] = '-';
buffer[offset++] = digit_char(-(value % base), upper); buffer[offset++] = digit_char(-(value % base), upper);
value = -(value / base); 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;
}
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';
}
}
if (value == 0 && width > 0) while (value || offset < digits)
buffer[offset++] = '0';
while (value)
{ {
buffer[offset++] = digit_char(value % base, upper); buffer[offset++] = digit_char(value % base, upper);
value /= base; value /= base;
} }
int prefix_length = 0; if (options.zero_padded)
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)
{ {
buffer[offset++] = 'x'; int zeroes = options.width - prefix_length;
for (int i = offset; i < zeroes; i++)
buffer[offset++] = '0'; 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++) for (int i = 0; i < offset / 2; i++)
{ {
char temp = buffer[i]; char temp = buffer[i];
@ -273,6 +276,13 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun
format++; format++;
} }
} }
else if (*format == '-')
{
percision = -1;
format++;
while (isdigit(*format))
format++;
}
else if (*format == '*') else if (*format == '*')
{ {
percision = va_arg(arguments, int); percision = va_arg(arguments, int);

View File

@ -476,7 +476,6 @@ int vprintf(const char* format, va_list arguments)
// TODO // TODO
int vscanf(const char*, va_list); int vscanf(const char*, va_list);
// TODO
int vsnprintf(char* buffer, size_t max_size, const char* format, va_list arguments) int vsnprintf(char* buffer, size_t max_size, const char* format, va_list arguments)
{ {
if (buffer == nullptr) 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 }; print_info info { buffer, max_size };
return printf_impl(format, arguments, int ret = printf_impl(format, arguments,
[](int c, void* _info) [](int c, void* _info)
{ {
print_info* info = (print_info*)_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->buffer++;
info->remaining--; info->remaining--;
} }
return 0; return 0;
}, &info }, &info
); );
*info.buffer = '\0';
return ret;
} }
// TODO
int vsprintf(char* buffer, const char* format, va_list arguments) int vsprintf(char* buffer, const char* format, va_list arguments)
{ {
if (buffer == nullptr) if (buffer == nullptr)
return printf_impl(format, arguments, [](int, void*) { return 0; }, 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) [](int c, void* _buffer)
{ {
*(*(char**)_buffer)++ = c; *(*(char**)_buffer)++ = c;
return 0; return 0;
}, &buffer }, &buffer
); );
*buffer = '\0';
return ret;
} }
// TODO // TODO