]> git.mxchange.org Git - simgear.git/blob - simgear/debug/logstream.hxx
- new FSF addresses
[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 #ifdef SG_HAVE_STD_INCLUDES
35 # include <streambuf>
36 # include <iostream>
37 #else
38 # include <iostream.h>
39 # include <simgear/sg_traits.hxx>
40 #endif
41
42 #include <simgear/debug/debug_types.h>
43
44 SG_USING_STD(streambuf);
45 SG_USING_STD(ostream);
46 SG_USING_STD(cout);
47 SG_USING_STD(cerr);
48 SG_USING_STD(endl);
49
50 #ifdef __MWERKS__
51 SG_USING_STD(iostream);
52 #endif
53
54 //
55 // TODO:
56 //
57 // 1. Change output destination. Done.
58 // 2. Make logbuf thread safe.
59 // 3. Read environment for default debugClass and debugPriority.
60 //
61
62 /**
63  * logbuf is an output-only streambuf with the ability to disable sets of
64  * messages at runtime. Only messages with priority >= logbuf::logPriority
65  * and debugClass == logbuf::logClass are output.
66  */
67 #ifdef SG_NEED_STREAMBUF_HACK
68 class logbuf : public __streambuf
69 #else
70 class logbuf : public streambuf
71 #endif
72 {
73 public:
74
75 #ifndef SG_HAVE_STD_INCLUDES
76     typedef char_traits<char>           traits_type;
77     typedef char_traits<char>::int_type int_type;
78     // typedef char_traits<char>::pos_type pos_type;
79     // typedef char_traits<char>::off_type off_type;
80 #endif
81     // logbuf( streambuf* sb ) : sbuf(sb) {}
82     /** Constructor */
83     logbuf();
84
85     /** Destructor */
86     ~logbuf();
87
88     /**
89      * Is logging enabled?
90      * @return true or false*/
91     bool enabled() { return logging_enabled; }
92
93     /**
94      * Set the logging level of subsequent messages.
95      * @param c debug class
96      * @param p priority
97      */
98     void set_log_state( sgDebugClass c, sgDebugPriority p );
99
100     /**
101      * Set the global logging level.
102      * @param c debug class
103      * @param p priority
104      */
105     static void set_log_level( sgDebugClass c, sgDebugPriority p );
106
107
108     /**
109      * Set the allowed logging classes.
110      * @param c All enabled logging classes anded together.
111      */
112     static void set_log_classes (sgDebugClass c);
113
114
115     /**
116      * Get the logging classes currently enabled.
117      * @return All enabled debug logging anded together.
118      */
119     static sgDebugClass get_log_classes ();
120
121
122     /**
123      * Set the logging priority.
124      * @param c The priority cutoff for logging messages.
125      */
126     static void set_log_priority (sgDebugPriority p);
127
128
129     /**
130      * Get the current logging priority.
131      * @return The priority cutoff for logging messages.
132      */
133     static sgDebugPriority get_log_priority ();
134
135
136     /**
137      * Set the stream buffer
138      * @param sb stream buffer
139      */
140     void set_sb( streambuf* sb );
141
142 protected:
143
144     /** sync/flush */
145     inline virtual int sync();
146
147     /** overflow */
148     int_type overflow( int ch );
149     // int xsputn( const char* s, istreamsize n );
150
151 private:
152
153     // The streambuf used for actual output. Defaults to cerr.rdbuf().
154     static streambuf* sbuf;
155
156     static bool logging_enabled;
157     static sgDebugClass logClass;
158     static sgDebugPriority logPriority;
159
160 private:
161
162     // Not defined.
163     logbuf( const logbuf& );
164     void operator= ( const logbuf& );
165 };
166
167 inline int
168 logbuf::sync()
169 {
170 #ifdef SG_HAVE_STD_INCLUDES
171         return sbuf->pubsync();
172 #else
173         return sbuf->sync();
174 #endif
175 }
176
177 inline void
178 logbuf::set_log_state( sgDebugClass c, sgDebugPriority p )
179 {
180     logging_enabled = ((c & logClass) != 0 && p >= logPriority);
181 }
182
183 inline logbuf::int_type
184 logbuf::overflow( int c )
185 {
186 #ifdef _MSC_VER
187     static bool has_console = false;
188     if ( logging_enabled ) {
189         if ( !has_console ) {
190             AllocConsole();
191             freopen("conin$", "r", stdin);
192             freopen("conout$", "w", stdout);
193             freopen("conout$", "w", stderr);
194             has_console = true;
195         }
196         return sbuf->sputc(c);
197     }
198     else
199         return EOF == 0 ? 1: 0;
200 #else
201     return logging_enabled ? sbuf->sputc(c) : (EOF == 0 ? 1: 0);
202 #endif
203 }
204
205 /**
206  * logstream manipulator for setting the log level of a message.
207  */
208 struct loglevel
209 {
210     loglevel( sgDebugClass c, sgDebugPriority p )
211         : logClass(c), logPriority(p) {}
212
213     sgDebugClass logClass;
214     sgDebugPriority logPriority;
215 };
216
217 /**
218  * A helper class that ensures a streambuf and ostream are constructed and
219  * destroyed in the correct order.  The streambuf must be created before the
220  * ostream but bases are constructed before members.  Thus, making this class
221  * a private base of logstream, declared to the left of ostream, we ensure the
222  * correct order of construction and destruction.
223  */
224 struct logstream_base
225 {
226     // logstream_base( streambuf* sb ) : lbuf(sb) {}
227     logstream_base() {}
228
229     logbuf lbuf;
230 };
231
232 /**
233  * Class to manage the debug logging stream.
234  */
235 class logstream : private logstream_base, public ostream
236 {
237 public:
238     /**
239      * The default is to send messages to cerr.
240      * @param out output stream
241      */
242     logstream( ostream& out )
243         // : logstream_base(out.rdbuf()),
244         : logstream_base(),
245           ostream(&lbuf) { lbuf.set_sb(out.rdbuf());}
246
247     /**
248      * Set the output stream
249      * @param out output stream
250      */
251     void set_output( ostream& out ) { lbuf.set_sb( out.rdbuf() ); }
252
253     /**
254      * Set the global log class and priority level.
255      * @param c debug class
256      * @param p priority
257      */
258     void setLogLevels( sgDebugClass c, sgDebugPriority p );
259
260     /**
261      * Output operator to capture the debug level and priority of a message.
262      * @param l log level
263      */
264     inline ostream& operator<< ( const loglevel& l );
265 };
266
267 inline ostream&
268 logstream::operator<< ( const loglevel& l )
269 {
270     lbuf.set_log_state( l.logClass, l.logPriority );
271     return *this;
272 }
273
274 extern logstream *global_logstream;
275
276 /**
277  * \relates logstream
278  * Return the one and only logstream instance.
279  * We use a function instead of a global object so we are assured that cerr
280  * has been initialised.
281  * @return current logstream
282  */
283 inline logstream&
284 sglog()
285 {
286   if (global_logstream == NULL) {
287
288 #ifdef __APPLE__
289     /**
290      * There appears to be a bug in the C++ runtime in Mac OS X that
291      * will crash if certain funtions are called (in this case
292      * cerr.rdbuf()) during static initialization of a class. This
293      * print statement is hack to kick the library in the pants so it
294      * won't crash when cerr.rdbuf() is first called -DW 
295      **/
296     cout << "Using Mac OS X hack for initializing C++ stdio..." << endl;
297 #endif    
298     global_logstream = new logstream (cerr);
299   }
300     
301   return *global_logstream;
302 }
303
304
305 /** \def SG_LOG(C,P,M)
306  * Log a message.
307  * @param C debug class
308  * @param P priority
309  * @param M message
310  */
311 #ifdef FG_NDEBUG
312 # define SG_LOG(C,P,M)
313 #elif defined( __MWERKS__ )
314 # define SG_LOG(C,P,M) ::sglog() << ::loglevel(C,P) << M << std::endl
315 #else
316 # define SG_LOG(C,P,M) sglog() << loglevel(C,P) << M << endl
317 #endif
318
319
320 #endif // _LOGSTREAM_H
321