]> git.mxchange.org Git - simgear.git/blob - simgear/debug/logstream.hxx
Csaba/Jester : fix the material animation and display night textures
[simgear.git] / simgear / debug / logstream.hxx
1 /** \file logstream.hxx
2  * Stream based logging mechanism.
3  */
4
5 // Written by Bernie Bright, 1998
6 //
7 // Copyright (C) 1998  Bernie Bright - bbright@c031.aone.net.au
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Library General Public
11 // License as published by the Free Software Foundation; either
12 // version 2 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 // Library General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22 //
23 // $Id$
24
25 #ifndef _LOGSTREAM_H
26 #define _LOGSTREAM_H
27
28 #include <simgear/compiler.h>
29
30 #ifdef _MSC_VER
31 #  include <windows.h>
32 #endif
33
34 #include <streambuf>
35 #include <ostream>
36
37 #include <simgear/debug/debug_types.h>
38
39 using std::streambuf;
40 using std::ostream;
41
42 //
43 // TODO:
44 //
45 // 1. Change output destination. Done.
46 // 2. Make logbuf thread safe.
47 // 3. Read environment for default debugClass and debugPriority.
48 //
49
50 /**
51  * logbuf is an output-only streambuf with the ability to disable sets of
52  * messages at runtime. Only messages with priority >= logbuf::logPriority
53  * and debugClass == logbuf::logClass are output.
54  */
55 #ifdef SG_NEED_STREAMBUF_HACK
56 class logbuf : public __streambuf
57 #else
58 class logbuf : public std::streambuf
59 #endif
60 {
61 public:
62     // logbuf( streambuf* sb ) : sbuf(sb) {}
63     /** Constructor */
64     logbuf();
65
66     /** Destructor */
67     ~logbuf();
68
69     /**
70      * Is logging enabled?
71      * @return true or false*/
72     bool enabled() { return logging_enabled; }
73
74     /**
75      * Set the logging level of subsequent messages.
76      * @param c debug class
77      * @param p priority
78      */
79     void set_log_state( sgDebugClass c, sgDebugPriority p );
80
81     bool would_log( sgDebugClass c, sgDebugPriority p ) const;
82
83     /**
84      * Set the global logging level.
85      * @param c debug class
86      * @param p priority
87      */
88     static void set_log_level( sgDebugClass c, sgDebugPriority p );
89
90
91     /**
92      * Set the allowed logging classes.
93      * @param c All enabled logging classes anded together.
94      */
95     static void set_log_classes (sgDebugClass c);
96
97
98     /**
99      * Get the logging classes currently enabled.
100      * @return All enabled debug logging anded together.
101      */
102     static sgDebugClass get_log_classes ();
103
104
105     /**
106      * Set the logging priority.
107      * @param c The priority cutoff for logging messages.
108      */
109     static void set_log_priority (sgDebugPriority p);
110
111
112     /**
113      * Get the current logging priority.
114      * @return The priority cutoff for logging messages.
115      */
116     static sgDebugPriority get_log_priority ();
117
118
119     /**
120      * Set the stream buffer
121      * @param sb stream buffer
122      */
123     void set_sb( std::streambuf* sb );
124
125 #ifdef _MSC_VER
126     static void has_no_console() { has_console = false; }
127 #endif
128
129 protected:
130
131     /** sync/flush */
132     inline virtual int sync();
133
134     /** overflow */
135     int_type overflow( int ch );
136     // int xsputn( const char* s, istreamsize n );
137
138 private:
139
140     // The streambuf used for actual output. Defaults to cerr.rdbuf().
141     static std::streambuf* sbuf;
142
143     static bool logging_enabled;
144 #ifdef _MSC_VER
145     static bool has_console;
146 #endif
147     static sgDebugClass logClass;
148     static sgDebugPriority logPriority;
149
150 private:
151
152     // Not defined.
153     logbuf( const logbuf& );
154     void operator= ( const logbuf& );
155 };
156
157 inline int
158 logbuf::sync()
159 {
160         return sbuf->pubsync();
161 }
162
163 inline void
164 logbuf::set_log_state( sgDebugClass c, sgDebugPriority p )
165 {
166     logging_enabled = ((c & logClass) != 0 && p >= logPriority);
167 }
168
169 inline bool
170 logbuf::would_log( sgDebugClass c, sgDebugPriority p ) const
171 {
172     return ((c & logClass) != 0 && p >= logPriority);
173 }
174
175 inline logbuf::int_type
176 logbuf::overflow( int c )
177 {
178 #ifdef _MSC_VER
179     if ( logging_enabled ) {
180         if ( !has_console ) {
181             AllocConsole();
182             freopen("conin$", "r", stdin);
183             freopen("conout$", "w", stdout);
184             freopen("conout$", "w", stderr);
185             has_console = true;
186         }
187         return sbuf->sputc(c);
188     }
189     else
190         return EOF == 0 ? 1: 0;
191 #else
192     return logging_enabled ? sbuf->sputc(c) : (EOF == 0 ? 1: 0);
193 #endif
194 }
195
196 /**
197  * logstream manipulator for setting the log level of a message.
198  */
199 struct loglevel
200 {
201     loglevel( sgDebugClass c, sgDebugPriority p )
202         : logClass(c), logPriority(p) {}
203
204     sgDebugClass logClass;
205     sgDebugPriority logPriority;
206 };
207
208 /**
209  * A helper class that ensures a streambuf and ostream are constructed and
210  * destroyed in the correct order.  The streambuf must be created before the
211  * ostream but bases are constructed before members.  Thus, making this class
212  * a private base of logstream, declared to the left of ostream, we ensure the
213  * correct order of construction and destruction.
214  */
215 struct logstream_base
216 {
217     // logstream_base( streambuf* sb ) : lbuf(sb) {}
218     logstream_base() {}
219
220     logbuf lbuf;
221 };
222
223 /**
224  * Class to manage the debug logging stream.
225  */
226 class logstream : private logstream_base, public std::ostream
227 {
228 public:
229     /**
230      * The default is to send messages to cerr.
231      * @param out output stream
232      */
233     logstream( std::ostream& out )
234         // : logstream_base(out.rdbuf()),
235         : logstream_base(),
236           std::ostream(&lbuf) { lbuf.set_sb(out.rdbuf());}
237
238     /**
239      * Set the output stream
240      * @param out output stream
241      */
242     void set_output( std::ostream& out ) { lbuf.set_sb( out.rdbuf() ); }
243
244     /**
245      * Set the global log class and priority level.
246      * @param c debug class
247      * @param p priority
248      */
249     void setLogLevels( sgDebugClass c, sgDebugPriority p );
250
251     bool would_log(  sgDebugClass c, sgDebugPriority p ) const
252     {
253         return lbuf.would_log( c, p );
254     };
255
256     /**
257      * Output operator to capture the debug level and priority of a message.
258      * @param l log level
259      */
260     inline std::ostream& operator<< ( const loglevel& l );
261     friend logstream& sglog();
262     static logstream *initGlobalLogstream();
263 protected:
264     static logstream *global_logstream;
265 };
266
267 inline std::ostream&
268 logstream::operator<< ( const loglevel& l )
269 {
270     lbuf.set_log_state( l.logClass, l.logPriority );
271     return *this;
272 }
273
274 /**
275  * \relates logstream
276  * Return the one and only logstream instance.
277  * We use a function instead of a global object so we are assured that cerr
278  * has been initialised.
279  * @return current logstream
280  */
281 inline logstream&
282 sglog()
283 {
284     return *logstream::initGlobalLogstream();
285 }
286
287
288 /** \def SG_LOG(C,P,M)
289  * Log a message.
290  * @param C debug class
291  * @param P priority
292  * @param M message
293  */
294 #ifdef FG_NDEBUG
295 # define SG_LOG(C,P,M)
296 #else
297 # define SG_LOG(C,P,M) do {                     \
298         logstream& __tmplogstreamref(sglog());                      \
299         if(__tmplogstreamref.would_log(C,P)) {                      \
300         __tmplogstreamref << loglevel(C,P) << M << std::endl; } \
301         } while(0)
302 #endif
303
304 #define SG_ORIGIN __FILE__ ":" SG_STRINGIZE(__LINE__)
305
306 #endif // _LOGSTREAM_H
307