PageRenderTime 48ms CodeModel.GetById 16ms app.highlight 27ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/iostreams/filter/newline.hpp

http://hadesmem.googlecode.com/
C++ Header | 442 lines | 352 code | 69 blank | 21 comment | 106 complexity | bf500d3266192679c511606020794e25 MD5 | raw file
  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) && (_MSC_VER >= 1020)
 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
 40namespace boost { namespace iostreams {
 41
 42namespace newline {
 43
 44const char CR                   = 0x0D;
 45const char LF                   = 0x0A;
 46
 47    // Flags for configuring newline_filter.
 48
 49// Exactly one of the following three flags must be present.
 50
 51const int posix             = 1;    // Use CR as line separator.
 52const int mac               = 2;    // Use LF as line separator.
 53const int dos               = 4;    // Use CRLF as line separator.
 54const int mixed             = 8;    // Mixed line endings.
 55const int final_newline     = 16;
 56const int platform_mask     = posix | dos | mac;
 57
 58} // End namespace newline.
 59
 60namespace detail {
 61
 62class newline_base {
 63public:
 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    }
 95protected:
 96    newline_base(int flags) : flags_(flags) { }
 97    int flags_;
 98};
 99
100} // End namespace detail.
101
102class newline_error
103    : public BOOST_IOSTREAMS_FAILURE, public detail::newline_base
104{
105private:
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
113class newline_filter {
114public:
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        typedef typename iostreams::category_of<Sink>::type category;
218        if ((flags_ & f_write) != 0 && (flags_ & f_has_CR) != 0)
219            newline_if_sink(dest);
220        flags_ &= ~f_has_LF; // Restore original flags.
221    }
222private:
223
224    // Returns the appropriate element of a newline sequence.
225    int newline()
226    {
227        using iostreams::newline::CR;
228        using iostreams::newline::LF;
229
230        switch (flags_ & iostreams::newline::platform_mask) {
231        case iostreams::newline::posix:
232            return LF;
233        case iostreams::newline::mac:
234            return CR;
235        case iostreams::newline::dos:
236            if (flags_ & f_has_LF) {
237                flags_ &= ~f_has_LF;
238                return LF;
239            } else {
240                flags_ |= f_has_LF;
241                return CR;
242            }
243        }
244        return BOOST_IOSTREAMS_ASSERT_UNREACHABLE(0);
245    }
246
247    // Writes a newline sequence.
248    template<typename Sink>
249    bool newline(Sink& dest)
250    {
251        using iostreams::newline::CR;
252        using iostreams::newline::LF;
253
254        bool success = false;
255        switch (flags_ & iostreams::newline::platform_mask) {
256        case iostreams::newline::posix:
257            success = boost::iostreams::put(dest, LF);
258            break;
259        case iostreams::newline::mac:
260            success = boost::iostreams::put(dest, CR);
261            break;
262        case iostreams::newline::dos:
263            if ((flags_ & f_has_LF) != 0) {
264                if ((success = boost::iostreams::put(dest, LF)))
265                    flags_ &= ~f_has_LF;
266            } else if (boost::iostreams::put(dest, CR)) {
267                if (!(success = boost::iostreams::put(dest, LF)))
268                    flags_ |= f_has_LF;
269            }
270            break;
271        }
272        if (success)
273            flags_ &= ~f_has_CR;
274        return success;
275    }
276
277    // Writes a newline sequence if the given device is a Sink.
278    template<typename Device>
279    void newline_if_sink(Device& dest) 
280    { 
281        typedef typename iostreams::category_of<Device>::type category;
282        newline_if_sink(dest, is_convertible<category, output>()); 
283    }
284
285    template<typename Sink>
286    void newline_if_sink(Sink& dest, mpl::true_) { newline(dest); }
287
288    template<typename Source>
289    void newline_if_sink(Source&, mpl::false_) { }
290
291    enum flags {
292        f_has_LF         = 32768,
293        f_has_CR         = f_has_LF << 1,
294        f_has_newline    = f_has_CR << 1,
295        f_has_EOF        = f_has_newline << 1,
296        f_read           = f_has_EOF << 1,
297        f_write          = f_read << 1
298    };
299    int       flags_;
300};
301BOOST_IOSTREAMS_PIPABLE(newline_filter, 0)
302
303class newline_checker : public detail::newline_base {
304public:
305    typedef char                 char_type;
306    struct category
307        : dual_use_filter_tag,
308          closable_tag
309        { };
310    explicit newline_checker(int target = newline::mixed)
311        : detail::newline_base(0), target_(target), open_(false)
312        { }
313    template<typename Source>
314    int get(Source& src)
315    {
316        using newline::CR;
317        using newline::LF;
318
319        if (!open_) {
320            open_ = true;
321            source() = 0;
322        }
323
324        int c;
325        if ((c = iostreams::get(src)) == WOULD_BLOCK)
326            return WOULD_BLOCK;
327
328        // Update source flags.
329        if (c != EOF)
330            source() &= ~f_line_complete;
331        if ((source() & f_has_CR) != 0) {
332            if (c == LF) {
333                source() |= newline::dos;
334                source() |= f_line_complete;
335            } else {
336                source() |= newline::mac;
337                if (c == EOF)
338                    source() |= f_line_complete;
339            }
340        } else if (c == LF) {
341            source() |= newline::posix;
342            source() |= f_line_complete;
343        }
344        source() = (source() & ~f_has_CR) | (c == CR ? f_has_CR : 0);
345
346        // Check for errors.
347        if ( c == EOF &&
348            (target_ & newline::final_newline) != 0 &&
349            (source() & f_line_complete) == 0 )
350        {
351            fail();
352        }
353        if ( (target_ & newline::platform_mask) != 0 &&
354             (source() & ~target_ & newline::platform_mask) != 0 )
355        {
356            fail();
357        }
358
359        return c;
360    }
361
362    template<typename Sink>
363    bool put(Sink& dest, int c)
364    {
365        using iostreams::newline::CR;
366        using iostreams::newline::LF;
367
368        if (!open_) {
369            open_ = true;
370            source() = 0;
371        }
372
373        if (!iostreams::put(dest, c))
374            return false;
375
376         // Update source flags.
377        source() &= ~f_line_complete;
378        if ((source() & f_has_CR) != 0) {
379            if (c == LF) {
380                source() |= newline::dos;
381                source() |= f_line_complete;
382            } else {
383                source() |= newline::mac;
384            }
385        } else if (c == LF) {
386            source() |= newline::posix;
387            source() |= f_line_complete;
388        }
389        source() = (source() & ~f_has_CR) | (c == CR ? f_has_CR : 0);
390
391        // Check for errors.
392        if ( (target_ & newline::platform_mask) != 0 &&
393             (source() & ~target_ & newline::platform_mask) != 0 )
394        {
395            fail();
396        }
397
398        return true;
399    }
400
401    template<typename Sink>
402    void close(Sink&, BOOST_IOS::openmode)
403    {
404        using iostreams::newline::final_newline;
405
406        // Update final_newline flag.
407        if ( (source() & f_has_CR) != 0 ||
408             (source() & f_line_complete) != 0 )
409        {
410            source() |= final_newline;
411        }
412
413        // Clear non-sticky flags.
414        source() &= ~(f_has_CR | f_line_complete);
415
416        // Check for errors.
417        if ( (target_ & final_newline) != 0 &&
418             (source() & final_newline) == 0 )
419        {
420            fail();
421        }
422    }
423private:
424    void fail() { boost::throw_exception(newline_error(source())); }
425    int& source() { return flags_; }
426    int source() const { return flags_; }
427
428    enum flags {
429        f_has_CR = 32768,
430        f_line_complete = f_has_CR << 1
431    };
432
433    int   target_;  // Represents expected input.
434    bool  open_;
435};
436BOOST_IOSTREAMS_PIPABLE(newline_checker, 0)
437
438} } // End namespaces iostreams, boost.
439
440#include <boost/iostreams/detail/config/enable_warnings.hpp>
441
442#endif // #ifndef BOOST_IOSTREAMS_NEWLINE_FILTER_HPP_INCLUDED