• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 Copyright 2010 Beman Dawes
3 
4 Copyright 2019-2020 Glen Joseph Fernandes
5 (glenjofe@gmail.com)
6 
7 Distributed under the Boost Software License, Version 1.0.
8 (http://www.boost.org/LICENSE_1_0.txt)
9 */
10 #ifndef BOOST_IO_QUOTED_HPP
11 #define BOOST_IO_QUOTED_HPP
12 
13 #include <boost/io/detail/buffer_fill.hpp>
14 #include <boost/io/detail/ostream_guard.hpp>
15 #include <boost/io/ios_state.hpp>
16 
17 namespace boost {
18 namespace io {
19 namespace detail {
20 
21 template<class String, class Char>
22 struct quoted_proxy {
23     String string;
24     Char escape;
25     Char delim;
26 };
27 
28 template<class Char>
29 struct quoted_state {
30     const Char* string;
31     std::size_t size;
32     std::size_t count;
33 };
34 
35 template<class Char>
36 inline quoted_state<Char>
quoted_start(const Char * string,Char escape,Char delim)37 quoted_start(const Char* string, Char escape, Char delim)
38 {
39     const Char* end = string;
40     std::size_t count = 2;
41     for (Char ch; (ch = *end) != 0; ++end) {
42         count += 1 + (ch == escape || ch == delim);
43     }
44     quoted_state<Char> state = { string,
45         static_cast<std::size_t>(end - string), count };
46     return state;
47 }
48 
49 template<class Char, class String>
50 inline quoted_state<Char>
quoted_start(const String * string,Char escape,Char delim)51 quoted_start(const String* string, Char escape, Char delim)
52 {
53     const Char* begin = string->data();
54     std::size_t size = string->size();
55     std::size_t count = 2;
56     for (const Char *it = begin, *end = begin + size; it != end; ++it) {
57         Char ch = *it;
58         count += 1 + (ch == escape || ch == delim);
59     }
60     quoted_state<Char> state = { begin, size, count };
61     return state;
62 }
63 
64 template<class Char, class Traits>
65 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)66 quoted_put(std::basic_streambuf<Char, Traits>& buf, const Char* string,
67     std::size_t size, std::size_t count, Char escape, Char delim)
68 {
69     if (buf.sputc(delim) == Traits::eof()) {
70         return false;
71     }
72     if (size == count) {
73         if (static_cast<std::size_t>(buf.sputn(string, size)) != size) {
74             return false;
75         }
76     } else {
77         for (const Char* end = string + size; string != end; ++string) {
78             Char ch = *string;
79             if ((ch == escape || ch == delim) &&
80                 buf.sputc(escape) == Traits::eof()) {
81                 return false;
82             }
83             if (buf.sputc(ch) == Traits::eof()) {
84                 return false;
85             }
86         }
87     }
88     return buf.sputc(delim) != Traits::eof();
89 }
90 
91 template<class Char, class Traits, class String>
92 inline std::basic_ostream<Char, Traits>&
quoted_out(std::basic_ostream<Char,Traits> & os,String * string,Char escape,Char delim)93 quoted_out(std::basic_ostream<Char, Traits>& os, String* string, Char escape,
94     Char delim)
95 {
96     typedef std::basic_ostream<Char, Traits> stream;
97     ostream_guard<Char, Traits> guard(os);
98     typename stream::sentry entry(os);
99     if (entry) {
100         quoted_state<Char> state = boost::io::detail::quoted_start(string,
101             escape, delim);
102         std::basic_streambuf<Char, Traits>& buf = *os.rdbuf();
103         std::size_t width = static_cast<std::size_t>(os.width());
104         if (width <= state.count) {
105             if (!boost::io::detail::quoted_put(buf, state.string, state.size,
106                 state.count, escape, delim)) {
107                 return os;
108             }
109         } else if ((os.flags() & stream::adjustfield) == stream::left) {
110             if (!boost::io::detail::quoted_put(buf, state.string, state.size,
111                     state.count, escape, delim) ||
112                 !boost::io::detail::buffer_fill(buf, os.fill(),
113                     width - state.count)) {
114                 return os;
115             }
116         } else if (!boost::io::detail::buffer_fill(buf, os.fill(),
117                 width - state.count) ||
118             !boost::io::detail::quoted_put(buf, state.string, state.size,
119                 state.count, escape, delim)) {
120             return os;
121         }
122         os.width(0);
123     }
124     guard.release();
125     return os;
126 }
127 
128 template<class Char, class Traits>
129 inline std::basic_ostream<Char, Traits>&
operator <<(std::basic_ostream<Char,Traits> & os,const quoted_proxy<const Char *,Char> & proxy)130 operator<<(std::basic_ostream<Char, Traits>& os,
131     const quoted_proxy<const Char*, Char>& proxy)
132 {
133     return boost::io::detail::quoted_out(os, proxy.string, proxy.escape,
134         proxy.delim);
135 }
136 
137 template <class Char, class Traits, class Alloc>
138 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)139 operator<<(std::basic_ostream<Char, Traits>& os,
140     const quoted_proxy<const std::basic_string<Char, Traits, Alloc>*,
141         Char>& proxy)
142 {
143     return boost::io::detail::quoted_out(os, proxy.string, proxy.escape,
144         proxy.delim);
145 }
146 
147 template<class Char, class Traits, class Alloc>
148 inline std::basic_ostream<Char, Traits>&
operator <<(std::basic_ostream<Char,Traits> & os,const quoted_proxy<std::basic_string<Char,Traits,Alloc> *,Char> & proxy)149 operator<<(std::basic_ostream<Char, Traits>& os,
150     const quoted_proxy<std::basic_string<Char, Traits, Alloc>*, Char>& proxy)
151 {
152     return boost::io::detail::quoted_out(os, proxy.string, proxy.escape,
153         proxy.delim);
154 }
155 
156 template<class Char, class Traits, class Alloc>
157 inline std::basic_istream<Char, Traits>&
operator >>(std::basic_istream<Char,Traits> & is,const quoted_proxy<std::basic_string<Char,Traits,Alloc> *,Char> & proxy)158 operator>>(std::basic_istream<Char, Traits>& is,
159     const quoted_proxy<std::basic_string<Char, Traits, Alloc>*, Char>& proxy)
160 {
161     Char ch;
162     if (!(is >> ch)) {
163         return is;
164     }
165     if (ch != proxy.delim) {
166         is.unget();
167         return is >> *proxy.string;
168     }
169     {
170         boost::io::ios_flags_saver ifs(is);
171         std::noskipws(is);
172         proxy.string->clear();
173         while ((is >> ch) && ch != proxy.delim) {
174             if (ch == proxy.escape && !(is >> ch)) {
175                 break;
176             }
177             proxy.string->push_back(ch);
178         }
179     }
180     return is;
181 }
182 
183 } /* detail */
184 
185 template<class Char, class Traits, class Alloc>
186 inline detail::quoted_proxy<const std::basic_string<Char, Traits, Alloc>*,
187     Char>
quoted(const std::basic_string<Char,Traits,Alloc> & s,Char escape='\\\\',Char delim='\\"')188 quoted(const std::basic_string<Char, Traits, Alloc>& s, Char escape='\\',
189     Char delim='\"')
190 {
191     detail::quoted_proxy<const std::basic_string<Char, Traits, Alloc>*,
192         Char> proxy = { &s, escape, delim };
193     return proxy;
194 }
195 
196 template<class Char, class Traits, class Alloc>
197 inline detail::quoted_proxy<std::basic_string<Char, Traits, Alloc>*, Char>
quoted(std::basic_string<Char,Traits,Alloc> & s,Char escape='\\\\',Char delim='\\"')198 quoted(std::basic_string<Char, Traits, Alloc>& s, Char escape='\\',
199     Char delim='\"')
200 {
201     detail::quoted_proxy<std::basic_string<Char, Traits, Alloc>*,
202         Char> proxy = { &s, escape, delim };
203     return proxy;
204 }
205 
206 template<class Char>
207 inline detail::quoted_proxy<const Char*, Char>
quoted(const Char * s,Char escape='\\\\',Char delim='\\"')208 quoted(const Char* s, Char escape='\\', Char delim='\"')
209 {
210     detail::quoted_proxy<const Char*, Char> proxy = { s, escape, delim };
211     return proxy;
212 }
213 
214 } /* io */
215 } /* boost */
216 
217 #endif
218