]> git.lyx.org Git - lyx.git/blob - src/support/DebugStream.C
read the ChangeLog, use the C++ style casts more, some changes to the debugbufs,...
[lyx.git] / src / support / DebugStream.C
1 // Created by Lars Gullik Bjønnes
2 // Copyright 1999 Lars Gullik Bjønnes (larsbj@lyx.org)
3 // Released into the public domain.
4
5 // Primarily developed for use in the LyX Project http://www.lyx.org/
6 // but should be adaptable to any project.
7
8 //#define TEST_DEBUGSTREAM
9
10 #include <config.h>
11
12 //#include "DebugStream.h"
13 #include "debug.h"
14
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
17 // header.
18 //#define MODERN_STL_STREAMS
19 #ifdef MODERN_STL_STREAMS
20 #include <fstream>
21 #endif
22
23 using std::streambuf;
24 using std::streamsize;
25 using std::filebuf;
26 using std::cerr;
27 using std::ios;
28
29 ostream & operator<<(ostream & o, Debug::type t)
30 {
31         return o << int(t);
32 }
33
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.
37 */
38 class nullbuf : public streambuf {
39 protected:
40 #ifndef MODERN_STL_STREAMS
41         typedef char char_type;
42         typedef int int_type;
43         ///
44         virtual int sync() { return 0; }
45 #endif
46         /// 
47         virtual streamsize xsputn(char_type const *, streamsize n) {
48                 // fakes a purge of the buffer by returning n
49                 return n;
50         }
51         ///
52         virtual int_type overflow(int_type c = EOF) {
53                 // fakes success by returning c
54                 return c == EOF ? ' ' : c;
55         }
56 };
57
58 /** A streambuf that sends the output to two different streambufs. These
59     can be any kind of streambufs.
60 */
61 class teebuf : public streambuf {
62 public:
63         ///
64         teebuf(streambuf * b1, streambuf * b2)
65                 : streambuf(), sb1(b1), sb2(b2) {}
66 protected:
67 #ifndef MODERN_STL_STREAMS
68         typedef char char_type;
69         typedef int int_type;
70 #endif
71         ///
72         virtual int sync() {
73 #ifdef MODERN_STL_STREAMS
74                 sb2->pubsync();
75                 return sb1->pubsync();
76 #else
77                 sb2->sync();
78                 return sb1->sync();
79 #endif
80         }
81         ///
82         virtual streamsize xsputn(char_type const * p, streamsize n) {
83 #ifdef MODERN_STL_STREAMS
84                 sb2->sputn(p, n);
85                 return sb1->sputn(p, n);
86 #else
87                 sb2->xsputn(p, n);
88                 return sb1->xsputn(p, n);
89 #endif
90         }
91         ///
92         virtual int_type overflow(int_type c = EOF) {
93 #ifdef MODERN_STL_STREAMS
94                 sb2->sputc(c);
95                 return sb1->sputc(c);
96 #else
97                 sb2->overflow(c);
98                 return sb1->overflow(c);
99 #endif
100         }
101 private:
102         ///
103         streambuf * sb1;
104         ///
105         streambuf * sb2;
106 };
107
108 ///
109 class debugbuf : public streambuf {
110 public:
111         ///
112         debugbuf(streambuf * b)
113                 : streambuf(), sb(b) {}
114 protected:
115 #ifndef MODERN_STL_STREAMS
116         typedef char char_type;
117         typedef int int_type;
118 #endif
119         ///
120         virtual int sync() {
121 #ifdef MODERN_STL_STREAMS
122                 return sb->pubsync();
123 #else
124                 return sb->sync();
125 #endif
126         }
127         ///
128         virtual streamsize xsputn(char_type const * p, streamsize n) {
129 #ifdef MODERN_STL_STREAMS
130                 return sb->sputn(p, n);
131 #else
132                 return sb->xsputn(p, n);
133 #endif
134         }
135         ///
136         virtual int_type overflow(int_type c = EOF) {
137 #ifdef MODERN_STL_STREAMS
138                 return sb->sputc(c);
139 #else
140                 return sb->overflow(c);
141 #endif
142         }
143 private:
144         ///
145         streambuf * sb;
146 };
147
148
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.
152         filebuf fbuf;
153 };
154
155
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) {}
160
161         
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)
167 {
168         internal->fbuf.open(f, ios::out|ios::app);
169         delete rdbuf(new teebuf(cerr.rdbuf(),
170                                 &internal->fbuf));
171 }
172
173
174 DebugStream::~DebugStream()
175 {
176         delete nullstream.rdbuf(0); // Without this we leak
177         delete rdbuf(0);            // Without this we leak
178         if (internal)
179                 delete internal;
180 }
181
182
183 /// Sets the debugstreams' logfile to f.
184 void DebugStream::logFile(char const * f)
185 {
186         if (internal) {
187                 internal->fbuf.close();
188         } else {
189                 internal = new debugstream_internal;
190         }
191         internal->fbuf.open(f, ios::out|ios::app);
192         delete rdbuf(new teebuf(cerr.rdbuf(),
193                                 &internal->fbuf));
194 }
195
196
197 #ifdef TEST_DEBUGSTREAM
198
199 // Example debug stream
200 DebugStream debugstream;
201
202 int main(int, char **)
203 {
204         /**
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.
209            
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 
214            DebugStream::INFO.
215            
216            The overhead for
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.
221            
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 
224            of no concern.
225            
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
235            free.
236            
237            Some of the names are of course open to modifications. I will try
238            to use the names we already use in LyX.
239         */
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";
244         }
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";
252         }
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 | 
257                                          Debug::WARN));
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";
270         int i = 0;
271         int * p = new int;
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
274         // needed.
275         debugstream << "automatic " << &i 
276                     << ", free store " << p << endl;
277         delete p;
278         /*
279         for (int j = 0; j < 200000; ++j) {
280                 DebugStream tmp;
281                 tmp << "Test" << endl;
282         }
283         */
284 }
285 #endif