|
Debug Stream
Submitted by |
When I saw John Raptis' "C++ Console" posting, I decided to post this
code that I've had kicking around. It subclasses std::ostream into
'dbgstream', implementing iostream style output to the windows
OutputDebugString API.
Included is a sample main() showing usage, but usage is pretty simple:
just '#include' the header file and declare a dbgstream object. You can
then use it just like any other iostream.
This code can be used as a jumping off point for all kinds of std::ostream
redirection -- changing it to append output to a log window would be
trivial.
I also have a version of this code which works with UNIX syslog, anyone
interested in that code should contact me.
The code compiles with VC++5, using the included STL. It should compile
with STLport as well (the UNIX version of the code does ;-).
|
Currently browsing [dbgstream.zip] (2,412 bytes) - [dbgstream.h] - (3,390 bytes)
/*
** File: dbgstream.h -- header file for debugger/console stream
*/
#ifndef _H_DBGSTREAM_
#define _H_DBGSTREAM_
#include <ostream>
#include <string>
/// The following text and the ideas from it are from Dietmar Kuehl.
// <!! Copyright (C) 1997 Dietmar Kuehl >
// <!! Universitaet Konstanz, Germany, Lehrstuhl fuer praktische >
// <!! Informatik I >
// I'm not sure if the assertion is correct with "modern" Std C++ libraries,
// but It's a simple thing to keep in the code ;-)
// -----------------------------------------------------------------------------
// To get the order of construction and destruction straight I use a
// technique presented to me by Ron Klatchko (ron@crl.com): It would
// be cleaner to construct the 'streambuf' before the 'ostream is
// constructed (and destruction correspondingly in the reverse order)
// but bases are constructed prior to members. Thus, Ron came up with
// the idea to use a private base class, becoming the left most base
// class, containing the corresponding member: This yields the desired
// order of construction. I called this technique "Ron's Member".
/// This class is a utility class to avoid problems with stupid compilers.
/// see header file for details.
template <class T>
struct PBase // Ron's member
{
T sbuf;
PBase() { }
};
// This class implements a stream buffer for outputting to the win32
// debugging console.
/*!
The dbgbuf class is used by the dbgstream class to manage output
to OutpuDebugString() and to a 'tee' stream. The 'tee' stream can
be any std::ostream object. It's important to note that a pointer
to the tee ostream is kept inside this object, so it should not
be deleted until the dbgbuf object is no longer in use. (the dbgbuf
object does not try to copy the ostream object).
Messages are sent to the debugger and the tee stream when a newline
character is seen. Any leftover characters in the buffer will be output
when the object is destroyed.
This class is not normally used by itself, it is usually attached to
a dbgstream object.
*/
class dbgbuf : public std::streambuf {
private:
std::string msg; ///< buffer for current log message
std::ostream *tee; ///< if != 0, send output here, also.
/// internal function used to direct output to syslog and (optionally)
/// to the tee stream.
void flushMsg();
public:
/// constructor.
dbgbuf() : tee(0) { };
/// Destructor. No magic here.
~dbgbuf();
/// Set a stream to be used as an additional output. Messages are
/// directed to this stream as well as to syslog().
std::ostream *setTee(std::ostream *_tee);
protected:
/// streambuf implementation.
virtual int overflow(int ch);
private:
dbgbuf(dbgbuf const &); // disallow copy construction
void operator= (dbgbuf const &); // disallow copy assignment
};
/// dbgstream objects provide ostream functionality for dbgbuf
/// objects.
class dbgstream :
private PBase<dbgbuf>,
public std::basic_ostream<char,std::char_traits<char> >
{
public:
/// Constructor.
explicit dbgstream() :
std::basic_ostream<char,std::char_traits<char> > (&sbuf)
{ }
/// set tee object. Reflects to underlying stream buffer object.
std::ostream *setTee(std::ostream *_tee) {
return sbuf.setTee(_tee);
}
};
extern dbgstream dbg;
#endif /* _H_DBGSTREAM_ */
|
|
Currently browsing [dbgstream.zip] (2,412 bytes) - [dbgstream.cpp] - (1,183 bytes)
/*
** file: dbgstream.cpp -- debugging stream
*/
#include "dbgstream.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <fstream>
#ifdef DBG_TIMESTAMP
extern "C" {
#include <time.h>
};
#endif /* DBG_TIMESTAMP */
using namespace std;
dbgbuf::~dbgbuf()
{
flushMsg();
}
void dbgbuf::flushMsg()
{
if (msg.length() > 0) {
#if DBG_TIMESTAMP
char tbuf[64];
time_t t = time(0);
struct tm tm;
tm = *localtime(&t);
strftime(tbuf,sizeof(tbuf),"%b %d %R:%S",&tm);
OutputDebugStringA(tbuf);
OutputDebugStringA(":");
if (tee) {
(*tee) << tbuf << ": ";
}
#endif /* DBG_TIMESTAMP */
OutputDebugStringA(msg.c_str());
OutputDebugStringA("\n");
if (tee) {
(*tee) << msg << endl << flush;
}
msg.erase(); // erase message buffer
}
}
std::ostream *dbgbuf::setTee(std::ostream *_tee)
{
std::ostream *otee = tee;
tee = _tee; return otee;
}
int dbgbuf::overflow(int c)
{
if (c == '\n') {
flushMsg();
} else {
msg += c;
}
return c == -1 ? -1 : ' ';
}
#ifdef TEST_MAIN
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
dbgstream dbg;
dbg << "Hello, World." << endl;
return 0;
}
#endif /* TEST_MAIN */
|
|
The zip file viewer built into the Developer Toolbox made use
of the zlib library, as well as the zlibdll source additions.
|