218 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| /*
 | |
| 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
 |