// message_handler_log.h #ifndef MESSAGE_HANDLER_LOG_H #define MESSAGE_HANDLER_LOG_H #include <ostream> #include <sstream> #include <memory> #include <assert.h> // forward declaration(s) template< class char_type, class traits_type = std::char_traits< char_type> > class basic_message_handler_log; // represents the stream buffer for a message_handler_log (see below) // Note: NOT thread-safe template< class char_type , class traits_type = std::char_traits< char_type> > class basic_message_handler_log_streambuf : public std::basic_streambuf< char_type, traits_type> { private: typedef basic_message_handler_log_streambuf< char_type, traits_type> this_class; friend class basic_message_handler_log< char_type, traits_type>; typedef std::basic_streambuf< char_type, traits_type> streambuf_type; typedef basic_message_handler_log< char_type, traits_type> ostream_type; // base class typedef std::basic_streambuf< char_type, traits_type> base_class; enum { _BADOFF = -1 /* bad offset - for positioning functions */ }; #ifndef __GNUC__ using typename base_class::int_type; using typename base_class::pos_type; using typename base_class::off_type; #endif protected: // input, not allowed virtual int_type pbackfail(int_type = traits_type::eof()) { // only for output, not for input assert( false); return (traits_type::eof()); } virtual int showmanyc() { // only for output, not for input assert( false); return 0; } virtual int_type underflow() { // only for output, not for input assert( false); return (traits_type::eof()); } virtual int_type uflow() { // only for output, not for input assert( false); return (traits_type::eof()); } virtual std::streamsize xsgetn(char_type *, std::streamsize) { // only for output, not for input assert( false); return 0; } // positioning, not allowed - we're a log virtual pos_type seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode = std::ios_base::in | std::ios_base::out) { // we don't allow positioning assert( false); return (std::streampos( _BADOFF)); } virtual pos_type seekpos(pos_type, std::ios_base::openmode = std::ios_base::in | std::ios_base::out) { // we don't allow positioning assert( false); return (std::streampos( _BADOFF)); } // output functions // called to write out from the internal // buffer, into the external buffer virtual int sync() { m_pOwnerStream->on_new_message( get_stream_buffer().str() ); m_pStreamBuffer = std::auto_ptr< string_stream_type>( new string_stream_type); return 0; } virtual streambuf_type *setbuf( char_type * buffer, std::streamsize n) { // ... note: this function MUST be called // before working with this stream buffer // we don't use a buffer - we forward everything assert( buffer == NULL && n == 0); this->setp( NULL, NULL); return this; } // write the characters from the buffer // to their real destination virtual int_type overflow(int_type nChar = traits_type::eof()) { if ( traits_type::not_eof( nChar)) get_stream_buffer() << ( char_type)nChar; return traits_type::not_eof( nChar); } virtual std::streamsize xsputn(const char_type *S, std::streamsize N) { get_stream_buffer().write( S, N); return N; } public: basic_message_handler_log_streambuf() : m_pStreamBuffer( new string_stream_type), m_bLastMessageWritten( false) {} basic_message_handler_log_streambuf( const this_class & ) : m_pStreamBuffer( new string_stream_type), m_bLastMessageWritten( false) {} ~basic_message_handler_log_streambuf() { // from your basic_message_handler_log' // derived class' destructor, make sure you call // 'write_last_message( *this);' !!! assert( m_bLastMessageWritten); } private: typedef std::basic_ostringstream< char_type> string_stream_type; string_stream_type & get_stream_buffer() { return *m_pStreamBuffer; } template< class type> void process_last_message( type & val) { if ( m_bLastMessageWritten) return; m_bLastMessageWritten = true; val.on_last_message( get_stream_buffer().str()); } private: // holds the Message, until it's flushed std::auto_ptr< string_stream_type> m_pStreamBuffer; // the Message Handler Log - where we write into ostream_type * m_pOwnerStream; // has the last message been written? // if this is false, the last sync() has not been done. bool m_bLastMessageWritten; }; // derive your class from this, and implement the PROTECTED on_new_message function template< class char_type, class traits_type > class basic_message_handler_log : public std::basic_ostream< char_type, traits_type> { typedef basic_message_handler_log_streambuf< char_type, traits_type> handler_streambuf_type; friend class basic_message_handler_log_streambuf< char_type, traits_type>; typedef std::basic_ostream< char_type, traits_type> base_class; typedef std::basic_ostringstream< char_type> string_stream_type; protected: typedef std::basic_string< char_type> string_type; basic_message_handler_log() : m_StreamBuf(), base_class( NULL) { m_StreamBuf.m_pOwnerStream = this; this->init( &m_StreamBuf); m_StreamBuf.pubsetbuf( NULL, 0); } basic_message_handler_log( const basic_message_handler_log< char_type, traits_type> & from) : m_StreamBuf(), base_class( NULL) { m_StreamBuf.m_pOwnerStream = this; this->init( &m_StreamBuf); m_StreamBuf.pubsetbuf( NULL, 0); } // from your derived class' destructor, make sure you call // 'write_last_message( *this);' !!! virtual ~basic_message_handler_log() {} protected: virtual void on_new_message( const string_type & str) = 0; void on_last_message( const string_type & str) { // default behavior on_new_message( str); } template< class type> void write_last_message( type & val) { m_StreamBuf.process_last_message( val); } public: // our stream buffer handler_streambuf_type m_StreamBuf; }; typedef basic_message_handler_log< char> message_handler_log; typedef basic_message_handler_log< wchar_t> wmessage_handler_log; #endif |