source: NonGTP/Boost/boost/iostreams/filter/line.hpp @ 857

Revision 857, 6.8 KB checked in by igarcia, 18 years ago (diff)
Line 
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
27namespace 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//
36template< 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          >
44class basic_line_filter {
45private:
46    typedef typename std::basic_string<Ch>::traits_type  string_traits;
47public:
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        { };
61protected:
62    basic_line_filter() : pos_(string_type::npos), state_(0) { }
63public:
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    }
135private:
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};
205BOOST_IOSTREAMS_PIPABLE(basic_line_filter, 2)
206
207typedef basic_line_filter<char>     line_filter;
208typedef 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
Note: See TracBrowser for help on using the repository browser.