File indexing completed on 2025-01-30 09:44:31
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_IOSTREAMS_LINE_FILTER_HPP_INCLUDED
0009 #define BOOST_IOSTREAMS_LINE_FILTER_HPP_INCLUDED
0010
0011 #if defined(_MSC_VER)
0012 # pragma once
0013 #endif
0014
0015 #include <algorithm> // min.
0016 #include <boost/assert.hpp>
0017 #include <memory> // allocator.
0018 #include <string>
0019 #include <boost/config.hpp> // BOOST_STATIC_CONSTANT.
0020 #include <boost/iostreams/categories.hpp>
0021 #include <boost/iostreams/checked_operations.hpp>
0022 #include <boost/iostreams/detail/ios.hpp> // openmode, streamsize.
0023 #include <boost/iostreams/read.hpp> // check_eof
0024 #include <boost/iostreams/pipeline.hpp>
0025 #include <boost/iostreams/write.hpp>
0026
0027
0028 #include <boost/iostreams/detail/config/disable_warnings.hpp> // VC7.1 C4244.
0029
0030 namespace boost { namespace iostreams {
0031
0032
0033
0034
0035
0036
0037
0038
0039 template< typename Ch,
0040 typename Alloc = std::allocator<Ch> >
0041 class basic_line_filter {
0042 private:
0043 typedef typename std::basic_string<Ch>::traits_type string_traits;
0044 public:
0045 typedef Ch char_type;
0046 typedef char_traits<char_type> traits_type;
0047 typedef std::basic_string<
0048 Ch,
0049 string_traits,
0050 Alloc
0051 > string_type;
0052 struct category
0053 : dual_use,
0054 filter_tag,
0055 multichar_tag,
0056 closable_tag
0057 { };
0058 protected:
0059 basic_line_filter(bool suppress_newlines = false)
0060 : pos_(string_type::npos),
0061 flags_(suppress_newlines ? f_suppress : 0)
0062 { }
0063 public:
0064 virtual ~basic_line_filter() { }
0065
0066 template<typename Source>
0067 std::streamsize read(Source& src, char_type* s, std::streamsize n)
0068 {
0069 using namespace std;
0070 BOOST_ASSERT(!(flags_ & f_write));
0071 flags_ |= f_read;
0072
0073
0074 std::streamsize result = 0;
0075 if (!cur_line_.empty() && (result = read_line(s, n)) == n)
0076 return n;
0077
0078 typename traits_type::int_type status = traits_type::good();
0079 while (result < n && !traits_type::is_eof(status)) {
0080
0081
0082
0083 if (traits_type::would_block(status = next_line(src)))
0084 return result;
0085 result += read_line(s + result, n - result);
0086 }
0087
0088 return detail::check_eof(result);
0089 }
0090
0091 template<typename Sink>
0092 std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
0093 {
0094 using namespace std;
0095 BOOST_ASSERT(!(flags_ & f_read));
0096 flags_ |= f_write;
0097
0098
0099 if (pos_ != string_type::npos && !write_line(snk))
0100 return 0;
0101
0102 const char_type *cur = s, *next;
0103 while (true) {
0104
0105
0106
0107 typename string_type::size_type rest = n - (cur - s);
0108 if ((next = traits_type::find(cur, rest, traits_type::newline()))) {
0109 cur_line_.append(cur, next - cur);
0110 cur = next + 1;
0111 if (!write_line(snk))
0112 return static_cast<std::streamsize>(cur - s);
0113 } else {
0114 cur_line_.append(cur, rest);
0115 return n;
0116 }
0117 }
0118 }
0119
0120 template<typename Sink>
0121 void close(Sink& snk, BOOST_IOS::openmode which)
0122 {
0123 if ((flags_ & f_read) && which == BOOST_IOS::in)
0124 close_impl();
0125
0126 if ((flags_ & f_write) && which == BOOST_IOS::out) {
0127 try {
0128 if (!cur_line_.empty())
0129 write_line(snk);
0130 } catch (...) {
0131 try {
0132 close_impl();
0133 } catch (...) { }
0134 throw;
0135 }
0136 close_impl();
0137 }
0138 }
0139 private:
0140 virtual string_type do_filter(const string_type& line) = 0;
0141
0142
0143
0144 std::streamsize read_line(char_type* s, std::streamsize n)
0145 {
0146 using namespace std;
0147 std::streamsize result =
0148 (std::min) (n, static_cast<std::streamsize>(cur_line_.size()));
0149 traits_type::copy(s, cur_line_.data(), result);
0150 cur_line_.erase(0, result);
0151 return result;
0152 }
0153
0154
0155
0156 template<typename Source>
0157 typename traits_type::int_type next_line(Source& src)
0158 {
0159 using namespace std;
0160 typename traits_type::int_type c;
0161 while ( traits_type::is_good(c = iostreams::get(src)) &&
0162 c != traits_type::newline() )
0163 {
0164 cur_line_ += traits_type::to_int_type(c);
0165 }
0166 if (!traits_type::would_block(c)) {
0167 if (!cur_line_.empty() || c == traits_type::newline())
0168 cur_line_ = do_filter(cur_line_);
0169 if (c == traits_type::newline() && (flags_ & f_suppress) == 0)
0170 cur_line_ += c;
0171 }
0172 return c;
0173 }
0174
0175
0176
0177 template<typename Sink>
0178 bool write_line(Sink& snk)
0179 {
0180 string_type line = do_filter(cur_line_);
0181 if ((flags_ & f_suppress) == 0)
0182 line += traits_type::newline();
0183 std::streamsize amt = static_cast<std::streamsize>(line.size());
0184 bool result = iostreams::write_if(snk, line.data(), amt) == amt;
0185 if (result)
0186 clear();
0187 return result;
0188 }
0189
0190 void close_impl()
0191 {
0192 clear();
0193 flags_ &= f_suppress;
0194 }
0195
0196 void clear()
0197 {
0198 cur_line_.erase();
0199 pos_ = string_type::npos;
0200 }
0201
0202 enum flag_type {
0203 f_read = 1,
0204 f_write = f_read << 1,
0205 f_suppress = f_write << 1
0206 };
0207
0208 string_type cur_line_;
0209 typename string_type::size_type pos_;
0210 int flags_;
0211 };
0212 BOOST_IOSTREAMS_PIPABLE(basic_line_filter, 2)
0213
0214 typedef basic_line_filter<char> line_filter;
0215 typedef basic_line_filter<wchar_t> wline_filter;
0216
0217 } }
0218
0219 #include <boost/iostreams/detail/config/enable_warnings.hpp>
0220
0221 #endif