From 25717df15fad75f4d22c64d19f109fe51f5b004b Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Mon, 3 Jun 2024 16:32:33 +0200 Subject: [PATCH] lib/format: support asterisk with format specifier used by some libraries, e.g: printf("%*.s", 5, "Sun"); -> ' Sun' printf("%.*s", 2, "Sun"); -> 'Su' printf("%*.*s", 5, 2, "Sun"); -> ' Su' printf("%.*d", 3, 10); -> ' 10' Issue #5234 --- repos/libports/src/lib/format/console.cc | 48 ++++++++++++++++-------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/repos/libports/src/lib/format/console.cc b/repos/libports/src/lib/format/console.cc index 361c7ca489..3f3cdf9695 100644 --- a/repos/libports/src/lib/format/console.cc +++ b/repos/libports/src/lib/format/console.cc @@ -32,19 +32,26 @@ class Format_command enum Type { INT, UINT, STRING, CHAR, PTR, PERCENT, INVALID }; enum Length { DEFAULT, LONG, SIZE_T, LONG_LONG }; + struct Decimal { int value; bool star; }; + private: /** * Read decimal value from string */ - int decode_decimal(const char *str, int *consumed) + Decimal decode_decimal(const char *str, int *consumed) { + if (str[*consumed] == '*') { + (*consumed) ++; + return { .value = 0, .star = true }; + } + int res = 0; while (1) { char c = str[*consumed]; if (!c || c < '0' || c > '0' + 9) - return res; + return { .value = res, .star = false }; res = (res * 10) + c - '0'; (*consumed)++; @@ -53,15 +60,15 @@ class Format_command public: - Type type = INVALID; /* format argument type */ - Length length = DEFAULT; /* format argument length */ - int padding = 0; /* min number of characters to print */ - int precision = 0; /* max number of characters to print */ - int base = 10; /* base of numeric arguments */ - bool lalign = false; /* align left */ - bool zeropad = false; /* pad with zero instead of space */ - bool uppercase = false; /* use upper case for hex numbers */ - int consumed = 0; /* nb of consumed format string chars */ + Type type = INVALID; /* format argument type */ + Length length = DEFAULT; /* format argument length */ + Decimal padding { }; /* min number of characters to print */ + Decimal precision { }; /* max number of characters to print */ + int base = 10; /* base of numeric arguments */ + bool lalign = false; /* align left */ + bool zeropad = false; /* pad with zero instead of space */ + bool uppercase = false; /* use upper case for hex numbers */ + int consumed = 0; /* nb of consumed format string chars */ /** * Constructor @@ -182,6 +189,13 @@ void Console::vprintf(const char *format, va_list list) Format_command cmd(format); /* read numeric argument from va_list */ + + if (cmd.padding.star) + cmd.padding.value = va_arg(list, int); + + if (cmd.precision.star) + cmd.precision.value = va_arg(list, int); + long long numeric_arg = 0; if (cmd.numeric()) { switch (cmd.length) { @@ -226,7 +240,8 @@ void Console::vprintf(const char *format, va_list list) case Format_command::UINT: if (cmd.length == Format_command::LONG_LONG) { - out_unsigned(numeric_arg, cmd.base, cmd.padding, + out_unsigned(numeric_arg, cmd.base, + cmd.padding.value, [&] (char c) { _out_char(c); }); break; } @@ -235,7 +250,8 @@ void Console::vprintf(const char *format, va_list list) case Format_command::PTR: - out_unsigned((long)numeric_arg, cmd.base, cmd.padding, + out_unsigned((long)numeric_arg, cmd.base, + cmd.padding.value, [&] (char c) { _out_char(c); }); break; @@ -246,12 +262,12 @@ void Console::vprintf(const char *format, va_list list) case Format_command::STRING: - if (cmd.precision) { + if (cmd.precision.value) { int p = 0; char const *a = va_arg(list, const char *); - for (; a && *a && p < cmd.precision; ++a, ++p) + for (; a && *a && p < cmd.precision.value; ++a, ++p) _out_char(*a); - for (; p < cmd.padding; ++p) + for (; p < cmd.padding.value; ++p) _out_char(' '); } else { _out_string(va_arg(list, const char *));