Ugly, not-to-be-pushed sucking in of all of Boost to get windows to work.
[dyninst.git] / external / boost / iostreams / filter / line.hpp
1 // (C) Copyright Jonathan Turkanis 2005.
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 #ifndef BOOST_IOSTREAMS_LINE_FILTER_HPP_INCLUDED
8 #define BOOST_IOSTREAMS_LINE_FILTER_HPP_INCLUDED
9
10 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
11 # pragma once
12 #endif
13
14 #include <algorithm>                               // min.
15 #include <cassert>
16 #include <memory>                                  // allocator.
17 #include <string>
18 #include <boost/config.hpp>                        // BOOST_STATIC_CONSTANT.
19 #include <boost/iostreams/categories.hpp>
20 #include <boost/iostreams/detail/closer.hpp>
21 #include <boost/iostreams/detail/ios.hpp>          // openmode, streamsize.
22 #include <boost/iostreams/pipeline.hpp>
23
24 // Must come last.
25 #include <boost/iostreams/detail/config/disable_warnings.hpp> // VC7.1 C4244.
26
27 namespace boost { namespace iostreams {
28
29 //
30 // Template name: line_filter.
31 // Template paramters:
32 //      Ch - The character type.
33 //      Alloc - The allocator type.
34 // Description: Filter which processes data one line at a time.
35 //
36 template< typename Ch,
37           typename Alloc =
38           #if BOOST_WORKAROUND(__GNUC__, < 3)
39               typename std::basic_string<Ch>::allocator_type
40           #else
41               std::allocator<Ch>
42           #endif
43           >
44 class basic_line_filter {
45 private:
46     typedef typename std::basic_string<Ch>::traits_type  string_traits;
47 public:
48     typedef Ch                                           char_type;
49     typedef char_traits<char_type>                       traits_type;
50     typedef std::basic_string<
51                 Ch,
52                 string_traits,
53                 Alloc
54             >                                            string_type;
55     struct category
56         : dual_use,
57           filter_tag,
58           multichar_tag,
59           closable_tag
60         { };
61 protected:
62     basic_line_filter() : pos_(string_type::npos), state_(0) { }
63 public:
64     virtual ~basic_line_filter() { }
65
66     template<typename Source>
67     std::streamsize read(Source& src, char_type* s, std::streamsize n)
68     {
69         using namespace std;
70         assert(!(state_ & f_write));
71         state_ |= f_read;
72
73         // Handle unfinished business.
74         streamsize result = 0;
75         if (!cur_line_.empty() && (result = read_line(s, n)) == n)
76             return n;
77
78         typename traits_type::int_type status = traits_type::good();
79         while (result < n && !traits_type::is_eof(status)) {
80
81             // Call next_line() to retrieve a line of filtered test, and
82             // read_line() to copy it into buffer s.
83             if (traits_type::would_block(status = next_line(src)))
84                 return result;
85             result += read_line(s + result, n - result);
86         }
87
88         return detail::check_eof(result);
89     }
90
91     template<typename Sink>
92     std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
93     {
94         using namespace std;
95         assert(!(state_ & f_read));
96         state_ |= f_write;
97
98         // Handle unfinished business.
99         if (pos_ != string_type::npos && !write_line(snk))
100             return 0;
101
102         const char_type *cur = s, *next;
103         while (true) {
104
105             // Search for the next full line in [cur, s + n), filter it
106             // and write it to snk.
107             typename string_type::size_type rest = n - (cur - s);
108             if ((next = traits_type::find(cur, rest, traits_type::newline()))) {
109                 cur_line_.append(cur, next - cur);
110                 cur = next + 1;
111                 if (!write_line(snk))
112                     return static_cast<std::streamsize>(cur - s);
113             } else {
114                 cur_line_.append(cur, rest);
115                 return n;
116             }
117         }
118     }
119
120     typedef basic_line_filter<Ch, Alloc> self;
121     friend struct detail::closer<self>;
122
123     template<typename Sink>
124     void close(Sink& snk, BOOST_IOS::openmode which)
125     {
126         if ((state_ & f_read) && (which & BOOST_IOS::in))
127             close();
128
129         if ((state_ & f_write) && (which & BOOST_IOS::out)) {
130             detail::closer<self> closer(*this);
131             if (!cur_line_.empty())
132                 write_line(snk);
133         }
134     }
135 private:
136     virtual string_type do_filter(const string_type& line) = 0;
137
138     // Copies filtered characters fron the current line into
139     // the given buffer.
140     std::streamsize read_line(char_type* s, std::streamsize n)
141     {
142         using namespace std;
143         streamsize result =
144             (std::min) (n, static_cast<streamsize>(cur_line_.size()));
145         traits_type::copy(s, cur_line_.data(), result);
146         cur_line_.erase(0, result);
147         return result;
148     }
149
150     // Attempts to retrieve a line of text from the given source; returns
151     // an int_type as a good/eof/would_block status code.
152     template<typename Source>
153     typename traits_type::int_type next_line(Source& src)
154     {
155         using namespace std;
156         typename traits_type::int_type c;
157         while ( traits_type::is_good(c = iostreams::get(src)) &&
158                 c != traits_type::newline() )
159         {
160             cur_line_ += traits_type::to_int_type(c);
161         }
162         if (!traits_type::would_block(c)) {
163             if (!cur_line_.empty() || c == traits_type::newline())
164                 cur_line_ = do_filter(cur_line_);
165             if (c == traits_type::newline())
166                 cur_line_ += c;
167         }
168         return c; // status indicator.
169     }
170
171     // Filters the current line and attemps to write it to the given sink.
172     // Returns true for success.
173     template<typename Sink>
174     bool write_line(Sink& snk)
175     {
176         string_type line = do_filter(cur_line_) + traits_type::newline();
177         std::streamsize amt = static_cast<std::streamsize>(line.size());
178         bool result = iostreams::write(snk, line.data(), amt) == amt;
179         if (result)
180             clear();
181         return result;
182     }
183
184     void close()
185     {
186         clear();
187         state_ = 0;
188     }
189
190     void clear()
191     {
192         cur_line_.erase();
193         pos_ = string_type::npos;
194     }
195
196     enum flag_type {
197         f_read   = 1,
198         f_write  = f_read << 1
199     };
200
201     string_type                      cur_line_;
202     typename string_type::size_type  pos_;
203     int                              state_;
204 };
205 BOOST_IOSTREAMS_PIPABLE(basic_line_filter, 2)
206
207 typedef basic_line_filter<char>     line_filter;
208 typedef basic_line_filter<wchar_t>  wline_filter;
209
210 } } // End namespaces iostreams, boost.
211
212 #include <boost/iostreams/detail/config/enable_warnings.hpp>
213
214 #endif // #ifndef BOOST_IOSTREAMS_LINE_FILTER_HPP_INCLUDED