1 // Created by Lars Gullik Bjønnes
2 // Copyright 1999 Lars Gullik Bjønnes (larsbj@lyx.org)
3 // Released into the public domain.
5 // Primarily developed for use in the LyX Project http://www.lyx.org/
6 // but should be adaptable to any project.
8 //#define TEST_DEBUGSTREAM
10 //#include "DebugStream.h"
13 // Since the current C++ lib in egcs does not have a standard implementation
14 // of basic_streambuf and basic_filebuf we don't have to include this
16 #ifdef MODERN_STL_STREAMS
21 using std::streamsize;
26 ostream & operator<<(ostream & o, Debug::type t)
31 /** This is a streambuffer that never prints out anything, at least
32 that is the intention. You can call it a no-op streambuffer, and
33 the ostream that uses it will be a no-op stream.
35 class nullbuf : public streambuf {
38 virtual int sync() { return 0; }
40 virtual streamsize xsputn(char const *, streamsize n) {
41 // fakes a purge of the buffer by returning n
45 virtual int overflow(int c = EOF) {
46 // fakes success by returning c
47 return c == EOF ? ' ' : c;
51 /** A streambuf that sends the output to two different streambufs. These
52 can be any kind of streambufs.
54 class teebuf : public streambuf {
57 teebuf(streambuf * b1, streambuf * b2)
58 : streambuf(), sb1(b1), sb2(b2) {}
62 #ifdef MODERN_STL_STREAMS
64 return sb1->pubsync();
71 virtual streamsize xsputn(char const * p, streamsize n) {
72 #ifdef MODERN_STL_STREAMS
74 return sb1->sputn(p, n);
77 return sb1->xsputn(p, n);
81 virtual int overflow(int c = EOF) {
82 #ifdef MODERN_STL_STREAMS
87 return sb1->overflow(c);
98 class debugbuf : public streambuf {
101 debugbuf(streambuf * b)
102 : streambuf(), sb(b) {}
106 #ifdef MODERN_STL_STREAMS
107 return sb->pubsync();
113 virtual streamsize xsputn(char const * p, streamsize n) {
114 #ifdef MODERN_STL_STREAMS
115 return sb->sputn(p, n);
117 return sb->xsputn(p, n);
121 virtual int overflow(int c = EOF) {
122 #ifdef MODERN_STL_STREAMS
125 return sb->overflow(c);
133 /// So that public parts of DebugStream does not need to know about filebuf
134 struct DebugStream::debugstream_internal {
135 /// Used when logging to file.
139 /// Constructor, sets the debug level to t.
140 DebugStream::DebugStream(Debug::type t)
141 : ostream(new debugbuf(cerr.rdbuf())),
142 dt(t), nullstream(new nullbuf), internal(0) {}
145 /// Constructor, sets the log file to f, and the debug level to t.
146 DebugStream::DebugStream(char const * f, Debug::type t)
147 : ostream(new debugbuf(cerr.rdbuf())),
148 dt(t), nullstream(new nullbuf),
149 internal(new debugstream_internal)
151 internal->fbuf.open(f, ios::out|ios::app);
152 delete rdbuf(new teebuf(cerr.rdbuf(),
157 DebugStream::~DebugStream()
159 delete nullstream.rdbuf(0); // Without this we leak
160 delete rdbuf(0); // Without this we leak
165 /// Sets the debugstreams' logfile to f.
166 void DebugStream::logFile(char const * f)
169 internal->fbuf.close();
171 internal = new debugstream_internal;
173 internal->fbuf.open(f, ios::out|ios::app);
174 delete rdbuf(new teebuf(cerr.rdbuf(),
179 #ifdef TEST_DEBUGSTREAM
181 // Example debug stream
182 DebugStream debugstream;
184 int main(int, char **)
187 I have been running some tests on this to see how much overhead
188 this kind of permanent debug code has. My conclusion is: not
189 much. In all, but the most time critical code, this will have
190 close to no impact at all.
192 In the tests that I have run the use of
193 if (debugstream.debugging(DebugStream::INFO))
194 debugstream << "some debug\n";
195 has close to no overhead when the debug level is not
199 debugstream.debug(DebugStream::INFO) << "some debug\n";
200 is also very small when the debug level is not
201 DebugStream::INFO. However the overhead for this will increase
202 if complex debugging information is output.
204 The overhead when the debug level is DebugStream::INFO can be
205 significant, but since we then are running in debug mode it is
208 Why should we use this instead of the class Error that we already
209 have? First of all it uses C++ iostream and constructs, secondly
210 it will be a lot easier to output the debug info that we need
211 without a lot of manual conversions, thirdly we can now use
212 iomanipulators and the complete iostream formatting functions.
213 pluss it will work for all types that have a operator<<
214 defined, and can be used in functors that take a ostream & as
215 parameter. And there should be less need for temporary objects.
216 And one nice bonus is that we get a log file almost for
219 Some of the names are of course open to modifications. I will try
220 to use the names we already use in LyX.
222 // Just a few simple debugs to show how it can work.
223 debugstream << "Debug level set to Debug::NONE\n";
224 if (debugstream.debugging()) {
225 debugstream << "Something must be debugged\n";
227 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
228 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
229 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
230 debugstream.level(Debug::value("INFO"));
231 debugstream << "Setting debug level to Debug::INFO\n";
232 if (debugstream.debugging()) {
233 debugstream << "Something must be debugged\n";
235 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
236 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
237 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
238 debugstream.addLevel(Debug::type(Debug::CRIT |
240 debugstream << "Adding Debug::CRIT and Debug::WARN\n";
241 debugstream[Debug::WARN] << "more debug(WARN)\n";
242 debugstream[Debug::INFO] << "even more debug(INFO)\n";
243 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
244 debugstream.delLevel(Debug::INFO);
245 debugstream << "Removing Debug::INFO\n";
246 debugstream[Debug::WARN] << "more debug(WARN)\n";
247 debugstream[Debug::INFO] << "even more debug(INFO)\n";
248 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
249 debugstream.logFile("logfile");
250 debugstream << "Setting logfile to \"logfile\"\n";
251 debugstream << "Value: " << 123 << " " << "12\n";
254 // note: the (void*) is needed on g++ 2.7.x since it does not
255 // support partial specialization. In egcs this should not be
257 debugstream << "automatic " << &i
258 << ", free store " << p << endl;
261 for (int j = 0; j < 200000; ++j) {
263 tmp << "Test" << endl;