mirror of
https://github.com/boostorg/iostreams.git
synced 2026-01-19 04:12:14 +00:00
222 lines
6.3 KiB
C++
222 lines
6.3 KiB
C++
// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
|
|
// (C) Copyright 2003-2007 Jonathan Turkanis
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.)
|
|
|
|
// See http://www.boost.org/libs/iostreams for documentation.
|
|
|
|
#ifndef BOOST_IOSTREAMS_DICTIONARY_FILTER_HPP_INCLUDED
|
|
#define BOOST_IOSTREAMS_DICTIONARY_FILTER_HPP_INCLUDED
|
|
|
|
#include <algorithm> // swap.
|
|
#include <cassert>
|
|
#include <cstdio> // EOF.
|
|
#include <iostream> // cin, cout.
|
|
#include <cctype>
|
|
#include <map>
|
|
#include <boost/config.hpp> // BOOST_NO_STDC_NAMESPACE.
|
|
#include <boost/iostreams/concepts.hpp>
|
|
#include <boost/iostreams/filter/stdio.hpp>
|
|
#include <boost/iostreams/operations.hpp>
|
|
|
|
#ifdef BOOST_NO_STDC_NAMESPACE
|
|
namespace std {
|
|
using ::isalpha;
|
|
using ::isupper;
|
|
using ::toupper;
|
|
using ::tolower;
|
|
}
|
|
#endif
|
|
|
|
namespace boost { namespace iostreams { namespace example {
|
|
|
|
class dictionary {
|
|
public:
|
|
void add(std::string key, const std::string& value);
|
|
void replace(std::string& key);
|
|
private:
|
|
typedef std::map<std::string, std::string> map_type;
|
|
void tolower(std::string& str);
|
|
map_type map_;
|
|
};
|
|
|
|
class dictionary_stdio_filter : public stdio_filter {
|
|
public:
|
|
dictionary_stdio_filter(dictionary& d) : dictionary_(d) { }
|
|
private:
|
|
void do_filter()
|
|
{
|
|
using namespace std;
|
|
while (true) {
|
|
int c = std::cin.get();
|
|
if (c == EOF || !std::isalpha((unsigned char) c)) {
|
|
dictionary_.replace(current_word_);
|
|
cout.write( current_word_.data(),
|
|
static_cast<std::streamsize>(current_word_.size()) );
|
|
current_word_.erase();
|
|
if (c == EOF)
|
|
break;
|
|
cout.put(c);
|
|
} else {
|
|
current_word_ += c;
|
|
}
|
|
}
|
|
}
|
|
dictionary& dictionary_;
|
|
std::string current_word_;
|
|
};
|
|
|
|
class dictionary_input_filter : public input_filter {
|
|
public:
|
|
dictionary_input_filter(dictionary& d)
|
|
: dictionary_(d), off_(std::string::npos), eof_(false)
|
|
{ }
|
|
|
|
template<typename Source>
|
|
int get(Source& src)
|
|
{
|
|
// Handle unfinished business.
|
|
if (off_ != std::string::npos && off_ < current_word_.size())
|
|
return current_word_[off_++];
|
|
if (off_ == current_word_.size()) {
|
|
current_word_.erase();
|
|
off_ = std::string::npos;
|
|
}
|
|
if (eof_)
|
|
return EOF;
|
|
|
|
// Compute curent word.
|
|
while (true) {
|
|
int c;
|
|
if ((c = iostreams::get(src)) == WOULD_BLOCK)
|
|
return WOULD_BLOCK;
|
|
|
|
if (c == EOF || !std::isalpha((unsigned char) c)) {
|
|
dictionary_.replace(current_word_);
|
|
off_ = 0;
|
|
if (c == EOF)
|
|
eof_ = true;
|
|
else
|
|
current_word_ += c;
|
|
break;
|
|
} else {
|
|
current_word_ += c;
|
|
}
|
|
}
|
|
|
|
return this->get(src); // Note: current_word_ is not empty.
|
|
}
|
|
|
|
template<typename Source>
|
|
void close(Source&)
|
|
{
|
|
current_word_.erase();
|
|
off_ = std::string::npos;
|
|
eof_ = false;
|
|
}
|
|
private:
|
|
dictionary& dictionary_;
|
|
std::string current_word_;
|
|
std::string::size_type off_;
|
|
bool eof_;
|
|
};
|
|
|
|
class dictionary_output_filter : public output_filter {
|
|
public:
|
|
typedef std::map<std::string, std::string> map_type;
|
|
dictionary_output_filter(dictionary& d)
|
|
: dictionary_(d), off_(std::string::npos)
|
|
{ }
|
|
|
|
template<typename Sink>
|
|
bool put(Sink& dest, int c)
|
|
{
|
|
if (off_ != std::string::npos && !write_current_word(dest))
|
|
return false;
|
|
if (!std::isalpha((unsigned char) c)) {
|
|
dictionary_.replace(current_word_);
|
|
off_ = 0;
|
|
}
|
|
|
|
current_word_ += c;
|
|
return true;
|
|
}
|
|
|
|
template<typename Sink>
|
|
void close(Sink& dest)
|
|
{
|
|
// Reset current_word_ and off_, saving old values.
|
|
std::string current_word;
|
|
std::string::size_type off = 0;
|
|
current_word.swap(current_word_);
|
|
std::swap(off, off_);
|
|
|
|
// Write remaining characters to dest.
|
|
if (off == std::string::npos) {
|
|
dictionary_.replace(current_word);
|
|
off = 0;
|
|
}
|
|
if (!current_word.empty())
|
|
iostreams::write(
|
|
dest,
|
|
current_word.data() + off,
|
|
static_cast<std::streamsize>(current_word.size() - off)
|
|
);
|
|
}
|
|
private:
|
|
template<typename Sink>
|
|
bool write_current_word(Sink& dest)
|
|
{
|
|
using namespace std;
|
|
std::streamsize amt =
|
|
static_cast<std::streamsize>(current_word_.size() - off_);
|
|
std::streamsize result =
|
|
iostreams::write(dest, current_word_.data() + off_, amt);
|
|
if (result == amt) {
|
|
current_word_.erase();
|
|
off_ = string::npos;
|
|
return true;
|
|
} else {
|
|
off_ += static_cast<string::size_type>(result);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
dictionary& dictionary_;
|
|
std::string current_word_;
|
|
std::string::size_type off_;
|
|
};
|
|
|
|
//------------------Implementation of dictionary------------------------------//
|
|
|
|
inline void dictionary::add(std::string key, const std::string& value)
|
|
{
|
|
tolower(key);
|
|
map_[key] = value;
|
|
}
|
|
|
|
inline void dictionary::replace(std::string& key)
|
|
{
|
|
using namespace std;
|
|
string copy(key);
|
|
tolower(copy);
|
|
map_type::iterator it = map_.find(key);
|
|
if (it == map_.end())
|
|
return;
|
|
string& value = it->second;
|
|
if (!value.empty() && !key.empty() && std::isupper((unsigned char) key[0]))
|
|
value[0] = std::toupper((unsigned char) value[0]);
|
|
key = value;
|
|
return;
|
|
}
|
|
|
|
inline void dictionary::tolower(std::string& str)
|
|
{
|
|
for (std::string::size_type z = 0, len = str.size(); z < len; ++z)
|
|
str[z] = std::tolower((unsigned char) str[z]);
|
|
}
|
|
|
|
} } } // End namespaces example, iostreams, boost.
|
|
|
|
#endif // #ifndef BOOST_IOSTREAMS_DICTIONARY_FILTER_HPP_INCLUDED
|