|
Boost Users : |
Subject: Re: [Boost-users] Iostreams: how can I control my (ostream) filter?
From: Akim Demaille (akim_at_[hidden])
Date: 2014-11-16 12:20:35
Le 15 nov. 2014 à 18:53, Sylro <syrmonsieur_at_[hidden]> a écrit :
> I have the same problem trying to escape XML : I want the filter to be
> enabled when writing contents and attribute values, and disabled when
> writing the markup.
>
> I tried the same solutions as Akim, but ended up embedding "control
> sequences" within the data to enable/disable the filter. From outside it's
> not that bad since the control sequences are wrapped into manipulators, but
> the implementation is simply horrible.
>
> Is there any suggestion to solve our problem ? How can we control a filter
> without having to sync ?
> Thanks !
Hi Sylro,
FWIW, here is what I ended up doing. First, the
filter itself:
#pragma once
#include <iostream>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/char_traits.hpp> // EOF, WOULD_BLOCK
#include <boost/iostreams/concepts.hpp> // multichar_output_filter
#include <boost/iostreams/operations.hpp> // get
namespace vcsn
{
namespace detail
{
namespace io = boost::iostreams;
/// Backslash backslashes.
class backslashify_output_filter
: public io::multichar_output_filter
{
public:
explicit backslashify_output_filter()
{}
void enable()
{
enabled_ = true;
}
void disable()
{
enabled_ = false;
}
template <typename Sink>
std::streamsize
write(Sink& dest, const char* s, std::streamsize n)
{
std::streamsize z;
for (z = 0; z < n; ++z)
{
char c = s[z];
if (enabled_ && c == '\\')
if (!io::put(dest, '\\'))
// FIXME: probably lost a char here.
break;
if (!io::put(dest, c))
break;
}
return z;
}
bool enabled_ = false;
};
}
}
then the caller:
bos_ << " [label = \"";
enable_();
aut_->print_state_name(s, bos_, "text");
disable_();
boss << "\", shape = box";
where bos_ is the stream:
detail::io::filtering_ostream bos_;
initialized like this:
dotter(const automaton_t& aut, std::ostream& out,
bool dot2tex = false)
: super_t(aut, out)
, dot2tex_(dot2tex)
{
bos_.push(detail::backslashify_output_filter());
bos_.push(out);
}
Then, the enable/disable sequence is as follows:
/// Enable the escaping of backslashes.
void enable_()
{
boost::iostreams::flush(bos_);
bos_.component<detail::backslashify_output_filter>(0)->enable();
}
/// Disable the escaping of backslashes.
void disable_()
{
boost::iostreams::flush(bos_);
bos_.component<detail::backslashify_output_filter>(0)->disable();
}
where the calls to flush are extremely important. I have
_not_ implement flush in my filter, to avoid flushing
downstream and kill the buffers: only the buffers before
the filter and the filter itself are flushed, so that the
effect happens when it should.
Cheers!
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net