1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
|
#include <iostream>
#include <windows.h>
#include <cstdlib>
#include <sstream>
#include <string>
#include <cstdio>
namespace utility
{
template < typename C, typename T = std::char_traits<C> >
struct basic_teebuf : public std::basic_streambuf<C,T>
{
typedef std::basic_streambuf<C,T> streambuf_type;
typedef typename T::int_type int_type;
basic_teebuf( streambuf_type* buff_a, streambuf_type* buff_b )
: first(buff_a), second(buff_b) {}
protected:
virtual int_type overflow( int_type c )
{
const int_type eof = T::eof() ;
if( T::eq_int_type( c, eof ) ) return T::not_eof(c) ;
else
{
const typename T::char_type ch = T::to_char_type(c) ;
return T::eq_int_type( first->sputc(ch), eof ) ||
T::eq_int_type( second->sputc(ch), eof ) ? eof : c ;
}
}
virtual int sync() { return !first->pubsync() && !second->pubsync() ? 0 : -1 ; }
private:
streambuf_type* first ;
streambuf_type* second ;
};
typedef basic_teebuf<char> teebuf;
}
int main()
{
// set up a tee to also send output of stdout to a string buffer
std::stringbuf sbuf( std::ios_base::out ) ;
std::streambuf* const oldbuf = std::cout.rdbuf() ;
utility::teebuf tbuf( oldbuf, &sbuf ) ;
std::cout.rdbuf( &tbuf ) ;
// and some output from this program
std::cout << "line #1: " << 1234 << '\n'
<< "line #2: " << 56.78 << '\n'
<< "line #3: " << 999 << ' ' << 999.999 << '\n' << std::flush ;
std::cout << "press enter to continue... " ;
std::cin.get() ;
std::system( "cls && dir /OS" ) ; // clear the screen and send some fresh (external) output to the console
std::cout << "------ output from this program through std::cout ----\n" << std::flush ; // and some output from this program (std::cout)
std::puts( "------ and some more output from this program using cstdio ----" ) ; // and some more output from this program (cstdio)
std::cout.rdbuf(oldbuf) ; // restore old behaviour of cout
const HANDLE h_stdout = ::GetStdHandle(STD_OUTPUT_HANDLE) ;
if( h_stdout != INVALID_HANDLE_VALUE )
{
const std::size_t NROWS = 40 ;
const std::size_t NCOLS = 120 ;
::CHAR_INFO buffer[NROWS][NCOLS] ; // NROWSxNCOLS
// read the *current* console screen contents into the buffer (read what is currently in the console)
::SMALL_RECT rect {0,0,NCOLS-1,24} ; // the console screen (buffer) region to read from (120x25)
if( ::ReadConsoleOutput( h_stdout, buffer[0], {NCOLS,NROWS} /*buffer size colsxrows*/, {0,0} /*buffer top,left*/, &rect ) )
{
// retrieve the *current* text in the console into a string. note: use the contents of the updated rect
std::string console_text ;
for( std::size_t row = rect.Top ; row <= rect.Bottom ; ++row )
for( std::size_t col = rect.Left ; col <= rect.Right ; ++col ) console_text += buffer[row][col].Char.AsciiChar ;
std::cout << "\n\n---------------------\nstring retrieved through ReadConsoleOutput\n---------------------\n" << console_text ;
}
}
const std::string tee_text = sbuf.str() ; // retrieve the string from the string buffer (gets what was written using std::cout)
std::cout << "\n\n---------------------\nstring retrieved from the teed string stream\n---------------------\n" << tee_text ;
}
|