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 | #ifndef BOOST_IOSTREAMS_DICTIONARY_FILTER_HPP_INCLUDED |
9 | #define BOOST_IOSTREAMS_DICTIONARY_FILTER_HPP_INCLUDED |
10 | |
11 | #include <algorithm> // swap. |
12 | #include <cassert> |
13 | #include <cstdio> // EOF. |
14 | #include <iostream> // cin, cout. |
15 | #include <cctype> |
16 | #include <map> |
17 | #include <boost/config.hpp> // BOOST_NO_STDC_NAMESPACE. |
18 | #include <boost/iostreams/concepts.hpp> |
19 | #include <boost/iostreams/filter/stdio.hpp> |
20 | #include <boost/iostreams/operations.hpp> |
21 | |
22 | #ifdef BOOST_NO_STDC_NAMESPACE |
23 | namespace std { |
24 | using ::isalpha; |
25 | using ::isupper; |
26 | using ::toupper; |
27 | using ::tolower; |
28 | } |
29 | #endif |
30 | |
31 | namespace boost { namespace iostreams { namespace example { |
32 | |
33 | class dictionary { |
34 | public: |
35 | void add(std::string key, const std::string& value); |
36 | void replace(std::string& key); |
37 | private: |
38 | typedef std::map<std::string, std::string> map_type; |
39 | void tolower(std::string& str); |
40 | map_type map_; |
41 | }; |
42 | |
43 | class dictionary_stdio_filter : public stdio_filter { |
44 | public: |
45 | dictionary_stdio_filter(dictionary& d) : dictionary_(d) { } |
46 | private: |
47 | void do_filter() |
48 | { |
49 | using namespace std; |
50 | while (true) { |
51 | int c = std::cin.get(); |
52 | if (c == EOF || !std::isalpha((unsigned char) c)) { |
53 | dictionary_.replace(key&: current_word_); |
54 | cout.write( s: current_word_.data(), |
55 | n: static_cast<std::streamsize>(current_word_.size()) ); |
56 | current_word_.erase(); |
57 | if (c == EOF) |
58 | break; |
59 | cout.put(c: c); |
60 | } else { |
61 | current_word_ += c; |
62 | } |
63 | } |
64 | } |
65 | dictionary& dictionary_; |
66 | std::string current_word_; |
67 | }; |
68 | |
69 | class dictionary_input_filter : public input_filter { |
70 | public: |
71 | dictionary_input_filter(dictionary& d) |
72 | : dictionary_(d), off_(std::string::npos), eof_(false) |
73 | { } |
74 | |
75 | template<typename Source> |
76 | int get(Source& src) |
77 | { |
78 | // Handle unfinished business. |
79 | if (off_ != std::string::npos && off_ < current_word_.size()) |
80 | return current_word_[off_++]; |
81 | if (off_ == current_word_.size()) { |
82 | current_word_.erase(); |
83 | off_ = std::string::npos; |
84 | } |
85 | if (eof_) |
86 | return EOF; |
87 | |
88 | // Compute curent word. |
89 | while (true) { |
90 | int c; |
91 | if ((c = iostreams::get(src)) == WOULD_BLOCK) |
92 | return WOULD_BLOCK; |
93 | |
94 | if (c == EOF || !std::isalpha((unsigned char) c)) { |
95 | dictionary_.replace(key&: current_word_); |
96 | off_ = 0; |
97 | if (c == EOF) |
98 | eof_ = true; |
99 | else |
100 | current_word_ += c; |
101 | break; |
102 | } else { |
103 | current_word_ += c; |
104 | } |
105 | } |
106 | |
107 | return this->get(src); // Note: current_word_ is not empty. |
108 | } |
109 | |
110 | template<typename Source> |
111 | void close(Source&) |
112 | { |
113 | current_word_.erase(); |
114 | off_ = std::string::npos; |
115 | eof_ = false; |
116 | } |
117 | private: |
118 | dictionary& dictionary_; |
119 | std::string current_word_; |
120 | std::string::size_type off_; |
121 | bool eof_; |
122 | }; |
123 | |
124 | class dictionary_output_filter : public output_filter { |
125 | public: |
126 | typedef std::map<std::string, std::string> map_type; |
127 | dictionary_output_filter(dictionary& d) |
128 | : dictionary_(d), off_(std::string::npos) |
129 | { } |
130 | |
131 | template<typename Sink> |
132 | bool put(Sink& dest, int c) |
133 | { |
134 | if (off_ != std::string::npos && !write_current_word(dest)) |
135 | return false; |
136 | if (!std::isalpha((unsigned char) c)) { |
137 | dictionary_.replace(key&: current_word_); |
138 | off_ = 0; |
139 | } |
140 | |
141 | current_word_ += c; |
142 | return true; |
143 | } |
144 | |
145 | template<typename Sink> |
146 | void close(Sink& dest) |
147 | { |
148 | // Reset current_word_ and off_, saving old values. |
149 | std::string current_word; |
150 | std::string::size_type off = 0; |
151 | current_word.swap(s&: current_word_); |
152 | std::swap(a&: off, b&: off_); |
153 | |
154 | // Write remaining characters to dest. |
155 | if (off == std::string::npos) { |
156 | dictionary_.replace(key&: current_word); |
157 | off = 0; |
158 | } |
159 | if (!current_word.empty()) |
160 | iostreams::write( |
161 | dest, |
162 | current_word.data() + off, |
163 | static_cast<std::streamsize>(current_word.size() - off) |
164 | ); |
165 | } |
166 | private: |
167 | template<typename Sink> |
168 | bool write_current_word(Sink& dest) |
169 | { |
170 | using namespace std; |
171 | std::streamsize amt = |
172 | static_cast<std::streamsize>(current_word_.size() - off_); |
173 | std::streamsize result = |
174 | iostreams::write(dest, current_word_.data() + off_, amt); |
175 | if (result == amt) { |
176 | current_word_.erase(); |
177 | off_ = string::npos; |
178 | return true; |
179 | } else { |
180 | off_ += static_cast<string::size_type>(result); |
181 | return false; |
182 | } |
183 | } |
184 | |
185 | dictionary& dictionary_; |
186 | std::string current_word_; |
187 | std::string::size_type off_; |
188 | }; |
189 | |
190 | //------------------Implementation of dictionary------------------------------// |
191 | |
192 | inline void dictionary::add(std::string key, const std::string& value) |
193 | { |
194 | tolower(str&: key); |
195 | map_[key] = value; |
196 | } |
197 | |
198 | inline void dictionary::replace(std::string& key) |
199 | { |
200 | using namespace std; |
201 | string copy(key); |
202 | tolower(str&: copy); |
203 | map_type::iterator it = map_.find(x: key); |
204 | if (it == map_.end()) |
205 | return; |
206 | string& value = it->second; |
207 | if (!value.empty() && !key.empty() && std::isupper((unsigned char) key[0])) |
208 | value[0] = std::toupper(c: (unsigned char) value[0]); |
209 | key = value; |
210 | return; |
211 | } |
212 | |
213 | inline void dictionary::tolower(std::string& str) |
214 | { |
215 | for (std::string::size_type z = 0, len = str.size(); z < len; ++z) |
216 | str[z] = std::tolower(c: (unsigned char) str[z]); |
217 | } |
218 | |
219 | } } } // End namespaces example, iostreams, boost. |
220 | |
221 | #endif // #ifndef BOOST_IOSTREAMS_DICTIONARY_FILTER_HPP_INCLUDED |
222 | |