Boost logo

Boost :

From: Jonathan Turkanis (technews_at_[hidden])
Date: 2005-02-28 19:31:09


Brian Braatz wrote:

>
> I have this sinking feeling this is like when I am standing in front
> of
> the fridge and say "Honey, WHERE IS THE MILK?"

:-)

>> I'm not familiar with the function OutputDebugString,

<snip>

> OutputDebugString() is a win32 function, basically when you build

<snip>

> (I point this out because it is semi-important to note that the
> process OutputDebugString has to go through is SLOW. I.e. just for
> reference, you would NOT want to call OutputDebugString() for each char)

Devices are buffered by default, so unless you specify a buffer of size 0 is
should be called only when you have written a big chunk of text or when you
flush the stream.

> The problem with above, IF I UNDERSTAND iostreams properly, is that I
> just want a filter on the debug_out_sink because it needs the \r\n.
> Everything else needs a \n.

Only data that flows through the newline filter will be affected, so if you put
the newline filter after the tee everything should work in your case.

> Do I need to weave in the filter on the debug_out_sink class? (either
> by "has a" or "is a")?
>
> What I am after is the "user" of debug_out_sink can just "push" it in
> without having to know about \r\n vs \n weirdness.

More generally, if you want the line-ending conversions built in to
debug_out_sink, you could use the class template compose:

    struct debug_out_sink_impl { /* as before */ };

    debug_out_sink : compose<newline_filter, debug_out_sink_impl > {
        // writes to a debug_out_sink_impl , filteed by a newline_filter
    };

The only problem is I haven't written compose yet! The reason is that I can't
figure out what the constructor arguments should be, since arguments for both
components may need to be specified.

The only way to merge the line-conversion with the debug_out_sink using existing
library components (rather than by hand) is to use the detail class chain, like
so:

     #include <boost/iostreams/detail/chain.hpp>
     #include <boost/iostreams/filter/newline_filter.hpp>

    struct debug_out_sink_impl : boost::iostreams::sink
    {
        void write(const char* s, std::streamsize n)
        {
            std::string str(s, n);
            OutputDebugStringA(str.c_str());
        }
    };

    struct debug_out_sink
        : boost::iostreams::detail::chain<boost::iostreams::output>
    {
        debug_out_sink ()
        {
            using namespace boost::iostreams;
            push(newline_filter(newline::windows));
            push(debug_out_sink_impl());
        }
    };

I've included a test program at the end, which executes correctly on my machine.

The class chain is a detail because I was not sure it would be useful to library
users, and by documenting it I would increase the apparent size of the library.
If there is no other good way to solve this sort of problem, I'll make chain
public.

Jonathan

------------------

#include <windows.h>
#include <fstream>
#include <iostream>
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/detail/chain.hpp>
#include <boost/iostreams/filter/newline_filter.hpp>
#include <boost/iostreams/filtering_stream.hpp>

struct debug_out_sink_impl : boost::iostreams::sink
{
    void write(const char* s, std::streamsize n)
    {
        std::string str(s, n);
        OutputDebugStringA(str.c_str());
    }
};

struct debug_out_sink
    : boost::iostreams::detail::chain<boost::iostreams::output>
{
    debug_out_sink ()
    {
        using namespace boost::iostreams;
        push(newline_filter(newline::windows));
        push(debug_out_sink_impl());
    }
};

struct tee : boost::iostreams::multichar_output_filter {
    tee(std::ostream& dest) : dest(dest) { }

    template<typename Sink>
    void write(Sink& snk, const char* s, std::streamsize n)
    {
        // Write to the downstream Sink
        boost::iostreams::write(snk, s, n);

        // Write to the stored ostream:
        dest.write(s, n);
    }

    std::ostream& dest;
};

int main()
{
    using namespace std;
    using namespace boost::iostreams;
    filtering_ostream out;
    std::ofstream log("C:/log.txt");
    debug_out_sink dbosink;
    out.push(tee(log));
    out.push(tee(std::cout));
    out.push(dbosink);
    out << "LINE ONE" << endl
        << "Next line" << endl
        << "third line" << endl;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk