
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; }