I want to use this snippet from Mr-Edd\'s iostreams article to print std::clog somewhere.
#include
#include
#include
I think you want to pull the text from the ostream while it's not empty. You could do something like this:
std::string s = oss.str();
if(!s.empty()) {
// output s here
oss.str(""); // set oss to contain the empty string
}
Let me know if this isn't what you wanted.
Of course, the better solution is to remove the middle man and have a new streambuf go wherever you really want it, no need to probe later. something like this (note, this does it for every char, but there is plenty of buffering options in streambufs as well):
class outbuf : public std::streambuf {
public:
outbuf() {
// no buffering, overflow on every char
setp(0, 0);
}
virtual int_type overflow(int_type c = traits_type::eof()) {
// add the char to wherever you want it, for example:
// DebugConsole.setText(DebugControl.text() + c);
return c;
}
};
int main() {
// set std::cout to use my custom streambuf
outbuf ob;
std::streambuf *sb = std::cout.rdbuf(&ob);
// do some work here
// make sure to restore the original so we don't get a crash on close!
std::cout.rdbuf(sb);
return 0;
}
I needed to grab outputs to std::cout and std::cerr from third party libraries and log them using log4cxx, and still retaining the original outputs.
This is what I came up with. It's pretty straight-forward:
I replace the old buffer of an ostream (like std::cout) with my own class so that I get access to what ever is written to it.
I also create a new std::ostream object with the old buffer so that I can continue to get the output to my console, besides sending it to my logger. Which I find kind of handy.
Code:
class intercept_stream : public std::streambuf{
public:
intercept_stream(std::ostream& stream, char const* logger):
_logger(log4cxx::Logger::getLogger(logger)),
_orgstream(stream),
_newstream(NULL)
{
//Swap the the old buffer in ostream with this buffer.
_orgbuf=_orgstream.rdbuf(this);
//Create a new ostream that we set the old buffer in
boost::scoped_ptr<std::ostream> os(new std::ostream(_orgbuf));
_newstream.swap(os);
}
~intercept_stream(){
_orgstream.rdbuf(_orgbuf);//Restore old buffer
}
protected:
virtual streamsize xsputn(const char *msg, streamsize count){
//Output to new stream with old buffer (to e.g. screen [std::cout])
_newstream->write(msg, count);
//Output to log4cxx logger
std::string s(msg,count);
if (_logger->isInfoEnabled()) {
_logger->forcedLog(::log4cxx::Level::getInfo(), s, LOG4CXX_LOCATION);
}
return count;
}
private:
log4cxx::LoggerPtr _logger;
std::streambuf* _orgbuf;
std::ostream& _orgstream;
boost::scoped_ptr<std::ostream> _newstream;
};
Then to use it:
std::cout << "This will just go to my console"<<std::endl;
intercept_stream* intercepter = new intercept_stream(std::cout, "cout");
std::cout << "This will end up in both console and my log4cxx logfile, yay!" << std::endl;
I encourage you to look at Boost.IOStreams. It seems to fit your use-case nicely, and using it is surprisingly simple:
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <iostream>
namespace bio = boost::iostreams;
class MySink : public bio::sink
{
public:
std::streamsize write(const char* s, std::streamsize n)
{
//Do whatever you want with s
//...
return n;
}
};
int main()
{
bio::stream_buffer<MySink> sb;
sb.open(MySink());
std::streambuf * oldbuf = std::clog.rdbuf(&sb);
std::clog << "hello, world" << std::endl;
std::clog.rdbuf(oldbuf);
return 0;
}
For the log4cxx example you must override overflow() and sync() otherwise the badbit is always set after first stream is received.
See: http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/fd9d973282e0a402/a872eaedb142debc
InterceptStream::int_type InterceptStream::overflow(int_type c)
{
if(!traits_type::eq_int_type(c, traits_type::eof()))
{
char_type const t = traits_type::to_char_type(c);
this->xsputn(&t, 1);
}
return !traits_type::eof();
}
int InterceptStream::sync()
{
return 0;
}
If you just want to get the contents of the ostringstream, then use its str() member. For example:
string s = oss.str();