Thread: "Spying" on cout

  1. #1
    Registered User
    Join Date
    Nov 2006
    Posts
    12

    "Spying" on cout

    I've been trying to figure out how to redirect and split cout so that I can inspect it. Basically, there is some code that already uses cout that I do not want to modify, but I want to be able to process what is being output to cout, without stopping it from going to cout.

    I have found a usenet post that seems appropriate for my problem. However, I am having some difficulty using it. I am fairly new to C++, although not to programming in general, so it may just be syntax trouble.

    The method described in that post shows how to redirect cout to another stream using rdbuf. It also gives code for a "teebuf," which is designed to split a stream into two other streams.

    I am getting compile errors when I use the teebuf code provided:
    Code:
     #include <streambuf>
      class teebuf: public std::streambuf {
      public:
        typedef std::char_traits<char> traits_type;
        typedef traits_type::int_type  int_type;
    
        teebuf(std::streambuf* sb1, std::streambuf* sb2):
          m_sb1(sb1), m_sb2(sb2) {}
      private:
        int_type overflow(int_type c) {
          if (!traits_type::eq_int_type(c, traits_type::eof()) {
            c = sb1->sputc(c);
            if (!traits_type::eq_int_type(c, traits_type::eof()))
              c = sb2->overflow(c);
            return c;
          }
          else
            return traits_type::not_eof(c);
        }
        int sync() {
          int rc = sb1->sync();
          if (rc != -1)
            rc = sb2->sync();
          return rc;
        }
      };
    The problem seems to be related to the use of m_sb1 and m_sb2 in the constructor. I have tried adding private fields of type streambuf* with those two names. I then needed to change the references to sb1 and sb2 in the other parts of the code to m_sb1 and m_sb2. However, this results in three C2248 errors:

    error C2248: 'std::basic_streambuf<_Elem,_Traits>::overflow' : cannot access protected member declared in class 'std::basic_streambuf<_Elem,_Traits>'
    with
    [
    _Elem=char,
    _Traits=std::char_traits<char>
    ]
    and
    [
    _Elem=char,
    _Traits=std::char_traits<char>
    ]
    The other two errors are the same with sync instead of overflow.

    Does anyone have any idea what the correct way would be to fix this teebuf code? Or is it correct already but I am just using it wrong? Also, any other ways to solve my overall problem would be appreciated. Thanks.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Code:
    TEE(1)                           User Commands                          TEE(1)
    
    NAME
           tee - read from standard input and write to standard output and files
    
    SYNOPSIS
    If you're on Linux / Unix, you can just use a 'tee'
    myprog | tee
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Nov 2006
    Posts
    12
    Thanks for your reply. Unfortunately, it does not quite work in this situation. I am actually not trying to output to a file. I just want to be able to look at each character (or string, possibly), as it is printed. Some type of onPrint(char c) function or even onPrintLine(char[] line) would be ideal. I am creating a file that will be linked with existing code and run by a process already in place, so I cannot change the command line used to run the program.

    Sorry for all of these additional restrictions. If I cannot figure it out this way, I will look into getting the code that we already have deployed modified to provide a more detailed interface so I don't have to look at cout.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Is this within the program itself (I'm confused, you said you couldn't modify the code)?

    Even if it's not 'tee', you can still manipulate the streams from the outside in other ways similar to pipes.

    Also, say which OS / Compiler you're using.

    I'm guessing that the teebuf thing might be compiler specific, and that you need to fiddle it to make it work for you.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    carry on JaWiB's Avatar
    Join Date
    Feb 2003
    Location
    Seattle, WA
    Posts
    1,972
    I don't think you need to directly call overflow or sync on your class members (I'm less sure about the latter--and I don't think you even need to define a sync function unless you're buffering the output)

    Something like this might work:
    Code:
    #include <iostream>
    #include <fstream>
    #include <streambuf>
    
    template <class charT, class destbuf_type = std::streambuf, class srcbuf_type = std::streambuf, class traits = std::char_traits<charT> >
    class copy_outbuf: public std::basic_streambuf<charT, traits>
    {
    public:
      copy_outbuf(srcbuf_type* src, destbuf_type* dest):m_srcBuf(src),m_destBuf(dest){}
    protected:
      virtual int_type overflow(int_type c)
      {
        if (!traits::eq_int_type(c,traits::eof()))
        {
          if (m_srcBuf->sputc(c) == traits::eof()) //error occurred
            return traits::eof();
          if (m_destBuf->sputc(c) == traits::eof())
            return traits::eof();
        }
        return traits::not_eof(c);
      }
      virtual std::streamsize xsputn(const charT* s, std::streamsize num)
      {
        std::streamsize written = m_srcBuf->sputn(s,num);
        m_destBuf->sputn(s,written);
        return written;
      }
    private:
      srcbuf_type* m_srcBuf;
      destbuf_type* m_destBuf;
    };
    
    int main()
    {
      std::ofstream outfile("test.txt");
      copy_outbuf<char> new_buf(std::cout.rdbuf(),outfile.rdbuf());
      std::cout.rdbuf(&new_buf);
      std::cout<<"Hello World!";
      std::cout<<'h';
    }
    "Think not but that I know these things; or think
    I know them not: not therefore am I short
    Of knowing what I ought."
    -John Milton, Paradise Regained (1671)

    "Work hard and it might happen."
    -XSquared

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. class methods to cout stream
    By shintaro in forum C++ Programming
    Replies: 5
    Last Post: 11-11-2008, 07:27 PM
  2. cout
    By RenderedAwake in forum C++ Programming
    Replies: 5
    Last Post: 02-03-2005, 07:14 AM
  3. How Does cout Work
    By jrahhali in forum C++ Programming
    Replies: 8
    Last Post: 08-25-2004, 03:19 PM
  4. cout vs std::cout
    By none in forum C++ Programming
    Replies: 10
    Last Post: 07-26-2004, 11:20 PM
  5. FAQ cout
    By evilmonkey in forum FAQ Board
    Replies: 1
    Last Post: 10-07-2001, 11:32 AM