]> git.mxchange.org Git - simgear.git/blob - simgear/debug/logstream.hxx
Modified Files:
[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 #ifdef _MSC_VER
143     static void has_no_console() { has_console = false; }
144 #endif
145
146 protected:
147
148     /** sync/flush */
149     inline virtual int sync();
150
151     /** overflow */
152     int_type overflow( int ch );
153     // int xsputn( const char* s, istreamsize n );
154
155 private:
156
157     // The streambuf used for actual output. Defaults to cerr.rdbuf().
158     static streambuf* sbuf;
159
160     static bool logging_enabled;
161 #ifdef _MSC_VER
162     static bool has_console;
163 #endif
164     static sgDebugClass logClass;
165     static sgDebugPriority logPriority;
166
167 private:
168
169     // Not defined.
170     logbuf( const logbuf& );
171     void operator= ( const logbuf& );
172 };
173
174 inline int
175 logbuf::sync()
176 {
177 #ifdef SG_HAVE_STD_INCLUDES
178         return sbuf->pubsync();
179 #else
180         return sbuf->sync();
181 #endif
182 }
183
184 inline void
185 logbuf::set_log_state( sgDebugClass c, sgDebugPriority p )
186 {
187     logging_enabled = ((c & logClass) != 0 && p >= logPriority);
188 }
189
190 inline logbuf::int_type
191 logbuf::overflow( int c )
192 {
193 #ifdef _MSC_VER
194     if ( logging_enabled ) {
195         if ( !has_console ) {
196             AllocConsole();
197             freopen("conin$", "r", stdin);
198             freopen("conout$", "w", stdout);
199             freopen("conout$", "w", stderr);
200             has_console = true;
201         }
202         return sbuf->sputc(c);
203     }
204     else
205         return EOF == 0 ? 1: 0;
206 #else
207     return logging_enabled ? sbuf->sputc(c) : (EOF == 0 ? 1: 0);
208 #endif
209 }
210
211 /**
212  * logstream manipulator for setting the log level of a message.
213  */
214 struct loglevel
215 {
216     loglevel( sgDebugClass c, sgDebugPriority p )
217         : logClass(c), logPriority(p) {}
218
219     sgDebugClass logClass;
220     sgDebugPriority logPriority;
221 };
222
223 /**
224  * A helper class that ensures a streambuf and ostream are constructed and
225  * destroyed in the correct order.  The streambuf must be created before the
226  * ostream but bases are constructed before members.  Thus, making this class
227  * a private base of logstream, declared to the left of ostream, we ensure the
228  * correct order of construction and destruction.
229  */
230 struct logstream_base
231 {
232     // logstream_base( streambuf* sb ) : lbuf(sb) {}
233     logstream_base() {}
234
235     logbuf lbuf;
236 };
237
238 /**
239  * Class to manage the debug logging stream.
240  */
241 class logstream : private logstream_base, public ostream
242 {
243 public:
244     /**
245      * The default is to send messages to cerr.
246      * @param out output stream
247      */
248     logstream( ostream& out )
249         // : logstream_base(out.rdbuf()),
250         : logstream_base(),
251           ostream(&lbuf) { lbuf.set_sb(out.rdbuf());}
252
253     /**
254      * Set the output stream
255      * @param out output stream
256      */
257     void set_output( ostream& out ) { lbuf.set_sb( out.rdbuf() ); }
258
259     /**
260      * Set the global log class and priority level.
261      * @param c debug class
262      * @param p priority
263      */
264     void setLogLevels( sgDebugClass c, sgDebugPriority p );
265
266     /**
267      * Output operator to capture the debug level and priority of a message.
268      * @param l log level
269      */
270     inline ostream& operator<< ( const loglevel& l );
271 };
272
273 inline ostream&
274 logstream::operator<< ( const loglevel& l )
275 {
276     lbuf.set_log_state( l.logClass, l.logPriority );
277     return *this;
278 }
279
280 extern logstream *global_logstream;
281
282 /**
283  * \relates logstream
284  * Return the one and only logstream instance.
285  * We use a function instead of a global object so we are assured that cerr
286  * has been initialised.
287  * @return current logstream
288  */
289 inline logstream&
290 sglog()
291 {
292   if (global_logstream == NULL) {
293
294 #ifdef __APPLE__
295     /**
296      * There appears to be a bug in the C++ runtime in Mac OS X that
297      * will crash if certain funtions are called (in this case
298      * cerr.rdbuf()) during static initialization of a class. This
299      * print statement is hack to kick the library in the pants so it
300      * won't crash when cerr.rdbuf() is first called -DW 
301      **/
302     cout << "Using Mac OS X hack for initializing C++ stdio..." << endl;
303 #endif    
304     global_logstream = new logstream (cerr);
305   }
306     
307   return *global_logstream;
308 }
309
310
311 /** \def SG_LOG(C,P,M)
312  * Log a message.
313  * @param C debug class
314  * @param P priority
315  * @param M message
316  */
317 #ifdef FG_NDEBUG
318 # define SG_LOG(C,P,M)
319 #elif defined( __MWERKS__ )
320 # define SG_LOG(C,P,M) ::sglog() << ::loglevel(C,P) << M << std::endl
321 #else
322 # define SG_LOG(C,P,M) sglog() << loglevel(C,P) << M << endl
323 #endif
324
325
326 #endif // _LOGSTREAM_H
327