/* 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