]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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(current_word_); | |
54 | cout.write( current_word_.data(), | |
55 | static_cast<std::streamsize>(current_word_.size()) ); | |
56 | current_word_.erase(); | |
57 | if (c == EOF) | |
58 | break; | |
59 | cout.put(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(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(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(current_word_); | |
152 | std::swap(off, off_); | |
153 | ||
154 | // Write remaining characters to dest. | |
155 | if (off == std::string::npos) { | |
156 | dictionary_.replace(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(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(copy); | |
203 | map_type::iterator it = map_.find(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((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((unsigned char) str[z]); | |
217 | } | |
218 | ||
219 | } } } // End namespaces example, iostreams, boost. | |
220 | ||
221 | #endif // #ifndef BOOST_IOSTREAMS_DICTIONARY_FILTER_HPP_INCLUDED |