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