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