From 49b8bf997036a083a78ebfe736584c2e51005c75 Mon Sep 17 00:00:00 2001 From: Qwinci <32550582+Qwinci@users.noreply.github.com> Date: Sat, 3 Aug 2024 00:15:09 +0300 Subject: [PATCH] printf: Handle binary format specifiers --- include/frg/formatting.hpp | 6 +++--- include/frg/printf.hpp | 18 ++++++++++-------- tests/tests.cpp | 14 +++++++++++++- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/include/frg/formatting.hpp b/include/frg/formatting.hpp index eb284ff..1f9455e 100644 --- a/include/frg/formatting.hpp +++ b/include/frg/formatting.hpp @@ -94,14 +94,14 @@ enum class format_error { namespace _fmt_basics { // width: Minimum width of the output (padded with spaces by default). - // precision: Minimum number of digits in the ouput (always padded with zeros). + // precision: Minimum number of digits in the output (always padded with zeros). template void print_digits(S &sink, T number, bool negative, int radix, int width, int precision, char padding, bool left_justify, bool group_thousands, bool always_sign, bool plus_becomes_space, bool use_capitals, locale_options locale_opts) { const char *digits = use_capitals ? "0123456789ABCDEF" : "0123456789abcdef"; - char buffer[32]; + char buffer[64]; int k = 0; // number of digits int c = 0; // number of chars since last grouping @@ -137,7 +137,7 @@ namespace _fmt_basics { // print the number in reverse order and determine #digits. do { - FRG_ASSERT(k < 32); // TODO: variable number of digits + FRG_ASSERT(k < 64); // TODO: variable number of digits buffer[k++] = digits[number % radix]; number /= radix; step_grouping(); diff --git a/include/frg/printf.hpp b/include/frg/printf.hpp index 1d82b82..b1e801c 100644 --- a/include/frg/printf.hpp +++ b/include/frg/printf.hpp @@ -335,15 +335,16 @@ void do_printf_ints(S &sink, char t, format_options opts, opts.plus_becomes_space, false, locale_opts); } } break; - case 'o': { + case 'b': + case 'B' : { auto print = [&] (auto number) { if (number && opts.alt_conversion) - sink.append('0'); + sink.append(t == 'b' ? "0b" : "0B"); if(opts.precision && *opts.precision == 0 && !number) { // print nothing in this case }else{ - _fmt_basics::print_int(sink, number, 8, opts.minimum_width, + _fmt_basics::print_int(sink, number, 2, opts.minimum_width, opts.precision ? *opts.precision : 1, opts.fill_zeros ? '0' : ' ', opts.left_justify, false, opts.always_sign, opts.plus_becomes_space, false, locale_opts); @@ -367,15 +368,15 @@ void do_printf_ints(S &sink, char t, format_options opts, print(pop_arg(vsp, &opts)); } } break; - case 'x': { + case 'o': { auto print = [&] (auto number) { if (number && opts.alt_conversion) - sink.append("0x"); + sink.append('0'); if(opts.precision && *opts.precision == 0 && !number) { // print nothing in this case }else{ - _fmt_basics::print_int(sink, number, 16, opts.minimum_width, + _fmt_basics::print_int(sink, number, 8, opts.minimum_width, opts.precision ? *opts.precision : 1, opts.fill_zeros ? '0' : ' ', opts.left_justify, false, opts.always_sign, opts.plus_becomes_space, false, locale_opts); @@ -399,10 +400,11 @@ void do_printf_ints(S &sink, char t, format_options opts, print(pop_arg(vsp, &opts)); } } break; + case 'x': case 'X': { auto print = [&] (auto number) { if (number && opts.alt_conversion) - sink.append("0X"); + sink.append(t == 'x' ? "0x" : "0X"); if(opts.precision && *opts.precision == 0 && !number) { // print nothing in this case @@ -410,7 +412,7 @@ void do_printf_ints(S &sink, char t, format_options opts, _fmt_basics::print_int(sink, number, 16, opts.minimum_width, opts.precision ? *opts.precision : 1, opts.fill_zeros ? '0' : ' ', opts.left_justify, false, opts.always_sign, opts.plus_becomes_space, - true, locale_opts); + t == 'X', locale_opts); } }; diff --git a/tests/tests.cpp b/tests/tests.cpp index be80107..e247891 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -264,7 +264,7 @@ TEST(formatting, printf) { case 'p': case 's': frg::do_printf_chars(*sink_, t, opts, szmod, vsp_); break; - case 'd': case 'i': case 'o': case 'x': case 'X': case 'u': + case 'd': case 'i': case 'o': case 'x': case 'X': case 'b': case 'B': case 'u': frg::do_printf_ints(*sink_, t, opts, szmod, vsp_); break; default: @@ -333,6 +333,8 @@ TEST(formatting, printf) { // Test '#' flag. do_test("0xc", "%#x", 12); do_test("0XC", "%#X", 12); + do_test("0b1100", "%#b", 12); + do_test("0B1100", "%#B", 12); do_test("014", "%#o", 12); do_test("0", "%#x", 0); do_test("0", "%#X", 0); @@ -368,6 +370,16 @@ TEST(formatting, printf) { do_test("C", "%hhX", 12); do_test("C", "%jX", (uintmax_t)12); + // Test 'b' with different size mods to see + // if they work + do_test("1100", "%b", 12); + do_test("1100", "%lb", 12L); + do_test("1100", "%llb", 12LL); + do_test("1100", "%zb", (size_t)12); + do_test("1100", "%hb", 12); + do_test("1100", "%hhb", 12); + do_test("1100", "%jb", (uintmax_t)12); + // Test 'o' with different size mods to see // if they work do_test("14", "%o", 12);