| // -*-c++-*- | |
| // vim: set ft=cpp: | |
| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file Copyright.txt or https://cmake.org/licensing for details. */ | |
| #pragma once | |
| #include <iomanip> // IWYU pragma: export | |
| #if __cplusplus < 201402L || defined(_MSVC_LANG) && _MSVC_LANG < 201402L | |
| # include <ios> | |
| # include <iostream> | |
| # include <sstream> | |
| # include <string> | |
| # include <type_traits> | |
| #endif | |
| #if __cplusplus < 201703L || defined(_MSVC_LANG) && _MSVC_LANG < 201703L | |
| # include <cm/string_view> | |
| #endif | |
| namespace cm { | |
| #if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L | |
| using std::quoted; | |
| # if __cplusplus < 201703L || defined(_MSVC_LANG) && _MSVC_LANG < 201703L | |
| inline auto quoted(cm::string_view str, char delim = '"', char escape = '\\') | |
| { | |
| return std::quoted(static_cast<std::string>(str), delim, escape); | |
| } | |
| # endif | |
| #else | |
| namespace internals { | |
| // Struct for delimited strings. | |
| template <typename String, typename Char> | |
| struct quoted_string | |
| { | |
| static_assert(std::is_reference<String>::value || | |
| std::is_pointer<String>::value, | |
| "String type must be pointer or reference"); | |
| quoted_string(String str, Char del, Char esc) | |
| : string_(str) | |
| , delim_{ del } | |
| , escape_{ esc } | |
| { | |
| } | |
| quoted_string& operator=(quoted_string&) = delete; | |
| String string_; | |
| Char delim_; | |
| Char escape_; | |
| }; | |
| template <> | |
| struct quoted_string<cm::string_view, char> | |
| { | |
| quoted_string(cm::string_view str, char del, char esc) | |
| : string_(str) | |
| , delim_{ del } | |
| , escape_{ esc } | |
| { | |
| } | |
| quoted_string& operator=(quoted_string&) = delete; | |
| cm::string_view string_; | |
| char delim_; | |
| char escape_; | |
| }; | |
| template <typename Char, typename Traits> | |
| std::basic_ostream<Char, Traits>& operator<<( | |
| std::basic_ostream<Char, Traits>& os, | |
| const quoted_string<const Char*, Char>& str) | |
| { | |
| std::basic_ostringstream<Char, Traits> ostr; | |
| ostr << str.delim_; | |
| for (const Char* c = str.string_; *c; ++c) { | |
| if (*c == str.delim_ || *c == str.escape_) | |
| ostr << str.escape_; | |
| ostr << *c; | |
| } | |
| ostr << str.delim_; | |
| return os << ostr.str(); | |
| } | |
| template <typename Char, typename Traits, typename String> | |
| std::basic_ostream<Char, Traits>& operator<<( | |
| std::basic_ostream<Char, Traits>& os, const quoted_string<String, Char>& str) | |
| { | |
| std::basic_ostringstream<Char, Traits> ostr; | |
| ostr << str.delim_; | |
| for (auto c : str.string_) { | |
| if (c == str.delim_ || c == str.escape_) | |
| ostr << str.escape_; | |
| ostr << c; | |
| } | |
| ostr << str.delim_; | |
| return os << ostr.str(); | |
| } | |
| template <typename Char, typename Traits, typename Alloc> | |
| std::basic_istream<Char, Traits>& operator>>( | |
| std::basic_istream<Char, Traits>& is, | |
| const quoted_string<std::basic_string<Char, Traits, Alloc>&, Char>& str) | |
| { | |
| Char c; | |
| is >> c; | |
| if (!is.good()) | |
| return is; | |
| if (c != str.delim_) { | |
| is.unget(); | |
| is >> str.string_; | |
| return is; | |
| } | |
| str.string_.clear(); | |
| std::ios_base::fmtflags flags = | |
| is.flags(is.flags() & ~std::ios_base::skipws); | |
| do { | |
| is >> c; | |
| if (!is.good()) | |
| break; | |
| if (c == str.escape_) { | |
| is >> c; | |
| if (!is.good()) | |
| break; | |
| } else if (c == str.delim_) | |
| break; | |
| str.string_ += c; | |
| } while (true); | |
| is.setf(flags); | |
| return is; | |
| } | |
| } | |
| template <typename Char> | |
| inline internals::quoted_string<const Char*, Char> quoted( | |
| const Char* str, Char delim = Char('"'), Char escape = Char('\\')) | |
| { | |
| return internals::quoted_string<const Char*, Char>(str, delim, escape); | |
| } | |
| template <typename Char, typename Traits, typename Alloc> | |
| inline internals::quoted_string<const std::basic_string<Char, Traits, Alloc>&, | |
| Char> | |
| quoted(const std::basic_string<Char, Traits, Alloc>& str, | |
| Char delim = Char('"'), Char escape = Char('\\')) | |
| { | |
| return internals::quoted_string< | |
| const std::basic_string<Char, Traits, Alloc>&, Char>(str, delim, escape); | |
| } | |
| template <typename Char, typename Traits, typename Alloc> | |
| inline internals::quoted_string<std::basic_string<Char, Traits, Alloc>&, Char> | |
| quoted(std::basic_string<Char, Traits, Alloc>& str, Char delim = Char('"'), | |
| Char escape = Char('\\')) | |
| { | |
| return internals::quoted_string<std::basic_string<Char, Traits, Alloc>&, | |
| Char>(str, delim, escape); | |
| } | |
| inline internals::quoted_string<cm::string_view, char> quoted( | |
| cm::string_view str, char delim = '"', char escape = '\\') | |
| { | |
| return internals::quoted_string<cm::string_view, char>(str, delim, escape); | |
| } | |
| #endif | |
| } // namespace cm |