blob: 602b91258123fbc49216b14bfd2169fcce399873 [file] [log] [blame]
// -*-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