Browse Source

vsnprintf: Added more modifiers.

Branimir Karadžić 8 years ago
parent
commit
d937bda255
2 changed files with 42 additions and 7 deletions
  1. 27 7
      src/crt.cpp
  2. 15 0
      tests/vsnprintf_test.cpp

+ 27 - 7
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);

+ 15 - 0
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) );