Compare commits

..

No commits in common. "16e00bada0feb77fa95e3c8d596ab8131cac633c" and "cf3b2176f097d84a31051f33df405ee677bf84d8" have entirely different histories.

7 changed files with 79 additions and 248 deletions

View File

@ -26,8 +26,14 @@ static void log_serial(LogLevel level, const char* format, va_list origin)
Serial::printf("%4zu.%.3zu ", Timer::ticks(), Timer::ticks_ms() - (Timer::ticks() * 1000)); Serial::printf("%4zu.%.3zu ", Timer::ticks(), Timer::ticks_ms() - (Timer::ticks() * 1000));
pure_cstyle_format( cstyle_format(
format, [](char c, void*) { Serial::putchar((u8)c); }, nullptr, ap); format,
[](char c, void*) -> Result<void> {
Serial::putchar((u8)c);
return {};
},
nullptr, ap)
.expect_value("Sanity check failed in log_serial: Should never fail");
Serial::putchar('\n'); Serial::putchar('\n');
@ -50,8 +56,14 @@ static void log_text_console(LogLevel level, const char* format, va_list origin)
else else
TextConsole::set_foreground(WHITE); TextConsole::set_foreground(WHITE);
pure_cstyle_format( cstyle_format(
format, [](char c, void*) { TextConsole::putchar(c); }, nullptr, ap); format,
[](char c, void*) -> Result<void> {
TextConsole::putchar(c);
return {};
},
nullptr, ap)
.expect_value("Sanity check failed in log_text_console: Should never fail");
TextConsole::putchar('\n'); TextConsole::putchar('\n');

View File

@ -25,8 +25,14 @@ namespace Serial
{ {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
auto rc = pure_cstyle_format( auto rc = cstyle_format(
format, [](char c, void*) { putchar((u8)c); }, nullptr, ap); format,
[](char c, void*) -> Result<void> {
putchar((u8)c);
return {};
},
nullptr, ap)
.expect_value("Sanity check failed in Serial::printf: Should never fail");
va_end(ap); va_end(ap);
return rc; return rc;
} }

View File

@ -161,8 +161,14 @@ namespace TextConsole
{ {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
auto rc = pure_cstyle_format( auto rc = cstyle_format(
format, [](char c, void*) { putchar(c); }, nullptr, ap); format,
[](char c, void*) -> Result<void> {
putchar(c);
return {};
},
nullptr, ap)
.expect_value("Sanity check failed in TextConsole::printf: Should never fail");
va_end(ap); va_end(ap);
return rc; return rc;
} }

View File

@ -4,16 +4,7 @@
#include <stdarg.h> #include <stdarg.h>
typedef Result<void> (*callback_t)(char, void*); typedef Result<void> (*callback_t)(char, void*);
typedef void (*pure_callback_t)(char, void*);
// Used to format anything that can fail (writing to C FILEs, etc...)
Result<usize> cstyle_format(const char* format, callback_t callback, void* arg, va_list ap); Result<usize> cstyle_format(const char* format, callback_t callback, void* arg, va_list ap);
// Used to format anything that cannot fail (formatting to a string, writing to the serial port (kernel-only))
usize pure_cstyle_format(const char* format, pure_callback_t callback, void* arg, va_list ap);
// Convenience function which outputs into a fixed-size buffer (not unlike vsnprintf)
usize vstring_format(char* buf, usize max, const char* format, va_list ap); usize vstring_format(char* buf, usize max, const char* format, va_list ap);
// Convenience function which outputs into a fixed-size buffer (not unlike snprintf)
usize string_format(char* buf, usize max, const char* format, ...); usize string_format(char* buf, usize max, const char* format, ...);

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <luna/Types.h> #include <luna/Types.h>
usize scan_unsigned_integer(const char** str); usize _atou(const char** str);
isize scan_signed_integer(const char** str); isize _atos(const char** str);
usize parse_unsigned_integer(const char* str, const char** endptr, int base); usize _strtou(const char* str, const char** endptr, int base);
isize parse_signed_integer(const char* str, const char** endptr, int base); isize _strtoi(const char* str, const char** endptr, int base);

View File

@ -26,13 +26,6 @@ struct format_state
void* arg; void* arg;
}; };
struct pure_format_state
{
usize count;
pure_callback_t callback;
void* arg;
};
struct conv_state struct conv_state
{ {
flags_t flags; flags_t flags;
@ -46,12 +39,6 @@ static Result<void> format_putchar(char c, format_state& state)
return state.callback(c, state.arg); return state.callback(c, state.arg);
} }
static void pure_format_putchar(char c, pure_format_state& state)
{
state.count++;
return state.callback(c, state.arg);
}
static Result<void> format_puts(const char* s, format_state& state) static Result<void> format_puts(const char* s, format_state& state)
{ {
while (*s) while (*s)
@ -63,15 +50,6 @@ static Result<void> format_puts(const char* s, format_state& state)
return {}; return {};
} }
static void pure_format_puts(const char* s, pure_format_state& state)
{
while (*s)
{
pure_format_putchar(*s, state);
s++;
}
}
static Result<void> start_pad(const conv_state& vstate, format_state& state, usize start) static Result<void> start_pad(const conv_state& vstate, format_state& state, usize start)
{ {
if (!(vstate.flags & FLAG_LEFT_ALIGN)) if (!(vstate.flags & FLAG_LEFT_ALIGN))
@ -82,14 +60,6 @@ static Result<void> start_pad(const conv_state& vstate, format_state& state, usi
return {}; return {};
} }
static void pure_start_pad(const conv_state& vstate, pure_format_state& state, usize start)
{
if (!(vstate.flags & FLAG_LEFT_ALIGN))
{
while (start++ < vstate.width) pure_format_putchar(' ', state);
}
}
static Result<void> end_pad(const conv_state& vstate, format_state& state, usize start) static Result<void> end_pad(const conv_state& vstate, format_state& state, usize start)
{ {
if (vstate.flags & FLAG_LEFT_ALIGN) if (vstate.flags & FLAG_LEFT_ALIGN)
@ -100,14 +70,6 @@ static Result<void> end_pad(const conv_state& vstate, format_state& state, usize
return {}; return {};
} }
static void pure_end_pad(const conv_state& vstate, pure_format_state& state, usize start)
{
if (vstate.flags & FLAG_LEFT_ALIGN)
{
while (start++ < vstate.width) pure_format_putchar(' ', state);
}
}
static flags_t parse_flags(const char** format) static flags_t parse_flags(const char** format)
{ {
flags_t result = 0; flags_t result = 0;
@ -145,7 +107,7 @@ static usize parse_width(const char** format, flags_t& flags, va_list ap)
{ {
usize result = 0; usize result = 0;
if (_isdigit(**format)) result = scan_unsigned_integer(format); if (_isdigit(**format)) result = _atou(format);
else if (**format == '*') else if (**format == '*')
{ {
const int width = va_arg(ap, int); const int width = va_arg(ap, int);
@ -170,7 +132,7 @@ static usize parse_precision(const char** format, flags_t& flags, va_list ap)
flags |= FLAG_USE_PRECISION; flags |= FLAG_USE_PRECISION;
if (_isdigit(**format)) result = scan_unsigned_integer(format); if (_isdigit(**format)) result = _atou(format);
else if (**format == '*') else if (**format == '*')
{ {
const int precision = va_arg(ap, int); const int precision = va_arg(ap, int);
@ -241,34 +203,7 @@ static usize to_string(usize value, usize base, char* buf, usize max, bool upper
return i; return i;
} }
static Result<void> output_integer_data(conv_state& vstate, format_state& state, char* buf, usize len) static Result<void> output_integer(char specifier, conv_state& vstate, format_state& state, usize value, bool negative)
{
if (!(vstate.flags & FLAG_ZERO_PAD)) TRY(start_pad(vstate, state, len));
usize i = len;
while (i--) TRY(format_putchar(buf[i], state));
TRY(end_pad(vstate, state, len));
return {};
}
static void output_pure_integer_data(conv_state& vstate, pure_format_state& state, char* buf, usize len)
{
if (!(vstate.flags & FLAG_ZERO_PAD)) pure_start_pad(vstate, state, len);
usize i = len;
while (i--) pure_format_putchar(buf[i], state);
pure_end_pad(vstate, state, len);
}
template <typename ReturnType, typename FormatStateType>
static ReturnType output_integer_generic(char specifier, conv_state& vstate, FormatStateType& state, usize value,
bool negative,
ReturnType (*output_data)(conv_state&, FormatStateType&, char*, usize))
{ {
usize base = 10; usize base = 10;
bool uppercase = false; bool uppercase = false;
@ -325,27 +260,18 @@ static ReturnType output_integer_generic(char specifier, conv_state& vstate, For
buf[buflen++] = ' '; buf[buflen++] = ' ';
} }
return output_data(vstate, state, buf, buflen); if (!(vstate.flags & FLAG_ZERO_PAD)) TRY(start_pad(vstate, state, buflen));
usize i = buflen;
while (i--) TRY(format_putchar(buf[i], state));
TRY(end_pad(vstate, state, buflen));
return {};
} }
static Result<void> output_integer(char specifier, conv_state& vstate, format_state& state, usize value, bool negative) static Result<void> va_output_integer(char specifier, conv_state& vstate, format_state& state, va_list ap)
{
return output_integer_generic<Result<void>, format_state>(specifier, vstate, state, value, negative,
output_integer_data);
}
static void pure_output_integer(char specifier, conv_state& vstate, pure_format_state& state, usize value,
bool negative)
{
return output_integer_generic<void, pure_format_state>(specifier, vstate, state, value, negative,
output_pure_integer_data);
}
template <typename ReturnType, typename FormatStateType>
static ReturnType va_generic_output_integer(char specifier, conv_state& vstate, FormatStateType& state,
ReturnType (*integer_output)(char, conv_state&, FormatStateType&, usize,
bool),
va_list ap)
{ {
bool is_signed = false; bool is_signed = false;
bool negative = false; bool negative = false;
@ -364,12 +290,12 @@ static ReturnType va_generic_output_integer(char specifier, conv_state& vstate,
v = -v; v = -v;
negative = true; negative = true;
} }
return integer_output(specifier, vstate, state, (unsigned char)v, negative); return output_integer(specifier, vstate, state, (unsigned char)v, negative);
} }
else else
{ {
const unsigned char v = (unsigned char)va_arg(ap, unsigned int); const unsigned char v = (unsigned char)va_arg(ap, unsigned int);
return integer_output(specifier, vstate, state, v, false); return output_integer(specifier, vstate, state, v, false);
} }
} }
else if (vstate.flags & FLAG_SHORT) else if (vstate.flags & FLAG_SHORT)
@ -382,12 +308,12 @@ static ReturnType va_generic_output_integer(char specifier, conv_state& vstate,
v = -v; v = -v;
negative = true; negative = true;
} }
return integer_output(specifier, vstate, state, (unsigned short)v, negative); return output_integer(specifier, vstate, state, (unsigned short)v, negative);
} }
else else
{ {
const unsigned short v = (unsigned short)va_arg(ap, unsigned int); const unsigned short v = (unsigned short)va_arg(ap, unsigned int);
return integer_output(specifier, vstate, state, v, false); return output_integer(specifier, vstate, state, v, false);
} }
} }
else if (vstate.flags & FLAG_LONG_LONG) else if (vstate.flags & FLAG_LONG_LONG)
@ -400,12 +326,12 @@ static ReturnType va_generic_output_integer(char specifier, conv_state& vstate,
v = -v; v = -v;
negative = true; negative = true;
} }
return integer_output(specifier, vstate, state, (unsigned long long)v, negative); return output_integer(specifier, vstate, state, (unsigned long long)v, negative);
} }
else else
{ {
const unsigned long long v = va_arg(ap, unsigned long long); const unsigned long long v = va_arg(ap, unsigned long long);
return integer_output(specifier, vstate, state, v, false); return output_integer(specifier, vstate, state, v, false);
} }
} }
else if (vstate.flags & FLAG_LONG) else if (vstate.flags & FLAG_LONG)
@ -418,12 +344,12 @@ static ReturnType va_generic_output_integer(char specifier, conv_state& vstate,
v = -v; v = -v;
negative = true; negative = true;
} }
return integer_output(specifier, vstate, state, (unsigned long)v, negative); return output_integer(specifier, vstate, state, (unsigned long)v, negative);
} }
else else
{ {
const unsigned long v = va_arg(ap, unsigned long); const unsigned long v = va_arg(ap, unsigned long);
return integer_output(specifier, vstate, state, v, false); return output_integer(specifier, vstate, state, v, false);
} }
} }
else else
@ -436,26 +362,16 @@ static ReturnType va_generic_output_integer(char specifier, conv_state& vstate,
v = -v; v = -v;
negative = true; negative = true;
} }
return integer_output(specifier, vstate, state, (unsigned int)v, negative); return output_integer(specifier, vstate, state, (unsigned int)v, negative);
} }
else else
{ {
const unsigned int v = va_arg(ap, unsigned int); const unsigned int v = va_arg(ap, unsigned int);
return integer_output(specifier, vstate, state, v, false); return output_integer(specifier, vstate, state, v, false);
} }
} }
} }
static Result<void> va_output_integer(char specifier, conv_state& vstate, format_state& state, va_list ap)
{
return va_generic_output_integer<Result<void>, format_state>(specifier, vstate, state, output_integer, ap);
}
static void va_pure_output_integer(char specifier, conv_state& vstate, pure_format_state& state, va_list ap)
{
return va_generic_output_integer<void, pure_format_state>(specifier, vstate, state, pure_output_integer, ap);
}
Result<usize> cstyle_format(const char* format, callback_t callback, void* arg, va_list ap) Result<usize> cstyle_format(const char* format, callback_t callback, void* arg, va_list ap)
{ {
format_state state; format_state state;
@ -556,106 +472,6 @@ Result<usize> cstyle_format(const char* format, callback_t callback, void* arg,
return state.count; return state.count;
} }
usize pure_cstyle_format(const char* format, pure_callback_t callback, void* arg, va_list ap)
{
pure_format_state state;
state.callback = callback;
state.arg = arg;
state.count = 0;
while (*format)
{
if (*format != '%')
{
pure_format_putchar(*format, state);
format++;
continue;
}
format++;
if (*format == '%')
{
pure_format_putchar('%', state);
continue;
}
// %[flags][width][.precision][length]conversion
flags_t flags = parse_flags(&format);
const usize width = parse_width(&format, flags, ap);
usize precision = parse_precision(&format, flags, ap);
parse_length(&format, flags);
conv_state vstate = {flags, width, precision};
const char specifier = *format;
format++;
if (is_integer_format_specifier(specifier))
{
va_pure_output_integer(specifier, vstate, state, ap);
continue;
}
else if (specifier == 'p')
{
const void* ptr = va_arg(ap, void*);
if (ptr == nullptr)
{
pure_start_pad(vstate, state, 5);
pure_format_puts("(nil)", state);
pure_end_pad(vstate, state, 5);
continue;
}
vstate.width = (sizeof(void*) * 2) + 2;
vstate.flags |= (FLAG_ZERO_PAD | FLAG_ALTERNATE);
pure_output_integer('p', vstate, state, (usize)ptr, false);
continue;
}
else if (specifier == 'c')
{
const char c = (char)va_arg(ap, int);
pure_start_pad(vstate, state, 1);
pure_format_putchar(c, state);
pure_end_pad(vstate, state, 1);
continue;
}
else if (specifier == 's')
{
const char* str = va_arg(ap, const char*);
if (str == nullptr)
{
pure_start_pad(vstate, state, 6);
pure_format_puts("(null)", state);
pure_end_pad(vstate, state, 6);
continue;
}
else
{
usize len = strlen(str);
bool use_precision = (flags & FLAG_USE_PRECISION);
if (use_precision && len > precision) len = precision;
pure_start_pad(vstate, state, len);
while (*str && (!use_precision || precision))
{
pure_format_putchar(*str, state);
precision--;
str++;
}
pure_end_pad(vstate, state, len);
continue;
}
}
else { continue; }
}
return state.count;
}
struct StringFormatInfo struct StringFormatInfo
{ {
char* buffer; char* buffer;
@ -666,17 +482,18 @@ usize vstring_format(char* buf, usize max, const char* format, va_list ap)
{ {
StringFormatInfo info = {.buffer = buf, .remaining = max - 1}; StringFormatInfo info = {.buffer = buf, .remaining = max - 1};
usize result = pure_cstyle_format( usize result = cstyle_format(
format, format,
[](char c, void* arg) { [](char c, void* arg) -> Result<void> {
StringFormatInfo* info_arg = (StringFormatInfo*)arg; StringFormatInfo* info_arg = (StringFormatInfo*)arg;
if (!info_arg->remaining) return; if (!info_arg->remaining) return {};
*(info_arg->buffer) = c; *(info_arg->buffer) = c;
info_arg->buffer++; info_arg->buffer++;
info_arg->remaining--; info_arg->remaining--;
return; return {};
}, },
&info, ap); &info, ap)
.expect_value("Sanity check failed in vstring_format: Should never fail");
*(info.buffer) = 0; *(info.buffer) = 0;

View File

@ -16,7 +16,7 @@ static bool is_valid_digit_for_base(int base, char c)
return true; return true;
} }
usize parse_unsigned_integer(const char* str, const char** endptr, int base) usize _strtou(const char* str, const char** endptr, int base)
{ {
usize val = 0; usize val = 0;
@ -47,7 +47,7 @@ usize parse_unsigned_integer(const char* str, const char** endptr, int base)
return val; return val;
} }
isize parse_signed_integer(const char* str, const char** endptr, int base) isize _strtoi(const char* str, const char** endptr, int base)
{ {
bool negative = false; bool negative = false;
@ -59,19 +59,18 @@ isize parse_signed_integer(const char* str, const char** endptr, int base)
str++; str++;
} }
usize rc = parse_unsigned_integer( usize rc = _strtou(str, endptr,
str, endptr, base); // FIXME: Check for overflow (the unsigned usize value might not fit into a signed isize)
base); // FIXME: Check for overflow (the unsigned usize value might not fit into a signed isize)
return negative ? -(isize)rc : (isize)rc; return negative ? -(isize)rc : (isize)rc;
} }
usize scan_unsigned_integer(const char** str) usize _atou(const char** str)
{ {
return parse_unsigned_integer(*str, str, 10); return _strtou(*str, str, 10);
} }
isize scan_signed_integer(const char** str) isize _atos(const char** str)
{ {
return parse_signed_integer(*str, str, 10); return _strtoi(*str, str, 10);
} }