]> git.lyx.org Git - lyx.git/blob - src/support/DebugStream.C
fix lyxalgo.h, dra pagebreak with text on line, change the math_deco_search a bit
[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 #ifdef MODERN_STL_STREAMS
52         ///
53         virtual int_type overflow(int_type c = traits_type::eof()) {
54                 // fakes success by returning c
55                 return c == traits_type::eof() ? ' ' : c;
56         }
57 #else
58         ///
59         virtual int_type overflow(int_type c = EOF) {
60                 // fakes success by returning c
61                 return c == EOF ? ' ' : c;
62         }
63 #endif
64 };
65
66 /** A streambuf that sends the output to two different streambufs. These
67     can be any kind of streambufs.
68 */
69 class teebuf : public streambuf {
70 public:
71         ///
72         teebuf(streambuf * b1, streambuf * b2)
73                 : streambuf(), sb1(b1), sb2(b2) {}
74 protected:
75 #ifdef MODERN_STL_STREAMS
76         ///
77         virtual int sync() {
78                 sb2->pubsync();
79                 return sb1->pubsync();
80         }
81         ///
82         virtual streamsize xsputn(char_type const * p, streamsize n) {
83                 sb2->sputn(p, n);
84                 return sb1->sputn(p, n);
85         }
86         ///
87         virtual int_type overflow(int_type c = traits_type::eof()) {
88                 sb2->sputc(c);
89                 return sb1->sputc(c);
90         }
91 #else
92         typedef char char_type;
93         typedef int int_type;
94         ///
95         virtual int sync() {
96                 sb2->sync();
97                 return sb1->sync();
98         }
99         ///
100         virtual streamsize xsputn(char_type const * p, streamsize n) {
101                 sb2->xsputn(p, n);
102                 return sb1->xsputn(p, n);
103         }
104         ///
105         virtual int_type overflow(int_type c = EOF) {
106                 sb2->overflow(c);
107                 return sb1->overflow(c);
108         }
109 #endif
110 private:
111         ///
112         streambuf * sb1;
113         ///
114         streambuf * sb2;
115 };
116
117 ///
118 class debugbuf : public streambuf {
119 public:
120         ///
121         debugbuf(streambuf * b)
122                 : streambuf(), sb(b) {}
123 protected:
124 #ifdef MODERN_STL_STREAMS
125         ///
126         virtual int sync() {
127                 return sb->pubsync();
128         }
129         ///
130         virtual streamsize xsputn(char_type const * p, streamsize n) {
131                 return sb->sputn(p, n);
132         }
133         ///
134         virtual int_type overflow(int_type c = traits_type::eof()) {
135                 return sb->sputc(c);
136         }
137 #else
138         typedef char char_type;
139         typedef int int_type;
140         ///
141         virtual int sync() {
142                 return sb->sync();
143         }
144         ///
145         virtual streamsize xsputn(char_type const * p, streamsize n) {
146                 return sb->xsputn(p, n);
147         }
148         ///
149         virtual int_type overflow(int_type c = EOF) {
150                 return sb->overflow(c);
151         }
152 #endif
153 private:
154         ///
155         streambuf * sb;
156 };
157
158
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.
162         filebuf fbuf;
163 };
164
165
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) {}
170
171         
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)
177 {
178         internal->fbuf.open(f, ios::out|ios::app);
179         delete rdbuf(new teebuf(cerr.rdbuf(),
180                                 &internal->fbuf));
181 }
182
183
184 DebugStream::~DebugStream()
185 {
186         delete nullstream.rdbuf(0); // Without this we leak
187         delete rdbuf(0);            // Without this we leak
188         delete internal;
189 }
190
191
192 /// Sets the debugstreams' logfile to f.
193 void DebugStream::logFile(char const * f)
194 {
195         if (internal) {
196                 internal->fbuf.close();
197         } else {
198                 internal = new debugstream_internal;
199         }
200         internal->fbuf.open(f, ios::out|ios::app);
201         delete rdbuf(new teebuf(cerr.rdbuf(),
202                                 &internal->fbuf));
203 }
204
205
206 #ifdef TEST_DEBUGSTREAM
207
208 // Example debug stream
209 DebugStream debugstream;
210
211 int main(int, char **)
212 {
213         /**
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.
218            
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 
223            DebugStream::INFO.
224            
225            The overhead for
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.
230            
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 
233            of no concern.
234            
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
244            free.
245            
246            Some of the names are of course open to modifications. I will try
247            to use the names we already use in LyX.
248         */
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";
253         }
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";
261         }
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 | 
266                                          Debug::WARN));
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";
279         int i = 0;
280         int * p = new int;
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
283         // needed.
284         debugstream << "automatic " << &i 
285                     << ", free store " << p << endl;
286         delete p;
287         /*
288         for (int j = 0; j < 200000; ++j) {
289                 DebugStream tmp;
290                 tmp << "Test" << endl;
291         }
292         */
293 }
294 #endif