Implement an escape mechanism.

This commit is contained in:
Victor Zverovich 2012-12-10 15:04:55 -08:00
parent 6caa750a00
commit 31a507034e
3 changed files with 53 additions and 22 deletions

View File

@ -23,9 +23,15 @@ enum { PLUS_FLAG = 1, ZERO_FLAG = 2, HEX_PREFIX_FLAG = 4 };
// FormatError reporting unmatched '{'. The idea is that unmatched '{'
// should override other errors.
void ReportError(const char *s, const std::string &message) {
while (*s && *s != '}')
++s;
throw fmt::FormatError(*s ? message : std::string("unmatched '{' in format"));
for (int num_open_braces = 1; *s; ++s) {
if (*s == '{') {
++num_open_braces;
} else if (*s == '}') {
if (--num_open_braces == 0)
throw fmt::FormatError(message);
}
}
throw fmt::FormatError("unmatched '{' in format");
}
void ReportUnknownType(char code, const char *type) {
@ -225,8 +231,15 @@ void fmt::Formatter::Format() {
const char *start = format_;
const char *s = start;
while (*s) {
if (*s++ != '{') continue;
// TODO: handle escape sequence
char c = *s++;
if (c != '{' && c != '}') continue;
if (*s == c) {
buffer_.insert(buffer_.end(), start, s);
start = ++s;
continue;
}
if (c == '}')
throw FormatError("unmatched '}' in format");
buffer_.insert(buffer_.end(), start, s - 1);
// Parse argument index.

View File

@ -78,7 +78,7 @@ class Formatter {
: type(CUSTOM), custom_value(value), format(f) {}
};
std::vector<Arg> args_;
std::vector<Arg> args_; // Format arguments.
const char *format_; // Format string.
@ -94,7 +94,7 @@ class Formatter {
template <typename T>
void FormatInt(T value, unsigned flags, int width, char type);
// Formats a floating point number.
// Formats a floating point number (double or long double).
template <typename T>
void FormatDouble(
T value, unsigned flags, int width, int precision, char type);
@ -127,6 +127,16 @@ class ArgFormatter {
private:
friend class Formatter;
// This method is private to disallow formatting of arbitrary pointers.
// If you want to output a pointer cast it to void*. Do not implement!
template <typename T>
ArgFormatter &operator<<(const 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!
ArgFormatter &operator<<(wchar_t value);
protected:
mutable Formatter *formatter_;
@ -211,17 +221,6 @@ class ArgFormatter {
return *this;
}
// This method contains a deliberate error to disallow formatting
// arbitrary pointers. If you want to output a pointer cast it to void*.
template <typename T>
ArgFormatter &operator<<(const T *value) {
"Formatting arbitrary pointers is not allowed" = value;
}
// This method is not implemented intentionally to disallow formatting
// wide characters.
ArgFormatter &operator<<(wchar_t value);
template <typename T>
ArgFormatter &operator<<(T *value) {
const T *const_value = value;

View File

@ -66,8 +66,28 @@ class TestString {
}
};
TEST(FormatterTest, Escape) {
EXPECT_EQ("{", str(Format("{{")));
EXPECT_EQ("before {", str(Format("before {{")));
EXPECT_EQ("{ after", str(Format("{{ after")));
EXPECT_EQ("before { after", str(Format("before {{ after")));
EXPECT_EQ("}", str(Format("}}")));
EXPECT_EQ("before }", str(Format("before }}")));
EXPECT_EQ("} after", str(Format("}} after")));
EXPECT_EQ("before } after", str(Format("before }} after")));
EXPECT_EQ("{}", str(Format("{{}}")));
EXPECT_EQ("{42}", str(Format("{{{0}}}") << 42));
}
TEST(FormatterTest, UnmatchedBraces) {
EXPECT_THROW_MSG(Format("{"), FormatError, "unmatched '{' in format");
EXPECT_THROW_MSG(Format("}"), FormatError, "unmatched '}' in format");
EXPECT_THROW_MSG(Format("{0{}"), FormatError, "unmatched '{' in format");
}
TEST(FormatterTest, NoArgs) {
EXPECT_EQ("abracadabra", str(Format("{0}{1}{0}") << "abra" << "cad"));
EXPECT_EQ("test", str(Format("test")));
}
@ -77,7 +97,8 @@ TEST(FormatterTest, ArgsInDifferentPositions) {
EXPECT_EQ("42 after", str(Format("{0} after") << 42));
EXPECT_EQ("before 42 after", str(Format("before {0} after") << 42));
EXPECT_EQ("answer = 42", str(Format("{0} = {1}") << "answer" << 42));
EXPECT_EQ("42 is the answer", str(Format("{1} is the {0}") << "answer" << 42));
EXPECT_EQ("42 is the answer",
str(Format("{1} is the {0}") << "answer" << 42));
EXPECT_EQ("abracadabra", str(Format("{0}{1}{0}") << "abra" << "cad"));
}
@ -424,5 +445,3 @@ TEST(FormatterTest, FormatStringFromSpeedTest) {
<< 1.234 << 42 << 3.13 << "str"
<< reinterpret_cast<void*>(1000) << 'X'));
}
// TODO: more tests