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
13 #pragma implementation
16 //#include "DebugStream.h"
19 // Since the current C++ lib in egcs does not have a standard implementation
20 // of basic_streambuf and basic_filebuf we don't have to include this
22 //#define MODERN_STL_STREAMS
23 #ifdef MODERN_STL_STREAMS
30 using std::streamsize;
35 ostream & operator<<(ostream & o, Debug::type t)
40 /** This is a streambuffer that never prints out anything, at least
41 that is the intention. You can call it a no-op streambuffer, and
42 the ostream that uses it will be a no-op stream.
44 class nullbuf : public streambuf {
46 #ifndef MODERN_STL_STREAMS
47 typedef char char_type;
50 virtual int sync() { return 0; }
53 virtual streamsize xsputn(char_type const *, streamsize n) {
54 // fakes a purge of the buffer by returning n
57 #ifdef MODERN_STL_STREAMS
59 virtual int_type overflow(int_type c = traits_type::eof()) {
60 // fakes success by returning c
61 return c == traits_type::eof() ? ' ' : c;
65 virtual int_type overflow(int_type c = EOF) {
66 // fakes success by returning c
67 return c == EOF ? ' ' : c;
72 /** A streambuf that sends the output to two different streambufs. These
73 can be any kind of streambufs.
75 class teebuf : public streambuf {
78 teebuf(streambuf * b1, streambuf * b2)
79 : streambuf(), sb1(b1), sb2(b2) {}
81 #ifdef MODERN_STL_STREAMS
85 return sb1->pubsync();
88 virtual streamsize xsputn(char_type const * p, streamsize n) {
90 return sb1->sputn(p, n);
93 virtual int_type overflow(int_type c = traits_type::eof()) {
98 typedef char char_type;
106 virtual streamsize xsputn(char_type const * p, streamsize n) {
108 return sb1->xsputn(p, n);
111 virtual int_type overflow(int_type c = EOF) {
113 return sb1->overflow(c);
124 class debugbuf : public streambuf {
127 debugbuf(streambuf * b)
128 : streambuf(), sb(b) {}
130 #ifdef MODERN_STL_STREAMS
133 return sb->pubsync();
136 virtual streamsize xsputn(char_type const * p, streamsize n) {
137 return sb->sputn(p, n);
140 virtual int_type overflow(int_type c = traits_type::eof()) {
144 typedef char char_type;
145 typedef int int_type;
151 virtual streamsize xsputn(char_type const * p, streamsize n) {
152 return sb->xsputn(p, n);
155 virtual int_type overflow(int_type c = EOF) {
156 return sb->overflow(c);
165 /// So that public parts of DebugStream does not need to know about filebuf
166 struct DebugStream::debugstream_internal {
167 /// Used when logging to file.
172 /// Constructor, sets the debug level to t.
173 DebugStream::DebugStream(Debug::type t)
174 : ostream(new debugbuf(cerr.rdbuf())),
175 dt(t), nullstream(new nullbuf), internal(0) {}
178 /// Constructor, sets the log file to f, and the debug level to t.
179 DebugStream::DebugStream(char const * f, Debug::type t)
180 : ostream(new debugbuf(cerr.rdbuf())),
181 dt(t), nullstream(new nullbuf),
182 internal(new debugstream_internal)
184 internal->fbuf.open(f, ios::out|ios::app);
185 delete rdbuf(new teebuf(cerr.rdbuf(),
190 DebugStream::~DebugStream()
192 delete nullstream.rdbuf(0); // Without this we leak
193 delete rdbuf(0); // Without this we leak
198 /// Sets the debugstreams' logfile to f.
199 void DebugStream::logFile(char const * f)
202 internal->fbuf.close();
204 internal = new debugstream_internal;
206 internal->fbuf.open(f, ios::out|ios::app);
207 delete rdbuf(new teebuf(cerr.rdbuf(),
212 #ifdef TEST_DEBUGSTREAM
214 // Example debug stream
215 DebugStream debugstream;
217 int main(int, char **)
220 I have been running some tests on this to see how much overhead
221 this kind of permanent debug code has. My conclusion is: not
222 much. In all, but the most time critical code, this will have
223 close to no impact at all.
225 In the tests that I have run the use of
226 if (debugstream.debugging(DebugStream::INFO))
227 debugstream << "some debug\n";
228 has close to no overhead when the debug level is not
232 debugstream.debug(DebugStream::INFO) << "some debug\n";
233 is also very small when the debug level is not
234 DebugStream::INFO. However the overhead for this will increase
235 if complex debugging information is output.
237 The overhead when the debug level is DebugStream::INFO can be
238 significant, but since we then are running in debug mode it is
241 Why should we use this instead of the class Error that we already
242 have? First of all it uses C++ iostream and constructs, secondly
243 it will be a lot easier to output the debug info that we need
244 without a lot of manual conversions, thirdly we can now use
245 iomanipulators and the complete iostream formatting functions.
246 pluss it will work for all types that have a operator<<
247 defined, and can be used in functors that take a ostream & as
248 parameter. And there should be less need for temporary objects.
249 And one nice bonus is that we get a log file almost for
252 Some of the names are of course open to modifications. I will try
253 to use the names we already use in LyX.
255 // Just a few simple debugs to show how it can work.
256 debugstream << "Debug level set to Debug::NONE\n";
257 if (debugstream.debugging()) {
258 debugstream << "Something must be debugged\n";
260 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
261 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
262 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
263 debugstream.level(Debug::value("INFO"));
264 debugstream << "Setting debug level to Debug::INFO\n";
265 if (debugstream.debugging()) {
266 debugstream << "Something must be debugged\n";
268 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
269 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
270 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
271 debugstream.addLevel(Debug::type(Debug::CRIT |
273 debugstream << "Adding Debug::CRIT and Debug::WARN\n";
274 debugstream[Debug::WARN] << "more debug(WARN)\n";
275 debugstream[Debug::INFO] << "even more debug(INFO)\n";
276 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
277 debugstream.delLevel(Debug::INFO);
278 debugstream << "Removing Debug::INFO\n";
279 debugstream[Debug::WARN] << "more debug(WARN)\n";
280 debugstream[Debug::INFO] << "even more debug(INFO)\n";
281 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
282 debugstream.logFile("logfile");
283 debugstream << "Setting logfile to \"logfile\"\n";
284 debugstream << "Value: " << 123 << " " << "12\n";
287 // note: the (void*) is needed on g++ 2.7.x since it does not
288 // support partial specialization. In egcs this should not be
290 debugstream << "automatic " << &i
291 << ", free store " << p << endl;
294 for (int j = 0; j < 200000; ++j) {
296 tmp << "Test" << endl;