3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * Full author contact details are available in file CREDITS
11 //#define TEST_DEBUGSTREAM
15 //#include "DebugStream.h"
18 // Since the current C++ lib in egcs does not have a standard implementation
19 // of basic_streambuf and basic_filebuf we don't have to include this
21 //#define MODERN_STL_STREAMS
22 #ifdef MODERN_STL_STREAMS
29 using std::streamsize;
34 ostream & operator<<(ostream & o, Debug::type t)
39 /** This is a streambuffer that never prints out anything, at least
40 that is the intention. You can call it a no-op streambuffer, and
41 the ostream that uses it will be a no-op stream.
43 class nullbuf : public streambuf {
45 #ifndef MODERN_STL_STREAMS
46 typedef char char_type;
49 virtual int sync() { return 0; }
52 virtual streamsize xsputn(char_type const *, streamsize n) {
53 // fakes a purge of the buffer by returning n
56 #ifdef MODERN_STL_STREAMS
58 virtual int_type overflow(int_type c = traits_type::eof()) {
59 // fakes success by returning c
60 return c == traits_type::eof() ? ' ' : c;
64 virtual int_type overflow(int_type c = EOF) {
65 // fakes success by returning c
66 return c == EOF ? ' ' : c;
71 /** A streambuf that sends the output to two different streambufs. These
72 can be any kind of streambufs.
74 class teebuf : public streambuf {
77 teebuf(streambuf * b1, streambuf * b2)
78 : streambuf(), sb1(b1), sb2(b2) {}
80 #ifdef MODERN_STL_STREAMS
84 return sb1->pubsync();
87 virtual streamsize xsputn(char_type const * p, streamsize n) {
89 return sb1->sputn(p, n);
92 virtual int_type overflow(int_type c = traits_type::eof()) {
97 typedef char char_type;
105 virtual streamsize xsputn(char_type const * p, streamsize n) {
107 return sb1->xsputn(p, n);
110 virtual int_type overflow(int_type c = EOF) {
112 return sb1->overflow(c);
123 class debugbuf : public streambuf {
126 debugbuf(streambuf * b)
127 : streambuf(), sb(b) {}
129 #ifdef MODERN_STL_STREAMS
132 return sb->pubsync();
135 virtual streamsize xsputn(char_type const * p, streamsize n) {
136 return sb->sputn(p, n);
139 virtual int_type overflow(int_type c = traits_type::eof()) {
143 typedef char char_type;
144 typedef int int_type;
150 virtual streamsize xsputn(char_type const * p, streamsize n) {
151 return sb->xsputn(p, n);
154 virtual int_type overflow(int_type c = EOF) {
155 return sb->overflow(c);
164 /// So that public parts of DebugStream does not need to know about filebuf
165 struct DebugStream::debugstream_internal {
166 /// Used when logging to file.
171 /// Constructor, sets the debug level to t.
172 DebugStream::DebugStream(Debug::type t)
173 : ostream(new debugbuf(cerr.rdbuf())),
174 dt(t), nullstream(new nullbuf), internal(0) {}
177 /// Constructor, sets the log file to f, and the debug level to t.
178 DebugStream::DebugStream(char const * f, Debug::type t)
179 : ostream(new debugbuf(cerr.rdbuf())),
180 dt(t), nullstream(new nullbuf),
181 internal(new debugstream_internal)
183 internal->fbuf.open(f, ios::out|ios::app);
184 delete rdbuf(new teebuf(cerr.rdbuf(),
189 DebugStream::~DebugStream()
191 delete nullstream.rdbuf(0); // Without this we leak
192 delete rdbuf(0); // Without this we leak
197 /// Sets the debugstreams' logfile to f.
198 void DebugStream::logFile(char const * f)
201 internal->fbuf.close();
203 internal = new debugstream_internal;
205 internal->fbuf.open(f, ios::out|ios::app);
206 delete rdbuf(new teebuf(cerr.rdbuf(),
211 #ifdef TEST_DEBUGSTREAM
213 // Example debug stream
214 DebugStream debugstream;
216 int main(int, char **)
219 I have been running some tests on this to see how much overhead
220 this kind of permanent debug code has. My conclusion is: not
221 much. In all, but the most time critical code, this will have
222 close to no impact at all.
224 In the tests that I have run the use of
225 if (debugstream.debugging(DebugStream::INFO))
226 debugstream << "some debug\n";
227 has close to no overhead when the debug level is not
231 debugstream.debug(DebugStream::INFO) << "some debug\n";
232 is also very small when the debug level is not
233 DebugStream::INFO. However the overhead for this will increase
234 if complex debugging information is output.
236 The overhead when the debug level is DebugStream::INFO can be
237 significant, but since we then are running in debug mode it is
240 Why should we use this instead of the class Error that we already
241 have? First of all it uses C++ iostream and constructs, secondly
242 it will be a lot easier to output the debug info that we need
243 without a lot of manual conversions, thirdly we can now use
244 iomanipulators and the complete iostream formatting functions.
245 pluss it will work for all types that have a operator<<
246 defined, and can be used in functors that take a ostream & as
247 parameter. And there should be less need for temporary objects.
248 And one nice bonus is that we get a log file almost for
251 Some of the names are of course open to modifications. I will try
252 to use the names we already use in LyX.
254 // Just a few simple debugs to show how it can work.
255 debugstream << "Debug level set to Debug::NONE\n";
256 if (debugstream.debugging()) {
257 debugstream << "Something must be debugged\n";
259 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
260 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
261 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
262 debugstream.level(Debug::value("INFO"));
263 debugstream << "Setting debug level to Debug::INFO\n";
264 if (debugstream.debugging()) {
265 debugstream << "Something must be debugged\n";
267 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
268 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
269 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
270 debugstream.addLevel(Debug::type(Debug::CRIT |
272 debugstream << "Adding Debug::CRIT and Debug::WARN\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.delLevel(Debug::INFO);
277 debugstream << "Removing Debug::INFO\n";
278 debugstream[Debug::WARN] << "more debug(WARN)\n";
279 debugstream[Debug::INFO] << "even more debug(INFO)\n";
280 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
281 debugstream.logFile("logfile");
282 debugstream << "Setting logfile to \"logfile\"\n";
283 debugstream << "Value: " << 123 << " " << "12\n";
286 // note: the (void*) is needed on g++ 2.7.x since it does not
287 // support partial specialization. In egcs this should not be
289 debugstream << "automatic " << &i
290 << ", free store " << p << endl;
293 for (int j = 0; j < 200000; ++j) {
295 tmp << "Test" << endl;