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
12 //#include "DebugStream.h"
15 // Since the current C++ lib in egcs does not have a standard implementation
16 // of basic_streambuf and basic_filebuf we don't have to include this
18 //#define MODERN_STL_STREAMS
19 #ifdef MODERN_STL_STREAMS
26 using std::streamsize;
31 ostream & operator<<(ostream & o, Debug::type t)
36 /** This is a streambuffer that never prints out anything, at least
37 that is the intention. You can call it a no-op streambuffer, and
38 the ostream that uses it will be a no-op stream.
40 class nullbuf : public streambuf {
42 #ifndef MODERN_STL_STREAMS
43 typedef char char_type;
46 virtual int sync() { return 0; }
49 virtual streamsize xsputn(char_type const *, streamsize n) {
50 // fakes a purge of the buffer by returning n
53 #ifdef MODERN_STL_STREAMS
55 virtual int_type overflow(int_type c = traits_type::eof()) {
56 // fakes success by returning c
57 return c == traits_type::eof() ? ' ' : c;
61 virtual int_type overflow(int_type c = EOF) {
62 // fakes success by returning c
63 return c == EOF ? ' ' : c;
68 /** A streambuf that sends the output to two different streambufs. These
69 can be any kind of streambufs.
71 class teebuf : public streambuf {
74 teebuf(streambuf * b1, streambuf * b2)
75 : streambuf(), sb1(b1), sb2(b2) {}
77 #ifdef MODERN_STL_STREAMS
81 return sb1->pubsync();
84 virtual streamsize xsputn(char_type const * p, streamsize n) {
86 return sb1->sputn(p, n);
89 virtual int_type overflow(int_type c = traits_type::eof()) {
94 typedef char char_type;
102 virtual streamsize xsputn(char_type const * p, streamsize n) {
104 return sb1->xsputn(p, n);
107 virtual int_type overflow(int_type c = EOF) {
109 return sb1->overflow(c);
120 class debugbuf : public streambuf {
123 debugbuf(streambuf * b)
124 : streambuf(), sb(b) {}
126 #ifdef MODERN_STL_STREAMS
129 return sb->pubsync();
132 virtual streamsize xsputn(char_type const * p, streamsize n) {
133 return sb->sputn(p, n);
136 virtual int_type overflow(int_type c = traits_type::eof()) {
140 typedef char char_type;
141 typedef int int_type;
147 virtual streamsize xsputn(char_type const * p, streamsize n) {
148 return sb->xsputn(p, n);
151 virtual int_type overflow(int_type c = EOF) {
152 return sb->overflow(c);
161 /// So that public parts of DebugStream does not need to know about filebuf
162 struct DebugStream::debugstream_internal {
163 /// Used when logging to file.
168 /// Constructor, sets the debug level to t.
169 DebugStream::DebugStream(Debug::type t)
170 : ostream(new debugbuf(cerr.rdbuf())),
171 dt(t), nullstream(new nullbuf), internal(0) {}
174 /// Constructor, sets the log file to f, and the debug level to t.
175 DebugStream::DebugStream(char const * f, Debug::type t)
176 : ostream(new debugbuf(cerr.rdbuf())),
177 dt(t), nullstream(new nullbuf),
178 internal(new debugstream_internal)
180 internal->fbuf.open(f, ios::out|ios::app);
181 delete rdbuf(new teebuf(cerr.rdbuf(),
186 DebugStream::~DebugStream()
188 delete nullstream.rdbuf(0); // Without this we leak
189 delete rdbuf(0); // Without this we leak
194 /// Sets the debugstreams' logfile to f.
195 void DebugStream::logFile(char const * f)
198 internal->fbuf.close();
200 internal = new debugstream_internal;
202 internal->fbuf.open(f, ios::out|ios::app);
203 delete rdbuf(new teebuf(cerr.rdbuf(),
208 #ifdef TEST_DEBUGSTREAM
210 // Example debug stream
211 DebugStream debugstream;
213 int main(int, char **)
216 I have been running some tests on this to see how much overhead
217 this kind of permanent debug code has. My conclusion is: not
218 much. In all, but the most time critical code, this will have
219 close to no impact at all.
221 In the tests that I have run the use of
222 if (debugstream.debugging(DebugStream::INFO))
223 debugstream << "some debug\n";
224 has close to no overhead when the debug level is not
228 debugstream.debug(DebugStream::INFO) << "some debug\n";
229 is also very small when the debug level is not
230 DebugStream::INFO. However the overhead for this will increase
231 if complex debugging information is output.
233 The overhead when the debug level is DebugStream::INFO can be
234 significant, but since we then are running in debug mode it is
237 Why should we use this instead of the class Error that we already
238 have? First of all it uses C++ iostream and constructs, secondly
239 it will be a lot easier to output the debug info that we need
240 without a lot of manual conversions, thirdly we can now use
241 iomanipulators and the complete iostream formatting functions.
242 pluss it will work for all types that have a operator<<
243 defined, and can be used in functors that take a ostream & as
244 parameter. And there should be less need for temporary objects.
245 And one nice bonus is that we get a log file almost for
248 Some of the names are of course open to modifications. I will try
249 to use the names we already use in LyX.
251 // Just a few simple debugs to show how it can work.
252 debugstream << "Debug level set to Debug::NONE\n";
253 if (debugstream.debugging()) {
254 debugstream << "Something must be debugged\n";
256 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
257 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
258 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
259 debugstream.level(Debug::value("INFO"));
260 debugstream << "Setting debug level to Debug::INFO\n";
261 if (debugstream.debugging()) {
262 debugstream << "Something must be debugged\n";
264 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
265 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
266 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
267 debugstream.addLevel(Debug::type(Debug::CRIT |
269 debugstream << "Adding Debug::CRIT and Debug::WARN\n";
270 debugstream[Debug::WARN] << "more debug(WARN)\n";
271 debugstream[Debug::INFO] << "even more debug(INFO)\n";
272 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
273 debugstream.delLevel(Debug::INFO);
274 debugstream << "Removing Debug::INFO\n";
275 debugstream[Debug::WARN] << "more debug(WARN)\n";
276 debugstream[Debug::INFO] << "even more debug(INFO)\n";
277 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
278 debugstream.logFile("logfile");
279 debugstream << "Setting logfile to \"logfile\"\n";
280 debugstream << "Value: " << 123 << " " << "12\n";
283 // note: the (void*) is needed on g++ 2.7.x since it does not
284 // support partial specialization. In egcs this should not be
286 debugstream << "automatic " << &i
287 << ", free store " << p << endl;
290 for (int j = 0; j < 200000; ++j) {
292 tmp << "Test" << endl;