]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/iostreams/include/boost/iostreams/filter/newline.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / iostreams / include / boost / iostreams / filter / newline.hpp
1 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2 // (C) Copyright 2003-2007 Jonathan Turkanis
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
5
6 // See http://www.boost.org/libs/iostreams for documentation.
7
8 // NOTE: I hope to replace the current implementation with a much simpler
9 // one.
10
11 #ifndef BOOST_IOSTREAMS_NEWLINE_FILTER_HPP_INCLUDED
12 #define BOOST_IOSTREAMS_NEWLINE_FILTER_HPP_INCLUDED
13
14 #if defined(_MSC_VER)
15 # pragma once
16 #endif
17
18 #include <boost/assert.hpp>
19 #include <cstdio>
20 #include <stdexcept> // logic_error.
21 #include <boost/config.hpp> // BOOST_STATIC_CONSTANT.
22 #include <boost/iostreams/categories.hpp>
23 #include <boost/iostreams/detail/char_traits.hpp>
24 #include <boost/iostreams/detail/ios.hpp> // BOOST_IOSTREAMS_FAILURE
25 #include <boost/iostreams/read.hpp> // get
26 #include <boost/iostreams/write.hpp> // put
27 #include <boost/iostreams/pipeline.hpp>
28 #include <boost/iostreams/putback.hpp>
29 #include <boost/mpl/bool.hpp>
30 #include <boost/throw_exception.hpp>
31 #include <boost/type_traits/is_convertible.hpp>
32
33 // Must come last.
34 #include <boost/iostreams/detail/config/disable_warnings.hpp>
35
36 #define BOOST_IOSTREAMS_ASSERT_UNREACHABLE(val) \
37 (BOOST_ASSERT("unreachable code" == 0), val) \
38 /**/
39
40 namespace boost { namespace iostreams {
41
42 namespace newline {
43
44 const char CR = 0x0D;
45 const char LF = 0x0A;
46
47 // Flags for configuring newline_filter.
48
49 // Exactly one of the following three flags must be present.
50
51 const int posix = 1; // Use CR as line separator.
52 const int mac = 2; // Use LF as line separator.
53 const int dos = 4; // Use CRLF as line separator.
54 const int mixed = 8; // Mixed line endings.
55 const int final_newline = 16;
56 const int platform_mask = posix | dos | mac;
57
58 } // End namespace newline.
59
60 namespace detail {
61
62 class newline_base {
63 public:
64 bool is_posix() const
65 {
66 return !is_mixed() && (flags_ & newline::posix) != 0;
67 }
68 bool is_dos() const
69 {
70 return !is_mixed() && (flags_ & newline::dos) != 0;
71 }
72 bool is_mac() const
73 {
74 return !is_mixed() && (flags_ & newline::mac) != 0;
75 }
76 bool is_mixed_posix() const { return (flags_ & newline::posix) != 0; }
77 bool is_mixed_dos() const { return (flags_ & newline::dos) != 0; }
78 bool is_mixed_mac() const { return (flags_ & newline::mac) != 0; }
79 bool is_mixed() const
80 {
81 int platform =
82 (flags_ & newline::posix) != 0 ?
83 newline::posix :
84 (flags_ & newline::dos) != 0 ?
85 newline::dos :
86 (flags_ & newline::mac) != 0 ?
87 newline::mac :
88 0;
89 return (flags_ & ~platform & newline::platform_mask) != 0;
90 }
91 bool has_final_newline() const
92 {
93 return (flags_ & newline::final_newline) != 0;
94 }
95 protected:
96 newline_base(int flags) : flags_(flags) { }
97 int flags_;
98 };
99
100 } // End namespace detail.
101
102 class newline_error
103 : public BOOST_IOSTREAMS_FAILURE, public detail::newline_base
104 {
105 private:
106 friend class newline_checker;
107 newline_error(int flags)
108 : BOOST_IOSTREAMS_FAILURE("bad line endings"),
109 detail::newline_base(flags)
110 { }
111 };
112
113 class newline_filter {
114 public:
115 typedef char char_type;
116 struct category
117 : dual_use,
118 filter_tag,
119 closable_tag
120 { };
121
122 explicit newline_filter(int target) : flags_(target)
123 {
124 if ( target != iostreams::newline::posix &&
125 target != iostreams::newline::dos &&
126 target != iostreams::newline::mac )
127 {
128 boost::throw_exception(std::logic_error("bad flags"));
129 }
130 }
131
132 template<typename Source>
133 int get(Source& src)
134 {
135 using iostreams::newline::CR;
136 using iostreams::newline::LF;
137
138 BOOST_ASSERT((flags_ & f_write) == 0);
139 flags_ |= f_read;
140
141 if (flags_ & (f_has_LF | f_has_EOF)) {
142 if (flags_ & f_has_LF)
143 return newline();
144 else
145 return EOF;
146 }
147
148 int c =
149 (flags_ & f_has_CR) == 0 ?
150 iostreams::get(src) :
151 CR;
152
153 if (c == WOULD_BLOCK )
154 return WOULD_BLOCK;
155
156 if (c == CR) {
157 flags_ |= f_has_CR;
158
159 int d;
160 if ((d = iostreams::get(src)) == WOULD_BLOCK)
161 return WOULD_BLOCK;
162
163 if (d == LF) {
164 flags_ &= ~f_has_CR;
165 return newline();
166 }
167
168 if (d == EOF) {
169 flags_ |= f_has_EOF;
170 } else {
171 iostreams::putback(src, d);
172 }
173
174 flags_ &= ~f_has_CR;
175 return newline();
176 }
177
178 if (c == LF)
179 return newline();
180
181 return c;
182 }
183
184 template<typename Sink>
185 bool put(Sink& dest, char c)
186 {
187 using iostreams::newline::CR;
188 using iostreams::newline::LF;
189
190 BOOST_ASSERT((flags_ & f_read) == 0);
191 flags_ |= f_write;
192
193 if ((flags_ & f_has_LF) != 0)
194 return c == LF ?
195 newline(dest) :
196 newline(dest) && this->put(dest, c);
197
198 if (c == LF)
199 return newline(dest);
200
201 if ((flags_ & f_has_CR) != 0)
202 return newline(dest) ?
203 this->put(dest, c) :
204 false;
205
206 if (c == CR) {
207 flags_ |= f_has_CR;
208 return true;
209 }
210
211 return iostreams::put(dest, c);
212 }
213
214 template<typename Sink>
215 void close(Sink& dest, BOOST_IOS::openmode)
216 {
217 if ((flags_ & f_write) != 0 && (flags_ & f_has_CR) != 0)
218 newline_if_sink(dest);
219 flags_ &= ~f_has_LF; // Restore original flags.
220 }
221 private:
222
223 // Returns the appropriate element of a newline sequence.
224 int newline()
225 {
226 using iostreams::newline::CR;
227 using iostreams::newline::LF;
228
229 switch (flags_ & iostreams::newline::platform_mask) {
230 case iostreams::newline::posix:
231 return LF;
232 case iostreams::newline::mac:
233 return CR;
234 case iostreams::newline::dos:
235 if (flags_ & f_has_LF) {
236 flags_ &= ~f_has_LF;
237 return LF;
238 } else {
239 flags_ |= f_has_LF;
240 return CR;
241 }
242 }
243 return BOOST_IOSTREAMS_ASSERT_UNREACHABLE(0);
244 }
245
246 // Writes a newline sequence.
247 template<typename Sink>
248 bool newline(Sink& dest)
249 {
250 using iostreams::newline::CR;
251 using iostreams::newline::LF;
252
253 bool success = false;
254 switch (flags_ & iostreams::newline::platform_mask) {
255 case iostreams::newline::posix:
256 success = boost::iostreams::put(dest, LF);
257 break;
258 case iostreams::newline::mac:
259 success = boost::iostreams::put(dest, CR);
260 break;
261 case iostreams::newline::dos:
262 if ((flags_ & f_has_LF) != 0) {
263 if ((success = boost::iostreams::put(dest, LF)))
264 flags_ &= ~f_has_LF;
265 } else if (boost::iostreams::put(dest, CR)) {
266 if (!(success = boost::iostreams::put(dest, LF)))
267 flags_ |= f_has_LF;
268 }
269 break;
270 }
271 if (success)
272 flags_ &= ~f_has_CR;
273 return success;
274 }
275
276 // Writes a newline sequence if the given device is a Sink.
277 template<typename Device>
278 void newline_if_sink(Device& dest)
279 {
280 typedef typename iostreams::category_of<Device>::type category;
281 newline_if_sink(dest, is_convertible<category, output>());
282 }
283
284 template<typename Sink>
285 void newline_if_sink(Sink& dest, mpl::true_) { newline(dest); }
286
287 template<typename Source>
288 void newline_if_sink(Source&, mpl::false_) { }
289
290 enum flags {
291 f_has_LF = 32768,
292 f_has_CR = f_has_LF << 1,
293 f_has_newline = f_has_CR << 1,
294 f_has_EOF = f_has_newline << 1,
295 f_read = f_has_EOF << 1,
296 f_write = f_read << 1
297 };
298 int flags_;
299 };
300 BOOST_IOSTREAMS_PIPABLE(newline_filter, 0)
301
302 class newline_checker : public detail::newline_base {
303 public:
304 typedef char char_type;
305 struct category
306 : dual_use_filter_tag,
307 closable_tag
308 { };
309 explicit newline_checker(int target = newline::mixed)
310 : detail::newline_base(0), target_(target), open_(false)
311 { }
312 template<typename Source>
313 int get(Source& src)
314 {
315 using newline::CR;
316 using newline::LF;
317
318 if (!open_) {
319 open_ = true;
320 source() = 0;
321 }
322
323 int c;
324 if ((c = iostreams::get(src)) == WOULD_BLOCK)
325 return WOULD_BLOCK;
326
327 // Update source flags.
328 if (c != EOF)
329 source() &= ~f_line_complete;
330 if ((source() & f_has_CR) != 0) {
331 if (c == LF) {
332 source() |= newline::dos;
333 source() |= f_line_complete;
334 } else {
335 source() |= newline::mac;
336 if (c == EOF)
337 source() |= f_line_complete;
338 }
339 } else if (c == LF) {
340 source() |= newline::posix;
341 source() |= f_line_complete;
342 }
343 source() = (source() & ~f_has_CR) | (c == CR ? f_has_CR : 0);
344
345 // Check for errors.
346 if ( c == EOF &&
347 (target_ & newline::final_newline) != 0 &&
348 (source() & f_line_complete) == 0 )
349 {
350 fail();
351 }
352 if ( (target_ & newline::platform_mask) != 0 &&
353 (source() & ~target_ & newline::platform_mask) != 0 )
354 {
355 fail();
356 }
357
358 return c;
359 }
360
361 template<typename Sink>
362 bool put(Sink& dest, int c)
363 {
364 using iostreams::newline::CR;
365 using iostreams::newline::LF;
366
367 if (!open_) {
368 open_ = true;
369 source() = 0;
370 }
371
372 if (!iostreams::put(dest, c))
373 return false;
374
375 // Update source flags.
376 source() &= ~f_line_complete;
377 if ((source() & f_has_CR) != 0) {
378 if (c == LF) {
379 source() |= newline::dos;
380 source() |= f_line_complete;
381 } else {
382 source() |= newline::mac;
383 }
384 } else if (c == LF) {
385 source() |= newline::posix;
386 source() |= f_line_complete;
387 }
388 source() = (source() & ~f_has_CR) | (c == CR ? f_has_CR : 0);
389
390 // Check for errors.
391 if ( (target_ & newline::platform_mask) != 0 &&
392 (source() & ~target_ & newline::platform_mask) != 0 )
393 {
394 fail();
395 }
396
397 return true;
398 }
399
400 template<typename Sink>
401 void close(Sink&, BOOST_IOS::openmode)
402 {
403 using iostreams::newline::final_newline;
404
405 // Update final_newline flag.
406 if ( (source() & f_has_CR) != 0 ||
407 (source() & f_line_complete) != 0 )
408 {
409 source() |= final_newline;
410 }
411
412 // Clear non-sticky flags.
413 source() &= ~(f_has_CR | f_line_complete);
414
415 // Check for errors.
416 if ( (target_ & final_newline) != 0 &&
417 (source() & final_newline) == 0 )
418 {
419 fail();
420 }
421 }
422 private:
423 void fail() { boost::throw_exception(newline_error(source())); }
424 int& source() { return flags_; }
425 int source() const { return flags_; }
426
427 enum flags {
428 f_has_CR = 32768,
429 f_line_complete = f_has_CR << 1
430 };
431
432 int target_; // Represents expected input.
433 bool open_;
434 };
435 BOOST_IOSTREAMS_PIPABLE(newline_checker, 0)
436
437 } } // End namespaces iostreams, boost.
438
439 #include <boost/iostreams/detail/config/enable_warnings.hpp>
440
441 #endif // #ifndef BOOST_IOSTREAMS_NEWLINE_FILTER_HPP_INCLUDED