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
52 virtual int_type overflow(int_type c = EOF) {
53 // fakes success by returning c
54 return c == EOF ? ' ' : c;
58 /** A streambuf that sends the output to two different streambufs. These
59 can be any kind of streambufs.
61 class teebuf : public streambuf {
64 teebuf(streambuf * b1, streambuf * b2)
65 : streambuf(), sb1(b1), sb2(b2) {}
67 #ifndef MODERN_STL_STREAMS
68 typedef char char_type;
73 #ifdef MODERN_STL_STREAMS
75 return sb1->pubsync();
82 virtual streamsize xsputn(char_type const * p, streamsize n) {
83 #ifdef MODERN_STL_STREAMS
85 return sb1->sputn(p, n);
88 return sb1->xsputn(p, n);
92 virtual int_type overflow(int_type c = EOF) {
93 #ifdef MODERN_STL_STREAMS
98 return sb1->overflow(c);
109 class debugbuf : public streambuf {
112 debugbuf(streambuf * b)
113 : streambuf(), sb(b) {}
115 #ifndef MODERN_STL_STREAMS
116 typedef char char_type;
117 typedef int int_type;
121 #ifdef MODERN_STL_STREAMS
122 return sb->pubsync();
128 virtual streamsize xsputn(char_type const * p, streamsize n) {
129 #ifdef MODERN_STL_STREAMS
130 return sb->sputn(p, n);
132 return sb->xsputn(p, n);
136 virtual int_type overflow(int_type c = EOF) {
137 #ifdef MODERN_STL_STREAMS
140 return sb->overflow(c);
149 /// So that public parts of DebugStream does not need to know about filebuf
150 struct DebugStream::debugstream_internal {
151 /// Used when logging to file.
156 /// Constructor, sets the debug level to t.
157 DebugStream::DebugStream(Debug::type t)
158 : ostream(new debugbuf(cerr.rdbuf())),
159 dt(t), nullstream(new nullbuf), internal(0) {}
162 /// Constructor, sets the log file to f, and the debug level to t.
163 DebugStream::DebugStream(char const * f, Debug::type t)
164 : ostream(new debugbuf(cerr.rdbuf())),
165 dt(t), nullstream(new nullbuf),
166 internal(new debugstream_internal)
168 internal->fbuf.open(f, ios::out|ios::app);
169 delete rdbuf(new teebuf(cerr.rdbuf(),
174 DebugStream::~DebugStream()
176 delete nullstream.rdbuf(0); // Without this we leak
177 delete rdbuf(0); // Without this we leak
183 /// Sets the debugstreams' logfile to f.
184 void DebugStream::logFile(char const * f)
187 internal->fbuf.close();
189 internal = new debugstream_internal;
191 internal->fbuf.open(f, ios::out|ios::app);
192 delete rdbuf(new teebuf(cerr.rdbuf(),
197 #ifdef TEST_DEBUGSTREAM
199 // Example debug stream
200 DebugStream debugstream;
202 int main(int, char **)
205 I have been running some tests on this to see how much overhead
206 this kind of permanent debug code has. My conclusion is: not
207 much. In all, but the most time critical code, this will have
208 close to no impact at all.
210 In the tests that I have run the use of
211 if (debugstream.debugging(DebugStream::INFO))
212 debugstream << "some debug\n";
213 has close to no overhead when the debug level is not
217 debugstream.debug(DebugStream::INFO) << "some debug\n";
218 is also very small when the debug level is not
219 DebugStream::INFO. However the overhead for this will increase
220 if complex debugging information is output.
222 The overhead when the debug level is DebugStream::INFO can be
223 significant, but since we then are running in debug mode it is
226 Why should we use this instead of the class Error that we already
227 have? First of all it uses C++ iostream and constructs, secondly
228 it will be a lot easier to output the debug info that we need
229 without a lot of manual conversions, thirdly we can now use
230 iomanipulators and the complete iostream formatting functions.
231 pluss it will work for all types that have a operator<<
232 defined, and can be used in functors that take a ostream & as
233 parameter. And there should be less need for temporary objects.
234 And one nice bonus is that we get a log file almost for
237 Some of the names are of course open to modifications. I will try
238 to use the names we already use in LyX.
240 // Just a few simple debugs to show how it can work.
241 debugstream << "Debug level set to Debug::NONE\n";
242 if (debugstream.debugging()) {
243 debugstream << "Something must be debugged\n";
245 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
246 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
247 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
248 debugstream.level(Debug::value("INFO"));
249 debugstream << "Setting debug level to Debug::INFO\n";
250 if (debugstream.debugging()) {
251 debugstream << "Something must be debugged\n";
253 debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
254 debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
255 debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
256 debugstream.addLevel(Debug::type(Debug::CRIT |
258 debugstream << "Adding Debug::CRIT and Debug::WARN\n";
259 debugstream[Debug::WARN] << "more debug(WARN)\n";
260 debugstream[Debug::INFO] << "even more debug(INFO)\n";
261 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
262 debugstream.delLevel(Debug::INFO);
263 debugstream << "Removing Debug::INFO\n";
264 debugstream[Debug::WARN] << "more debug(WARN)\n";
265 debugstream[Debug::INFO] << "even more debug(INFO)\n";
266 debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
267 debugstream.logFile("logfile");
268 debugstream << "Setting logfile to \"logfile\"\n";
269 debugstream << "Value: " << 123 << " " << "12\n";
272 // note: the (void*) is needed on g++ 2.7.x since it does not
273 // support partial specialization. In egcs this should not be
275 debugstream << "automatic " << &i
276 << ", free store " << p << endl;
279 for (int j = 0; j < 200000; ++j) {
281 tmp << "Test" << endl;