Thread: Cout redirection problem

  1. #1
    C++ Programmer
    Join Date
    Aug 2005
    Posts
    39

    Cout redirection problem

    Hi,

    I'm redirecting cout output to a TextView, but I've a strange problem.

    I'm setting up the cout redirection in my constructor of my Window object (I'm using GTKmm as UI lib, in combination with Glademm)
    Code:
    	// Set up our own stream buffer
    	// First get the text buffer from the TextView
    	Gtk::TextView * textview = 0;
    	this -> glade_ref -> get_widget("txtLog", textview);
    
    	this -> stream_buffer = new TextViewStreamBuffer<char>;
    	this -> stream_buffer -> set_text_buffer(textview -> get_buffer());
    	std::cout.rdbuf(dynamic_cast<std::streambuf *>(this -> stream_buffer));
    This is my custom cout streambuf:
    Code:
    /**
     * DLDI GUI Patcher for Linux
     *
     * This program is an easy to use GUI to patch multiple files at once,
     * created with GTKmm and intended voor Linux users
     *
     * Created by Lucas van Dijk, using an modified version of dldi source,
     * by Michael Chisholm (Chishm)
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation; either version 2 of the License, or
     * (at your option) any later version.
     *
     * @author Lucas van Dijk
     * @author Micheal Chisholm
     * @version $Id$
     * @license http://www.opensource.org/licenses/gpl-license.php
     */
    
    #ifndef TEXTVIEWSTREAM_H_INCLUDED
    #define TEXTVIEWSTREAM_H_INCLUDED
    
    #include "stdinc.h"
    
    template <class charT = char, class traits = std::char_traits<charT> >
    class TextViewStreamBuffer : public std::basic_streambuf<charT, traits>
    {
    	protected:
    		// Members
    		Glib::RefPtr<Gtk::TextBuffer> buffer;
    
    		/**
    		 * This functions gets called when the << operator is used, and so we want to put the contents
    		 * in our TextView.
    		 */
    		std::streamsize xsputn(const charT * text, std::streamsize length)
    		{
    			if (this -> buffer)
    			{
    				this -> buffer -> insert(this -> buffer -> end(), Glib::ustring(text));
    
    				return static_cast<std::streamsize>(this -> buffer -> size());
    			}
    			else
    			{
    				return 0;
    			}
    		}
    
    	public:
    		TextViewStreamBuffer() : buffer(0) { }
    
    		/**
    		 * Sets our text buffer so we know what textview we need to use
    		 * @param buffer The TextBuffer object of the TextView
    		 */
    		void set_text_buffer(Glib::RefPtr<Gtk::TextBuffer> buffer)
    		{
    			this -> buffer = buffer;
    		}
    };
    
    #endif
    But now my problem, it quits redirecting after two cout's. I see to lines of cout's in my TextView, but there should be much more.

    here is a piece of code where I cout:
    Code:
    	// Iterate through all files
    	for(unsigned int i = 0; i < files.size(); i++)
    	{
    		// Get extension
    		std::string::size_type dot_position = files[i].find_last_of('.');
    
    		if(dot_position == std::string::npos)
    		{
    			// It's a directory, skip it
    			continue;
    		}
    
    		std::string extension = files[i].substr(dot_position, files[i].length());
    
    		// If it's al DLDI File...
    		if(extension == ".dldi")
    		{
    			// .. load it and add it to the combobox
    			DLDIFile * dldi_file = new DLDIFile(files[i]);
    
    			this -> dldi_files.push_back(dldi_file);
    
    			std::cout << "Found DLDI File, Driver name: " << files[i] << "fdg" << std::endl;
    
    			// Add to combo
    			row = *(this -> combo_model -> append());
    			row[this -> columns.text] = dldi_file -> get_driver_name();
    		}
    	}
    This function (it's not the complete function), iterates through all files, and adds all files with the .dldi extension to a combobox. It also cout something, so something is shown up in the log.

    There are 3 files in my directory, so in my log, there should be 3 times
    Found DLDI File, Driver name: {filename}
    But, there is only one, and 'fdg' doesn't show up too.

    Any ideas why it's acting so strange?

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    I have never tried redirecting cout, nor have I ever done any Gnome programming, so all I can help you with are my googling skills, such as they are . . . .

    Anyway, googling for "cout textview" gives you this page: http://mail.gnome.org/archives/gtkmm.../msg00104.html

    It's not very useful, but as this thread has no relies I thought I'd post it anyway.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    C++ Programmer
    Join Date
    Aug 2005
    Posts
    39
    Lol, that's me xD

    Still strange, it only adds the first two cout's to the log :/

  4. #4
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Lol, that's me xD
    Now that's funny. I guess it won't help you very much then.

    Hmm, well, I can only suggest some basic debugging.
    Code:
    std::cout.rdbuf(dynamic_cast<std::streambuf *>(this -> stream_buffer));
    Does this work if you use an ofstream's rdbuf()? What about if you take the source code from the standard library for std::streambuf? Then what happens if you modify your version of std::streambuf to also echo to a file?

    But I think that there is something stranger going on here.
    Code:
    std::cout << "Found DLDI File, Driver name: " << files[i] << "fdg" << std::endl;
    Code:
    Found DLDI File, Driver name: {filename}
    But, there is only one, and 'fdg' doesn't show up too.
    "Found..." as well as files[i] show up, right? So it's not like this would solve the problem:
    Code:
    std::cout << "Found DLDI File, Driver name: ";
    std::cout << files[i];
    std::cout << "fdg";
    std::cout << std::endl;
    because your cout works for at least two objects.

    Have you completely rebuilt your project? It sounds like something may not be getting compiled, but that's just a wild guess.

    [edit] I had another thought. It crashes right after printing files[i], right? Well, I'm going to guess that everything else you have printed was a string literal like "Found" of type const char*, but I don't think that files[i] is a const char *. Could it be that your cout always crashes when trying to print a variable of whatever type files[i] is? [/edit]
    Last edited by dwks; 06-03-2007 at 12:14 PM.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  5. #5
    C++ Programmer
    Join Date
    Aug 2005
    Posts
    39
    Quote Originally Posted by dwks View Post
    Now that's funny. I guess it won't help you very much then.

    Hmm, well, I can only suggest some basic debugging.
    Code:
    std::cout.rdbuf(dynamic_cast<std::streambuf *>(this -> stream_buffer));
    Does this work if you use an ofstream's rdbuf()? What about if you take the source code from the standard library for std::streambuf? Then what happens if you modify your version of std::streambuf to also echo to a file?

    But I think that there is something stranger going on here.
    Code:
    std::cout << "Found DLDI File, Driver name: " << files[i] << "fdg" << std::endl;
    "Found..." as well as files[i] show up, right? So it's not like this would solve the problem:
    Code:
    std::cout << "Found DLDI File, Driver name: ";
    std::cout << files[i];
    std::cout << "fdg";
    std::cout << std::endl;
    because your cout works for at least two objects.

    Have you completely rebuilt your project? It sounds like something may not be getting compiled, but that's just a wild guess.

    [edit] I had another thought. It crashes right after printing files[i], right? Well, I'm going to guess that everything else you have printed was a string literal like "Found" of type const char*, but I don't think that files[i] is a const char *. Could it be that your cout always crashes when trying to print a variable of whatever type files[i] is? [/edit]
    I've tried to cout something else than files[i] (just plain text), but the same happened. I also completely rebuild my project, but with the same result.

    I've also redirected my cout to a ofstream, and that works perfectly.
    Last edited by MrLucky; 06-05-2007 at 03:17 AM.

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Override all virtuals that streambuf provides and write something to cerr from each one, to find out which ones are called. In my experience, the very minimum any streambuf must override is overflow()+sync()/underflow(), depending on its direction.

    I once wrote a streambuffer that wrote the data to Win32 message boxes.
    Code:
    namespace watson {
    	namespace internal {
    		template <typename C> void box(const C *s, const C *t) {
    			messageBox(0, s, t, 0);
    		}
    	}
    
    	template <typename E, typename T = std::char_traits<E> >
    	class basic_boxstreambuf : public std::basic_streambuf<E, T> {
    		typedef std::vector<E> string_type;
    		string_type obuf;
    		string_type ibuf;
    		typename string_type::iterator opos;
    		std::basic_string<E, T> title;
    
    	protected:
    		char_type *epptr() const {
    			return obuf.empty() ? 0 : (&obuf[0]) + obuf.size();
    		}
    		char_type *pbase() {
    			return obuf.empty() ? 0 : &obuf[0];
    		}
    		char_type *pptr() const {
    			return opos == obuf.end() ? 0 : &*opos;
    		}
    		std::streamsize xsputn(const char_type *p, std::streamsize n) {
    			for(std::streamsize i = 0; i < n; ++i) {
    				obuf.push_back(p[i]);
    			}
    			return n;
    		}
    		int_type overflow(int_type i = traits_type::eof()) {
    			if(i != traits_type::eof()) {
    				obuf.push_back(traits_type::to_char_type(i));
    			}
    			return traits_type::not_eof(i);
    		}
    		int sync() {
    			obuf.push_back(0);
    			internal::box(&obuf[0], title.c_str());
    			obuf.clear();
    			return 0;
    		}
    
    	public:
    		basic_boxstreambuf(const std::basic_string<E, T> &t)
    			: title(t)
    		{
    			setbuf(0, 0);
    		}
    		void set_title(const std::basic_string<E, T> &t) {
    			title = t;
    		}
    	};
    }
    messageBox is a very thin wrapper around MessageBox. Note that this stream is peculiar in that it only prints data when it is explicitly flushed. The reason is obvious: printing involves popping up a message box, and allowing that to happen at any time would split the data in weird ways.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    C++ Programmer
    Join Date
    Aug 2005
    Posts
    39
    Well, I finally managed to get it to work

    I've found after some long searching this tutorial, and complete rewrote my streambuf.

    This is my final code:
    textviewbuffer.h
    Code:
    /**
     * DLDI GUI Patcher for Linux
     *
     * This program is an easy to use GUI to patch multiple files at once,
     * created with GTKmm and intended voor Linux users
     *
     * Created by Lucas van Dijk, using an modified version of dldi source,
     * by Michael Chisholm (Chishm)
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation; either version 2 of the License, or
     * (at your option) any later version.
     *
     * @author Lucas van Dijk
     * @version $Id$
     * @license http://www.opensource.org/licenses/gpl-license.php
     */
    
    #ifndef TEXTVIEWSTREAM_H_INCLUDED
    #define TEXTVIEWSTREAM_H_INCLUDED
    
    #include "stdinc.h"
    #include <streambuf>
    
    using std::size_t;
    
    class TextViewStreamBuffer : public std::streambuf
    {
    	protected:
    		Glib::RefPtr<Gtk::TextBuffer> textview_buf;
    		std::vector<char> buffer;
    
    	public:
    		explicit TextViewStreamBuffer(Glib::RefPtr<Gtk::TextBuffer> textview, size_t buffer_size = 256);
    
    	protected:
    		virtual int_type overflow(int_type character);
    		virtual int sync();
    
    		virtual bool write_to_buffer();
    };
    
    #endif
    textviewbuffer.cpp
    Code:
    /**
     * DLDI GUI Patcher for Linux
     *
     * This program is an easy to use GUI to patch multiple files at once,
     * created with GTKmm and intended voor Linux users
     *
     * Created by Lucas van Dijk, using an modified version of dldi source,
     * by Michael Chisholm (Chishm)
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation; either version 2 of the License, or
     * (at your option) any later version.
     *
     * @author Lucas van Dijk
     * @author Micheal Chisholm
     * @version $Id$
     * @license http://www.opensource.org/licenses/gpl-license.php
     */
    
    #include "../include/textviewstream.h"
    
    TextViewStreamBuffer::TextViewStreamBuffer(Glib::RefPtr<Gtk::TextBuffer> textview, size_t buffer_size) : textview_buf(textview), buffer(buffer_size + 1)
    {
    	char * base = &this -> buffer.front();
    	this -> setp(base, base + this -> buffer.size() - 1);
    }
    
    TextViewStreamBuffer::int_type TextViewStreamBuffer::overflow(int_type character)
    {
    	if(character != traits_type::eof())
    	{
    		if(this -> pptr() < this -> epptr())
    		{
    			*(this -> pptr()) = character;
    			this -> pbump(1);
    
    			if(this -> write_to_buffer())
    			{
    				return character;
    			}
    		}
    	}
    
    	return traits_type::eof();
    }
    
    int TextViewStreamBuffer::sync()
    {
    	return this -> write_to_buffer() ? 0 : -1;
    }
    
    bool TextViewStreamBuffer::write_to_buffer()
    {
    	this -> textview_buf -> insert(this -> textview_buf -> end(), pbase(), pptr());
    
    	this -> pbump(-(this -> pptr() - this -> pbase()));
    	return true;
    }
    Thanks all for your help

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. A question related to strcmp
    By meili100 in forum C++ Programming
    Replies: 6
    Last Post: 07-07-2007, 02:51 PM
  2. Getline problem
    By ktar89 in forum C++ Programming
    Replies: 3
    Last Post: 06-24-2007, 06:47 AM
  3. cout problem with windows API
    By xximranxx in forum Windows Programming
    Replies: 2
    Last Post: 05-04-2007, 12:37 AM
  4. WS_POPUP, continuation of old problem
    By blurrymadness in forum Windows Programming
    Replies: 1
    Last Post: 04-20-2007, 06:54 PM
  5. Weird Problem
    By Xeavor in forum C++ Programming
    Replies: 14
    Last Post: 11-20-2004, 11:23 AM