218 lines
6.2 KiB
C++
218 lines
6.2 KiB
C++
|
/*
|
||
|
Copyright 2010 Beman Dawes
|
||
|
|
||
|
Copyright 2019-2020 Glen Joseph Fernandes
|
||
|
(glenjofe@gmail.com)
|
||
|
|
||
|
Distributed under the Boost Software License, Version 1.0.
|
||
|
(http://www.boost.org/LICENSE_1_0.txt)
|
||
|
*/
|
||
|
#ifndef BOOST_IO_QUOTED_HPP
|
||
|
#define BOOST_IO_QUOTED_HPP
|
||
|
|
||
|
#include <boost/io/detail/buffer_fill.hpp>
|
||
|
#include <boost/io/detail/ostream_guard.hpp>
|
||
|
#include <boost/io/ios_state.hpp>
|
||
|
|
||
|
namespace boost {
|
||
|
namespace io {
|
||
|
namespace detail {
|
||
|
|
||
|
template<class String, class Char>
|
||
|
struct quoted_proxy {
|
||
|
String string;
|
||
|
Char escape;
|
||
|
Char delim;
|
||
|
};
|
||
|
|
||
|
template<class Char>
|
||
|
struct quoted_state {
|
||
|
const Char* string;
|
||
|
std::size_t size;
|
||
|
std::size_t count;
|
||
|
};
|
||
|
|
||
|
template<class Char>
|
||
|
inline quoted_state<Char>
|
||
|
quoted_start(const Char* string, Char escape, Char delim)
|
||
|
{
|
||
|
const Char* end = string;
|
||
|
std::size_t count = 2;
|
||
|
for (Char ch; (ch = *end) != 0; ++end) {
|
||
|
count += 1 + (ch == escape || ch == delim);
|
||
|
}
|
||
|
quoted_state<Char> state = { string,
|
||
|
static_cast<std::size_t>(end - string), count };
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
template<class Char, class String>
|
||
|
inline quoted_state<Char>
|
||
|
quoted_start(const String* string, Char escape, Char delim)
|
||
|
{
|
||
|
const Char* begin = string->data();
|
||
|
std::size_t size = string->size();
|
||
|
std::size_t count = 2;
|
||
|
for (const Char *it = begin, *end = begin + size; it != end; ++it) {
|
||
|
Char ch = *it;
|
||
|
count += 1 + (ch == escape || ch == delim);
|
||
|
}
|
||
|
quoted_state<Char> state = { begin, size, count };
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
template<class Char, class Traits>
|
||
|
inline bool
|
||
|
quoted_put(std::basic_streambuf<Char, Traits>& buf, const Char* string,
|
||
|
std::size_t size, std::size_t count, Char escape, Char delim)
|
||
|
{
|
||
|
if (buf.sputc(delim) == Traits::eof()) {
|
||
|
return false;
|
||
|
}
|
||
|
if (size == count) {
|
||
|
if (static_cast<std::size_t>(buf.sputn(string, size)) != size) {
|
||
|
return false;
|
||
|
}
|
||
|
} else {
|
||
|
for (const Char* end = string + size; string != end; ++string) {
|
||
|
Char ch = *string;
|
||
|
if ((ch == escape || ch == delim) &&
|
||
|
buf.sputc(escape) == Traits::eof()) {
|
||
|
return false;
|
||
|
}
|
||
|
if (buf.sputc(ch) == Traits::eof()) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return buf.sputc(delim) != Traits::eof();
|
||
|
}
|
||
|
|
||
|
template<class Char, class Traits, class String>
|
||
|
inline std::basic_ostream<Char, Traits>&
|
||
|
quoted_out(std::basic_ostream<Char, Traits>& os, String* string, Char escape,
|
||
|
Char delim)
|
||
|
{
|
||
|
typedef std::basic_ostream<Char, Traits> stream;
|
||
|
ostream_guard<Char, Traits> guard(os);
|
||
|
typename stream::sentry entry(os);
|
||
|
if (entry) {
|
||
|
quoted_state<Char> state = boost::io::detail::quoted_start(string,
|
||
|
escape, delim);
|
||
|
std::basic_streambuf<Char, Traits>& buf = *os.rdbuf();
|
||
|
std::size_t width = static_cast<std::size_t>(os.width());
|
||
|
if (width <= state.count) {
|
||
|
if (!boost::io::detail::quoted_put(buf, state.string, state.size,
|
||
|
state.count, escape, delim)) {
|
||
|
return os;
|
||
|
}
|
||
|
} else if ((os.flags() & stream::adjustfield) == stream::left) {
|
||
|
if (!boost::io::detail::quoted_put(buf, state.string, state.size,
|
||
|
state.count, escape, delim) ||
|
||
|
!boost::io::detail::buffer_fill(buf, os.fill(),
|
||
|
width - state.count)) {
|
||
|
return os;
|
||
|
}
|
||
|
} else if (!boost::io::detail::buffer_fill(buf, os.fill(),
|
||
|
width - state.count) ||
|
||
|
!boost::io::detail::quoted_put(buf, state.string, state.size,
|
||
|
state.count, escape, delim)) {
|
||
|
return os;
|
||
|
}
|
||
|
os.width(0);
|
||
|
}
|
||
|
guard.release();
|
||
|
return os;
|
||
|
}
|
||
|
|
||
|
template<class Char, class Traits>
|
||
|
inline std::basic_ostream<Char, Traits>&
|
||
|
operator<<(std::basic_ostream<Char, Traits>& os,
|
||
|
const quoted_proxy<const Char*, Char>& proxy)
|
||
|
{
|
||
|
return boost::io::detail::quoted_out(os, proxy.string, proxy.escape,
|
||
|
proxy.delim);
|
||
|
}
|
||
|
|
||
|
template <class Char, class Traits, class Alloc>
|
||
|
inline std::basic_ostream<Char, Traits>&
|
||
|
operator<<(std::basic_ostream<Char, Traits>& os,
|
||
|
const quoted_proxy<const std::basic_string<Char, Traits, Alloc>*,
|
||
|
Char>& proxy)
|
||
|
{
|
||
|
return boost::io::detail::quoted_out(os, proxy.string, proxy.escape,
|
||
|
proxy.delim);
|
||
|
}
|
||
|
|
||
|
template<class Char, class Traits, class Alloc>
|
||
|
inline std::basic_ostream<Char, Traits>&
|
||
|
operator<<(std::basic_ostream<Char, Traits>& os,
|
||
|
const quoted_proxy<std::basic_string<Char, Traits, Alloc>*, Char>& proxy)
|
||
|
{
|
||
|
return boost::io::detail::quoted_out(os, proxy.string, proxy.escape,
|
||
|
proxy.delim);
|
||
|
}
|
||
|
|
||
|
template<class Char, class Traits, class Alloc>
|
||
|
inline std::basic_istream<Char, Traits>&
|
||
|
operator>>(std::basic_istream<Char, Traits>& is,
|
||
|
const quoted_proxy<std::basic_string<Char, Traits, Alloc>*, Char>& proxy)
|
||
|
{
|
||
|
Char ch;
|
||
|
if (!(is >> ch)) {
|
||
|
return is;
|
||
|
}
|
||
|
if (ch != proxy.delim) {
|
||
|
is.unget();
|
||
|
return is >> *proxy.string;
|
||
|
}
|
||
|
{
|
||
|
boost::io::ios_flags_saver ifs(is);
|
||
|
std::noskipws(is);
|
||
|
proxy.string->clear();
|
||
|
while ((is >> ch) && ch != proxy.delim) {
|
||
|
if (ch == proxy.escape && !(is >> ch)) {
|
||
|
break;
|
||
|
}
|
||
|
proxy.string->push_back(ch);
|
||
|
}
|
||
|
}
|
||
|
return is;
|
||
|
}
|
||
|
|
||
|
} /* detail */
|
||
|
|
||
|
template<class Char, class Traits, class Alloc>
|
||
|
inline detail::quoted_proxy<const std::basic_string<Char, Traits, Alloc>*,
|
||
|
Char>
|
||
|
quoted(const std::basic_string<Char, Traits, Alloc>& s, Char escape='\\',
|
||
|
Char delim='\"')
|
||
|
{
|
||
|
detail::quoted_proxy<const std::basic_string<Char, Traits, Alloc>*,
|
||
|
Char> proxy = { &s, escape, delim };
|
||
|
return proxy;
|
||
|
}
|
||
|
|
||
|
template<class Char, class Traits, class Alloc>
|
||
|
inline detail::quoted_proxy<std::basic_string<Char, Traits, Alloc>*, Char>
|
||
|
quoted(std::basic_string<Char, Traits, Alloc>& s, Char escape='\\',
|
||
|
Char delim='\"')
|
||
|
{
|
||
|
detail::quoted_proxy<std::basic_string<Char, Traits, Alloc>*,
|
||
|
Char> proxy = { &s, escape, delim };
|
||
|
return proxy;
|
||
|
}
|
||
|
|
||
|
template<class Char>
|
||
|
inline detail::quoted_proxy<const Char*, Char>
|
||
|
quoted(const Char* s, Char escape='\\', Char delim='\"')
|
||
|
{
|
||
|
detail::quoted_proxy<const Char*, Char> proxy = { s, escape, delim };
|
||
|
return proxy;
|
||
|
}
|
||
|
|
||
|
} /* io */
|
||
|
} /* boost */
|
||
|
|
||
|
#endif
|