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
24 using std::streamsize;
29 ostream & operator<<(ostream & o, Debug::type t)
34 /** This is a streambuffer that never prints out anything, at least
35 that is the intention. You can call it a no-op streambuffer, and
36 the ostream that uses it will be a no-op stream.
38 class nullbuf : public streambuf {
40 #ifndef MODERN_STL_STREAMS
41 typedef char char_type;
44 virtual int sync() { return 0; }
47 virtual streamsize xsputn(char_type const *, streamsize n) {
48 // fakes a purge of the buffer by returning n
51 #ifdef MODERN_STL_STREAMS
53 virtual int_type overflow(int_type c = traits_type::eof()) {
54 // fakes success by returning c
55 return c == traits_type::eof() ? ' ' : c;
59 virtual int_type overflow(int_type c = EOF) {
60 // fakes success by returning c
61 return c == EOF ? ' ' : c;
66 /** A streambuf that sends the output to two different streambufs. These
67 can be any kind of streambufs.
69 class teebuf : public streambuf {
72 teebuf(streambuf * b1, streambuf * b2)
73 : streambuf(), sb1(b1), sb2(b2) {}
75 #ifdef MODERN_STL_STREAMS
79 return sb1->pubsync();
82 virtual streamsize xsputn(char_type const * p, streamsize n) {
84 return sb1->sputn(p, n);
87 virtual int_type overflow(int_type c = traits_type::eof()) {
92 typedef char char_type;
100 virtual streamsize xsputn(char_type const * p, streamsize n) {
102 return sb1->xsputn(p, n);
105 virtual int_type overflow(int_type c = EOF) {
107 return sb1->overflow(c);
118 class debugbuf : public streambuf {
121 debugbuf(streambuf * b)
122 : streambuf(), sb(b) {}
124 #ifdef MODERN_STL_STREAMS
127 return sb->pubsync();
130 virtual streamsize xsputn(char_type const * p, streamsize n) {
131 return sb->sputn(p, n);
134 virtual int_type overflow(int_type c = traits_type::eof()) {
138 typedef char char_type;
139 typedef int int_type;
145 virtual streamsize xsputn(char_type const * p, streamsize n) {
146 return sb->xsputn(p, n);
149 virtual int_type overflow(int_type c = EOF) {
150 return sb->overflow(c);
159 /// So that public parts of DebugStream does not need to know about filebuf
160 struct DebugStream::debugstream_internal {
161 /// Used when logging to file.
166 /// Constructor, sets the debug level to t.
167 DebugStream::DebugStream(Debug::type t)
168 : ostream(new debugbuf(cerr.rdbuf())),
169 dt(t), nullstream(new nullbuf), internal(0) {}
172 /// Constructor, sets the log file to f, and the debug level to t.
173 DebugStream::DebugStream(char const * f, Debug::type t)
174 : ostream(new debugbuf(cerr.rdbuf())),
175 dt(t), nullstream(new nullbuf),
176 internal(new debugstream_internal)
178 internal->fbuf.open(f, ios::out|ios::app);
179 delete rdbuf(new teebuf(cerr.rdbuf(),
184 DebugStream::~DebugStream()
186 delete nullstream.rdbuf(0); // Without this we leak
187 delete rdbuf(0); // Without this we leak
192 /// Sets the debugstreams' logfile to f.
193 void DebugStream::logFile(char const * f)
196 internal->fbuf.close();
198 internal = new debugstream_internal;
200 internal->fbuf.open(f, ios::out|ios::app);
201 delete rdbuf(new teebuf(cerr.rdbuf(),
206 #ifdef TEST_DEBUGSTREAM
208 // Example debug stream
209 DebugStream debugstream;
211 int main(int, char **)
214 I have been running some tests on this to see how much overhead
215 this kind of permanent debug code has. My conclusion is: not
216 much. In all, but the most time critical code, this will have
217 close to no impact at all.
219 In the tests that I have run the use of
220 if (debugstream.debugging(DebugStream::INFO))
221 debugstream << "some debug\n";
222 has close to no overhead when the debug level is not
226 debugstream.debug(DebugStream::INFO) << "some debug\n";
227 is also very small when the debug level is not
228 DebugStream::INFO. However the overhead for this will increase
229 if complex debugging information is output.
231 The overhead when the debug level is DebugStream::INFO can be
232 significant, but since we then are running in debug mode it is
235 Why should we use this instead of the class Error that we already
236 have? First of all it uses C++ iostream and constructs, secondly
237 it will be a lot easier to output the debug info that we need
238 without a lot of manual conversions, thirdly we can now use
239 iomanipulators and the complete iostream formatting functions.
240 pluss it will work for all types that have a operator<<
241 defined, and can be used in functors that take a ostream & as
242 parameter. And there should be less need for temporary objects.
243 And one nice bonus is that we get a log file almost for
246 Some of the names are of course open to modifications. I will try
247 to use the names we already use in LyX.
249 // Just a few simple debugs to show how it can work.
250 debugstream << "Debug level set to Debug::NONE\n";
251 if (debugstream.debugging()) {
252 debugstream << "Something must be debugged\n";
254 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
255 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
256 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
257 debugstream.level(Debug::value("INFO"));
258 debugstream << "Setting debug level to Debug::INFO\n";
259 if (debugstream.debugging()) {
260 debugstream << "Something must be debugged\n";
262 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
263 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
264 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
265 debugstream.addLevel(Debug::type(Debug::CRIT |
267 debugstream << "Adding Debug::CRIT and Debug::WARN\n";
268 debugstream[Debug::WARN] << "more debug(WARN)\n";
269 debugstream[Debug::INFO] << "even more debug(INFO)\n";
270 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
271 debugstream.delLevel(Debug::INFO);
272 debugstream << "Removing Debug::INFO\n";
273 debugstream[Debug::WARN] << "more debug(WARN)\n";
274 debugstream[Debug::INFO] << "even more debug(INFO)\n";
275 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
276 debugstream.logFile("logfile");
277 debugstream << "Setting logfile to \"logfile\"\n";
278 debugstream << "Value: " << 123 << " " << "12\n";
281 // note: the (void*) is needed on g++ 2.7.x since it does not
282 // support partial specialization. In egcs this should not be
284 debugstream << "automatic " << &i
285 << ", free store " << p << endl;
288 for (int j = 0; j < 200000; ++j) {
290 tmp << "Test" << endl;