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