123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
- // (C) Copyright 2003-2007 Jonathan Turkanis
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
- // See http://www.boost.org/libs/iostreams for documentation.
- // NOTE: I hope to replace the current implementation with a much simpler
- // one.
- #ifndef BOOST_IOSTREAMS_NEWLINE_FILTER_HPP_INCLUDED
- #define BOOST_IOSTREAMS_NEWLINE_FILTER_HPP_INCLUDED
- #if defined(_MSC_VER)
- # pragma once
- #endif
- #include <boost/assert.hpp>
- #include <cstdio>
- #include <stdexcept> // logic_error.
- #include <boost/config.hpp> // BOOST_STATIC_CONSTANT.
- #include <boost/iostreams/categories.hpp>
- #include <boost/iostreams/detail/char_traits.hpp>
- #include <boost/iostreams/detail/ios.hpp> // BOOST_IOSTREAMS_FAILURE
- #include <boost/iostreams/read.hpp> // get
- #include <boost/iostreams/write.hpp> // put
- #include <boost/iostreams/pipeline.hpp>
- #include <boost/iostreams/putback.hpp>
- #include <boost/mpl/bool.hpp>
- #include <boost/throw_exception.hpp>
- #include <boost/type_traits/is_convertible.hpp>
- // Must come last.
- #include <boost/iostreams/detail/config/disable_warnings.hpp>
- #define BOOST_IOSTREAMS_ASSERT_UNREACHABLE(val) \
- (BOOST_ASSERT("unreachable code" == 0), val) \
- /**/
- namespace boost { namespace iostreams {
- namespace newline {
- const char CR = 0x0D;
- const char LF = 0x0A;
- // Flags for configuring newline_filter.
- // Exactly one of the following three flags must be present.
- const int posix = 1; // Use CR as line separator.
- const int mac = 2; // Use LF as line separator.
- const int dos = 4; // Use CRLF as line separator.
- const int mixed = 8; // Mixed line endings.
- const int final_newline = 16;
- const int platform_mask = posix | dos | mac;
- } // End namespace newline.
- namespace detail {
- class newline_base {
- public:
- bool is_posix() const
- {
- return !is_mixed() && (flags_ & newline::posix) != 0;
- }
- bool is_dos() const
- {
- return !is_mixed() && (flags_ & newline::dos) != 0;
- }
- bool is_mac() const
- {
- return !is_mixed() && (flags_ & newline::mac) != 0;
- }
- bool is_mixed_posix() const { return (flags_ & newline::posix) != 0; }
- bool is_mixed_dos() const { return (flags_ & newline::dos) != 0; }
- bool is_mixed_mac() const { return (flags_ & newline::mac) != 0; }
- bool is_mixed() const
- {
- int platform =
- (flags_ & newline::posix) != 0 ?
- newline::posix :
- (flags_ & newline::dos) != 0 ?
- newline::dos :
- (flags_ & newline::mac) != 0 ?
- newline::mac :
- 0;
- return (flags_ & ~platform & newline::platform_mask) != 0;
- }
- bool has_final_newline() const
- {
- return (flags_ & newline::final_newline) != 0;
- }
- protected:
- newline_base(int flags) : flags_(flags) { }
- int flags_;
- };
- } // End namespace detail.
- class newline_error
- : public BOOST_IOSTREAMS_FAILURE, public detail::newline_base
- {
- private:
- friend class newline_checker;
- newline_error(int flags)
- : BOOST_IOSTREAMS_FAILURE("bad line endings"),
- detail::newline_base(flags)
- { }
- };
- class newline_filter {
- public:
- typedef char char_type;
- struct category
- : dual_use,
- filter_tag,
- closable_tag
- { };
- explicit newline_filter(int target) : flags_(target)
- {
- if ( target != iostreams::newline::posix &&
- target != iostreams::newline::dos &&
- target != iostreams::newline::mac )
- {
- boost::throw_exception(std::logic_error("bad flags"));
- }
- }
- template<typename Source>
- int get(Source& src)
- {
- using iostreams::newline::CR;
- using iostreams::newline::LF;
- BOOST_ASSERT((flags_ & f_write) == 0);
- flags_ |= f_read;
- if (flags_ & (f_has_LF | f_has_EOF)) {
- if (flags_ & f_has_LF)
- return newline();
- else
- return EOF;
- }
- int c =
- (flags_ & f_has_CR) == 0 ?
- iostreams::get(src) :
- CR;
- if (c == WOULD_BLOCK )
- return WOULD_BLOCK;
- if (c == CR) {
- flags_ |= f_has_CR;
- int d;
- if ((d = iostreams::get(src)) == WOULD_BLOCK)
- return WOULD_BLOCK;
- if (d == LF) {
- flags_ &= ~f_has_CR;
- return newline();
- }
- if (d == EOF) {
- flags_ |= f_has_EOF;
- } else {
- iostreams::putback(src, d);
- }
- flags_ &= ~f_has_CR;
- return newline();
- }
- if (c == LF)
- return newline();
- return c;
- }
- template<typename Sink>
- bool put(Sink& dest, char c)
- {
- using iostreams::newline::CR;
- using iostreams::newline::LF;
- BOOST_ASSERT((flags_ & f_read) == 0);
- flags_ |= f_write;
- if ((flags_ & f_has_LF) != 0)
- return c == LF ?
- newline(dest) :
- newline(dest) && this->put(dest, c);
- if (c == LF)
- return newline(dest);
- if ((flags_ & f_has_CR) != 0)
- return newline(dest) ?
- this->put(dest, c) :
- false;
- if (c == CR) {
- flags_ |= f_has_CR;
- return true;
- }
- return iostreams::put(dest, c);
- }
- template<typename Sink>
- void close(Sink& dest, BOOST_IOS::openmode)
- {
- if ((flags_ & f_write) != 0 && (flags_ & f_has_CR) != 0)
- newline_if_sink(dest);
- flags_ &= ~f_has_LF; // Restore original flags.
- }
- private:
- // Returns the appropriate element of a newline sequence.
- int newline()
- {
- using iostreams::newline::CR;
- using iostreams::newline::LF;
- switch (flags_ & iostreams::newline::platform_mask) {
- case iostreams::newline::posix:
- return LF;
- case iostreams::newline::mac:
- return CR;
- case iostreams::newline::dos:
- if (flags_ & f_has_LF) {
- flags_ &= ~f_has_LF;
- return LF;
- } else {
- flags_ |= f_has_LF;
- return CR;
- }
- }
- return BOOST_IOSTREAMS_ASSERT_UNREACHABLE(0);
- }
- // Writes a newline sequence.
- template<typename Sink>
- bool newline(Sink& dest)
- {
- using iostreams::newline::CR;
- using iostreams::newline::LF;
- bool success = false;
- switch (flags_ & iostreams::newline::platform_mask) {
- case iostreams::newline::posix:
- success = boost::iostreams::put(dest, LF);
- break;
- case iostreams::newline::mac:
- success = boost::iostreams::put(dest, CR);
- break;
- case iostreams::newline::dos:
- if ((flags_ & f_has_LF) != 0) {
- if ((success = boost::iostreams::put(dest, LF)))
- flags_ &= ~f_has_LF;
- } else if (boost::iostreams::put(dest, CR)) {
- if (!(success = boost::iostreams::put(dest, LF)))
- flags_ |= f_has_LF;
- }
- break;
- }
- if (success)
- flags_ &= ~f_has_CR;
- return success;
- }
- // Writes a newline sequence if the given device is a Sink.
- template<typename Device>
- void newline_if_sink(Device& dest)
- {
- typedef typename iostreams::category_of<Device>::type category;
- newline_if_sink(dest, is_convertible<category, output>());
- }
- template<typename Sink>
- void newline_if_sink(Sink& dest, mpl::true_) { newline(dest); }
- template<typename Source>
- void newline_if_sink(Source&, mpl::false_) { }
- enum flags {
- f_has_LF = 32768,
- f_has_CR = f_has_LF << 1,
- f_has_newline = f_has_CR << 1,
- f_has_EOF = f_has_newline << 1,
- f_read = f_has_EOF << 1,
- f_write = f_read << 1
- };
- int flags_;
- };
- BOOST_IOSTREAMS_PIPABLE(newline_filter, 0)
- class newline_checker : public detail::newline_base {
- public:
- typedef char char_type;
- struct category
- : dual_use_filter_tag,
- closable_tag
- { };
- explicit newline_checker(int target = newline::mixed)
- : detail::newline_base(0), target_(target), open_(false)
- { }
- template<typename Source>
- int get(Source& src)
- {
- using newline::CR;
- using newline::LF;
- if (!open_) {
- open_ = true;
- source() = 0;
- }
- int c;
- if ((c = iostreams::get(src)) == WOULD_BLOCK)
- return WOULD_BLOCK;
- // Update source flags.
- if (c != EOF)
- source() &= ~f_line_complete;
- if ((source() & f_has_CR) != 0) {
- if (c == LF) {
- source() |= newline::dos;
- source() |= f_line_complete;
- } else {
- source() |= newline::mac;
- if (c == EOF)
- source() |= f_line_complete;
- }
- } else if (c == LF) {
- source() |= newline::posix;
- source() |= f_line_complete;
- }
- source() = (source() & ~f_has_CR) | (c == CR ? f_has_CR : 0);
- // Check for errors.
- if ( c == EOF &&
- (target_ & newline::final_newline) != 0 &&
- (source() & f_line_complete) == 0 )
- {
- fail();
- }
- if ( (target_ & newline::platform_mask) != 0 &&
- (source() & ~target_ & newline::platform_mask) != 0 )
- {
- fail();
- }
- return c;
- }
- template<typename Sink>
- bool put(Sink& dest, int c)
- {
- using iostreams::newline::CR;
- using iostreams::newline::LF;
- if (!open_) {
- open_ = true;
- source() = 0;
- }
- if (!iostreams::put(dest, c))
- return false;
- // Update source flags.
- source() &= ~f_line_complete;
- if ((source() & f_has_CR) != 0) {
- if (c == LF) {
- source() |= newline::dos;
- source() |= f_line_complete;
- } else {
- source() |= newline::mac;
- }
- } else if (c == LF) {
- source() |= newline::posix;
- source() |= f_line_complete;
- }
- source() = (source() & ~f_has_CR) | (c == CR ? f_has_CR : 0);
- // Check for errors.
- if ( (target_ & newline::platform_mask) != 0 &&
- (source() & ~target_ & newline::platform_mask) != 0 )
- {
- fail();
- }
- return true;
- }
- template<typename Sink>
- void close(Sink&, BOOST_IOS::openmode)
- {
- using iostreams::newline::final_newline;
- // Update final_newline flag.
- if ( (source() & f_has_CR) != 0 ||
- (source() & f_line_complete) != 0 )
- {
- source() |= final_newline;
- }
- // Clear non-sticky flags.
- source() &= ~(f_has_CR | f_line_complete);
- // Check for errors.
- if ( (target_ & final_newline) != 0 &&
- (source() & final_newline) == 0 )
- {
- fail();
- }
- }
- private:
- void fail() { boost::throw_exception(newline_error(source())); }
- int& source() { return flags_; }
- int source() const { return flags_; }
- enum flags {
- f_has_CR = 32768,
- f_line_complete = f_has_CR << 1
- };
- int target_; // Represents expected input.
- bool open_;
- };
- BOOST_IOSTREAMS_PIPABLE(newline_checker, 0)
- } } // End namespaces iostreams, boost.
- #include <boost/iostreams/detail/config/enable_warnings.hpp>
- #endif // #ifndef BOOST_IOSTREAMS_NEWLINE_FILTER_HPP_INCLUDED
|