]> git.lyx.org Git - lyx.git/blob - src/support/DebugStream.C
fix the smallcaps drawing, move xfont metrics functions out from LyXFont, move non...
[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::ostream;
24 using std::streambuf;
25 using std::streamsize;
26 using std::filebuf;
27 using std::cerr;
28 using std::ios;
29
30 ostream & operator<<(ostream & o, Debug::type t)
31 {
32         return o << int(t);
33 }
34
35 /** This is a streambuffer that never prints out anything, at least
36     that is the intention. You can call it a no-op streambuffer, and
37     the ostream that uses it will be a no-op stream.
38 */
39 class nullbuf : public streambuf {
40 protected:
41 #ifndef MODERN_STL_STREAMS
42         typedef char char_type;
43         typedef int int_type;
44         ///
45         virtual int sync() { return 0; }
46 #endif
47         /// 
48         virtual streamsize xsputn(char_type const *, streamsize n) {
49                 // fakes a purge of the buffer by returning n
50                 return n;
51         }
52 #ifdef MODERN_STL_STREAMS
53         ///
54         virtual int_type overflow(int_type c = traits_type::eof()) {
55                 // fakes success by returning c
56                 return c == traits_type::eof() ? ' ' : c;
57         }
58 #else
59         ///
60         virtual int_type overflow(int_type c = EOF) {
61                 // fakes success by returning c
62                 return c == EOF ? ' ' : c;
63         }
64 #endif
65 };
66
67 /** A streambuf that sends the output to two different streambufs. These
68     can be any kind of streambufs.
69 */
70 class teebuf : public streambuf {
71 public:
72         ///
73         teebuf(streambuf * b1, streambuf * b2)
74                 : streambuf(), sb1(b1), sb2(b2) {}
75 protected:
76 #ifdef MODERN_STL_STREAMS
77         ///
78         virtual int sync() {
79                 sb2->pubsync();
80                 return sb1->pubsync();
81         }
82         ///
83         virtual streamsize xsputn(char_type const * p, streamsize n) {
84                 sb2->sputn(p, n);
85                 return sb1->sputn(p, n);
86         }
87         ///
88         virtual int_type overflow(int_type c = traits_type::eof()) {
89                 sb2->sputc(c);
90                 return sb1->sputc(c);
91         }
92 #else
93         typedef char char_type;
94         typedef int int_type;
95         ///
96         virtual int sync() {
97                 sb2->sync();
98                 return sb1->sync();
99         }
100         ///
101         virtual streamsize xsputn(char_type const * p, streamsize n) {
102                 sb2->xsputn(p, n);
103                 return sb1->xsputn(p, n);
104         }
105         ///
106         virtual int_type overflow(int_type c = EOF) {
107                 sb2->overflow(c);
108                 return sb1->overflow(c);
109         }
110 #endif
111 private:
112         ///
113         streambuf * sb1;
114         ///
115         streambuf * sb2;
116 };
117
118 ///
119 class debugbuf : public streambuf {
120 public:
121         ///
122         debugbuf(streambuf * b)
123                 : streambuf(), sb(b) {}
124 protected:
125 #ifdef MODERN_STL_STREAMS
126         ///
127         virtual int sync() {
128                 return sb->pubsync();
129         }
130         ///
131         virtual streamsize xsputn(char_type const * p, streamsize n) {
132                 return sb->sputn(p, n);
133         }
134         ///
135         virtual int_type overflow(int_type c = traits_type::eof()) {
136                 return sb->sputc(c);
137         }
138 #else
139         typedef char char_type;
140         typedef int int_type;
141         ///
142         virtual int sync() {
143                 return sb->sync();
144         }
145         ///
146         virtual streamsize xsputn(char_type const * p, streamsize n) {
147                 return sb->xsputn(p, n);
148         }
149         ///
150         virtual int_type overflow(int_type c = EOF) {
151                 return sb->overflow(c);
152         }
153 #endif
154 private:
155         ///
156         streambuf * sb;
157 };
158
159
160 /// So that public parts of DebugStream does not need to know about filebuf
161 struct DebugStream::debugstream_internal {
162         /// Used when logging to file.
163         filebuf fbuf;
164 };
165
166
167 /// Constructor, sets the debug level to t.
168 DebugStream::DebugStream(Debug::type t)
169         : ostream(new debugbuf(cerr.rdbuf())),
170           dt(t), nullstream(new nullbuf), internal(0) {}
171
172         
173 /// Constructor, sets the log file to f, and the debug level to t.
174 DebugStream::DebugStream(char const * f, Debug::type t)
175         : ostream(new debugbuf(cerr.rdbuf())),
176           dt(t), nullstream(new nullbuf),
177           internal(new debugstream_internal)
178 {
179         internal->fbuf.open(f, ios::out|ios::app);
180         delete rdbuf(new teebuf(cerr.rdbuf(),
181                                 &internal->fbuf));
182 }
183
184
185 DebugStream::~DebugStream()
186 {
187         delete nullstream.rdbuf(0); // Without this we leak
188         delete rdbuf(0);            // Without this we leak
189         delete internal;
190 }
191
192
193 /// Sets the debugstreams' logfile to f.
194 void DebugStream::logFile(char const * f)
195 {
196         if (internal) {
197                 internal->fbuf.close();
198         } else {
199                 internal = new debugstream_internal;
200         }
201         internal->fbuf.open(f, ios::out|ios::app);
202         delete rdbuf(new teebuf(cerr.rdbuf(),
203                                 &internal->fbuf));
204 }
205
206
207 #ifdef TEST_DEBUGSTREAM
208
209 // Example debug stream
210 DebugStream debugstream;
211
212 int main(int, char **)
213 {
214         /**
215            I have been running some tests on this to see how much overhead
216            this kind of permanent debug code has. My conclusion is: not 
217            much. In all, but the most time critical code, this will have 
218            close to no impact at all.
219            
220            In the tests that I have run the use of
221            if (debugstream.debugging(DebugStream::INFO))
222            debugstream << "some debug\n";
223            has close to no overhead when the debug level is not 
224            DebugStream::INFO.
225            
226            The overhead for
227            debugstream.debug(DebugStream::INFO) << "some debug\n";
228            is also very small when the debug level is not
229            DebugStream::INFO. However the overhead for this will increase
230            if complex debugging information is output.
231            
232            The overhead when the debug level is DebugStream::INFO can be
233            significant, but since we then are running in debug mode it is 
234            of no concern.
235            
236            Why should we use this instead of the class Error that we already
237            have? First of all it uses C++ iostream and constructs, secondly
238            it will be a lot easier to output the debug info that we need
239            without a lot of manual conversions, thirdly we can now use 
240            iomanipulators and the complete iostream formatting functions.
241            pluss it will work for all types that have a operator<< 
242            defined, and can be used in functors that take a ostream & as
243            parameter. And there should be less need for temporary objects.
244            And one nice bonus is that we get a log file almost for
245            free.
246            
247            Some of the names are of course open to modifications. I will try
248            to use the names we already use in LyX.
249         */
250         // Just a few simple debugs to show how it can work.
251         debugstream << "Debug level set to Debug::NONE\n";
252         if (debugstream.debugging()) {
253                 debugstream << "Something must be debugged\n";
254         }
255         debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
256         debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
257         debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
258         debugstream.level(Debug::value("INFO"));
259         debugstream << "Setting debug level to Debug::INFO\n";
260         if (debugstream.debugging()) {
261                 debugstream << "Something must be debugged\n";
262         }
263         debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
264         debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
265         debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
266         debugstream.addLevel(Debug::type(Debug::CRIT | 
267                                          Debug::WARN));
268         debugstream << "Adding Debug::CRIT and Debug::WARN\n";
269         debugstream[Debug::WARN] << "more debug(WARN)\n";
270         debugstream[Debug::INFO] << "even more debug(INFO)\n";
271         debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
272         debugstream.delLevel(Debug::INFO);
273         debugstream << "Removing Debug::INFO\n";
274         debugstream[Debug::WARN] << "more debug(WARN)\n";
275         debugstream[Debug::INFO] << "even more debug(INFO)\n";
276         debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
277         debugstream.logFile("logfile");
278         debugstream << "Setting logfile to \"logfile\"\n";
279         debugstream << "Value: " << 123 << " " << "12\n";
280         int i = 0;
281         int * p = new int;
282         // note: the (void*) is needed on g++ 2.7.x since it does not
283         // support partial specialization. In egcs this should not be
284         // needed.
285         debugstream << "automatic " << &i 
286                     << ", free store " << p << endl;
287         delete p;
288         /*
289         for (int j = 0; j < 200000; ++j) {
290                 DebugStream tmp;
291                 tmp << "Test" << endl;
292         }
293         */
294 }
295 #endif