From e3b4a3f1665197a5488d07f6950189ca4bb3372d Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 7 Dec 2013 08:12:03 -0800 Subject: [PATCH] Disallow formatting of wchar_t when using a char formatter. --- format.cc | 5 +++-- format.h | 31 ++++++++++++++++++------------- format_test.cc | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/format.cc b/format.cc index d62820b7..b29be007 100644 --- a/format.cc +++ b/format.cc @@ -396,13 +396,14 @@ inline const typename fmt::BasicFormatter::Arg template void fmt::BasicFormatter::CheckSign(const Char *&s, const Arg &arg) { + char sign = *s; if (arg.type > LAST_NUMERIC_TYPE) { ReportError(s, - Format("format specifier '{0}' requires numeric argument") << *s); + Format("format specifier '{}' requires numeric argument") << sign); } if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) { ReportError(s, - Format("format specifier '{0}' requires signed argument") << *s); + Format("format specifier '{}' requires signed argument") << sign); } ++s; } diff --git a/format.h b/format.h index a36284ca..753e25fd 100644 --- a/format.h +++ b/format.h @@ -157,11 +157,16 @@ void Array::append(const T *begin, const T *end) { } template -struct CharTraits; +class CharTraits; template <> -struct CharTraits { - typedef wchar_t UnsupportedType; +class CharTraits { + private: + // Conversion from wchar_t to char is not supported. + static char ConvertWChar(wchar_t); + + public: + typedef const wchar_t *UnsupportedStrType; template static int FormatFloat(char *buffer, std::size_t size, @@ -169,8 +174,11 @@ struct CharTraits { }; template <> -struct CharTraits { - typedef char UnsupportedType; +class CharTraits { + public: + typedef const char *UnsupportedStrType; + + static wchar_t ConvertWChar(wchar_t value) { return value; } template static int FormatFloat(wchar_t *buffer, std::size_t size, @@ -545,7 +553,7 @@ class BasicWriter { // char stream and vice versa. If you want to print a wide string // as a pointer as std::ostream does, cast it to const void*. // Do not implement! - void operator<<(const typename internal::CharTraits::UnsupportedType *); + void operator<<(typename internal::CharTraits::UnsupportedStrType); public: /** @@ -841,12 +849,6 @@ class BasicFormatter { template Arg(T *value); - // This method is private to disallow formatting of wide characters. - // If you want to output a wide character cast it to integer type. - // Do not implement! - // TODO - //Arg(wchar_t value); - public: Type type; union { @@ -884,7 +886,10 @@ class BasicFormatter { Arg(double value) : type(DOUBLE), double_value(value), formatter(0) {} Arg(long double value) : type(LONG_DOUBLE), long_double_value(value), formatter(0) {} - Arg(Char value) : type(CHAR), int_value(value), formatter(0) {} + Arg(char value) : type(CHAR), int_value(value), formatter(0) {} + Arg(wchar_t value) + : type(CHAR), int_value(internal::CharTraits::ConvertWChar(value)), + formatter(0) {} Arg(const Char *value) : type(STRING), formatter(0) { string.value = value; diff --git a/format_test.cc b/format_test.cc index 146a2df6..2597948a 100644 --- a/format_test.cc +++ b/format_test.cc @@ -304,6 +304,13 @@ TEST(WriterTest, WriteChar) { CHECK_WRITE('a'); } +TEST(WriterTest, WriteWideChar) { + // TODO + //CHECK_WRITE_WCHAR(L'a'); + // The following line shouldn't compile: + CHECK_WRITE_CHAR(L'a'); +} + TEST(WriterTest, WriteString) { CHECK_WRITE_CHAR("abc"); // The following line shouldn't compile: @@ -1155,6 +1162,13 @@ TEST(FormatterTest, FormatChar) { CheckUnknownTypes('a', "c", "char"); EXPECT_EQ("a", str(Format("{0}") << 'a')); EXPECT_EQ("z", str(Format("{0:c}") << 'z')); + EXPECT_EQ(L"a", str(Format(L"{0}") << 'a')); +} + +TEST(FormatterTest, FormatWChar) { + EXPECT_EQ(L"a", str(Format(L"{0}") << L'a')); + // This shouldn't compile: + //Format("{0}") << L'a'; } TEST(FormatterTest, FormatCString) {