diff --git a/src/crt.cpp b/src/crt.cpp index 57f448a..58ab014 100644 --- a/src/crt.cpp +++ b/src/crt.cpp @@ -155,6 +155,8 @@ namespace bx , fill(' ') , left(false) , upper(false) + , spec(false) + , sign(false) { } @@ -164,6 +166,8 @@ namespace bx char fill; bool left; bool upper; + bool spec; + bool sign; }; static int32_t write(WriterI* _writer, const char* _str, int32_t _len, const Param& _param, Error* _err) @@ -171,6 +175,8 @@ namespace bx int32_t size = 0; int32_t len = (int32_t)strnlen(_str, _len); int32_t padding = _param.width > len ? _param.width - len : 0; + bool sign = _param.sign && len > 1 && _str[0] != '-'; + padding = padding > 0 ? padding - sign : 0; if (!_param.left) { @@ -188,6 +194,11 @@ namespace bx size += write(_writer, toUpper(_str[ii]), _err); } } + else if (sign) + { + size += write(_writer, '+', _err); + size += write(_writer, _str, len, _err); + } else { size += write(_writer, _str, len, _err); @@ -248,7 +259,12 @@ namespace bx } const char* dot = strnchr(str, '.'); - const int32_t precLen = int32_t(dot + 1 + _param.prec - str); + const int32_t precLen = int32_t( + dot + + uint32_min(_param.prec + _param.spec, 1) + + _param.prec + - str + ); if (precLen > len) { for (int32_t ii = len; ii < precLen; ++ii) @@ -301,23 +317,27 @@ namespace bx while (' ' == ch || '-' == ch - || '0' == ch) + || '+' == ch + || '0' == ch + || '#' == ch) { switch (ch) { case '-': param.left = true; break; + case '+': param.sign = true; break; case ' ': param.fill = ' '; break; case '0': param.fill = '0'; break; - } - - if (param.left) - { - param.fill = ' '; + case '#': param.spec = true; break; } read(&reader, ch); } + if (param.left) + { + param.fill = ' '; + } + if ('*' == ch) { read(&reader, ch); diff --git a/tests/vsnprintf_test.cpp b/tests/vsnprintf_test.cpp index eca14bb..72d7109 100644 --- a/tests/vsnprintf_test.cpp +++ b/tests/vsnprintf_test.cpp @@ -83,6 +83,21 @@ TEST_CASE("vsnprintf d/i/o/u/x", "") REQUIRE(test("000000000000EDCB5433", "%020X", -0x1234abcd) ); } +TEST_CASE("vsnprintf modifiers", "") +{ + REQUIRE(test("| 1.000000|", "|%10f|", 1.0f) ); + REQUIRE(test("|1.000000 |", "|%-10f|", 1.0f) ); + REQUIRE(test("|001.000000|", "|%010f|", 1.0f) ); + REQUIRE(test("|0000000001|", "|%010.0f|", 1.0f) ); + REQUIRE(test("|000000001.|", "|%#010.0f|", 1.0f) ); + REQUIRE(test("| 1|", "|%10.0f|", 1.0f) ); + REQUIRE(test("| 1.|", "|%#10.0f|", 1.0f) ); + REQUIRE(test("| +1.|", "|%#+10.0f|", 1.0f) ); + REQUIRE(test("|1 |", "|%-10.0f|", 1.0f) ); + REQUIRE(test("|1. |", "|%#-10.0f|", 1.0f) ); + REQUIRE(test("|+1. |", "|%+#-10.0f|", 1.0f) ); +} + TEST_CASE("vsnprintf p", "") { REQUIRE(test("0xbadc0de", "%p", (void*)0xbadc0de) );