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:
dictionary_stdio_filter(dictionary & d)45     dictionary_stdio_filter(dictionary& d) : dictionary_(d) { }
46 private:
do_filter()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:
dictionary_input_filter(dictionary & d)71     dictionary_input_filter(dictionary& d)
72         : dictionary_(d), off_(std::string::npos), eof_(false)
73         { }
74 
75     template<typename Source>
get(Source & src)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>
close(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;
dictionary_output_filter(dictionary & d)127     dictionary_output_filter(dictionary& d)
128         : dictionary_(d), off_(std::string::npos)
129         { }
130 
131     template<typename Sink>
put(Sink & dest,int c)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>
close(Sink & dest)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>
write_current_word(Sink & dest)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 
add(std::string key,const std::string & value)192 inline void dictionary::add(std::string key, const std::string& value)
193 {
194     tolower(key);
195     map_[key] = value;
196 }
197 
replace(std::string & key)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 
tolower(std::string & str)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
222