#pragma once #include namespace cruft::format { namespace detail { /// A utility string container that is rendered enclosed in quotes when formatted. template struct escaped_string { /// The string that needs to be escaped string_type source; /// The character marking the beginning and end of the string that needs to be escaped typename string_type::value_type delim; /// The character that escapes other characters typename string_type::value_type escape; constexpr bool escaped_character (char c) const { return delim == c or escape == c; } /// Copies the string characters to an output iterator, inserting /// delim and escape characters as required. template constexpr OutputT copy (OutputT dst) const { *dst++ = delim; for (const auto& c : source) { if (escaped_character (c)) *dst++ = escape; *dst++ = c; } *dst++ = delim; return dst; } }; } /// Returns an object that will be enclosed between delimiters. All /// occurrences of this delimiter will be escaped with the supplied /// character (as will occurences of this escape character). constexpr auto quoted ( std::string_view source, char delim = '"', char escape = '\\' ) { return cruft::format::detail::escaped_string< std::string_view > { .source = source, .delim = delim, .escape = escape, }; } } /////////////////////////////////////////////////////////////////////////////// template struct fmt::formatter> { constexpr format_parse_context::iterator parse (fmt::format_parse_context ctx) const { return ctx.begin(); } constexpr format_context::iterator format( cruft::format::detail::escaped_string const& val, format_context & ctx ) const { return val.copy (ctx.out()); } };