You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
4.4 KiB
181 lines
4.4 KiB
3 years ago
|
// -*-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
|