Boost logo

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