]> git.mxchange.org Git - simgear.git/blob - simgear/debug/logstream.hxx
fd1c878c77647064801fd946f00881941ffebf9b
[simgear.git] / simgear / debug / logstream.hxx
1 // Stream based logging mechanism.
2 //
3 // Written by Bernie Bright, 1998
4 //
5 // Copyright (C) 1998  Bernie Bright - bbright@c031.aone.net.au
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Library General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU Library General Public
18 // License along with this library; if not, write to the
19 // Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 // Boston, MA  02111-1307, USA.
21 //
22 // $Id$
23
24 #ifndef _LOGSTREAM_H
25 #define _LOGSTREAM_H
26
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30
31
32 #include <simgear/compiler.h>
33
34 // At least Irix needs this
35 #ifdef FG_HAVE_NATIVE_SGI_COMPILERS
36 #include <char_traits.h>
37 #endif
38
39 #ifdef SG_HAVE_STD_INCLUDES
40 # include <streambuf>
41 # include <iostream>
42 #else
43 # include <iostream.h>
44 # include <simgear/fg_traits.hxx>
45 #endif
46
47 #include <simgear/debug/debug_types.h>
48
49 #ifndef FG_HAVE_NATIVE_SGI_COMPILERS
50 FG_USING_STD(streambuf);
51 FG_USING_STD(ostream);
52 FG_USING_STD(cerr);
53 FG_USING_STD(endl);
54 #else
55 FG_USING_STD(char_traits);
56 #endif
57
58 #ifdef __MWERKS__
59 FG_USING_STD(iostream);
60 #endif
61
62 //
63 // TODO:
64 //
65 // 1. Change output destination. Done.
66 // 2. Make logbuf thread safe.
67 // 3. Read environment for default debugClass and debugPriority.
68 //
69
70 //-----------------------------------------------------------------------------
71 //
72 // logbuf is an output-only streambuf with the ability to disable sets of
73 // messages at runtime. Only messages with priority >= logbuf::logPriority
74 // and debugClass == logbuf::logClass are output.
75 //
76 class logbuf : public streambuf
77 {
78 public:
79
80 #ifndef SG_HAVE_STD_INCLUDES
81     typedef char_traits<char>           traits_type;
82     typedef char_traits<char>::int_type int_type;
83     // typedef char_traits<char>::pos_type pos_type;
84     // typedef char_traits<char>::off_type off_type;
85 #endif
86 //     logbuf( streambuf* sb ) : sbuf(sb) {}
87     logbuf();
88     ~logbuf();
89
90     // Is logging enabled?
91     bool enabled() { return logging_enabled; }
92
93     // Set the logging level of subsequent messages.
94     void set_log_state( fgDebugClass c, fgDebugPriority p );
95
96     // Set the global logging level.
97     static void set_log_level( fgDebugClass c, fgDebugPriority p );
98
99     //
100     void set_sb( streambuf* sb );
101
102 protected:
103
104     inline virtual int sync();
105     int_type overflow( int ch );
106 //     int xsputn( const char* s, istreamsize n );
107
108 private:
109
110     // The streambuf used for actual output. Defaults to cerr.rdbuf().
111     static streambuf* sbuf;
112
113     static bool logging_enabled;
114     static fgDebugClass logClass;
115     static fgDebugPriority logPriority;
116
117 private:
118
119     // Not defined.
120     logbuf( const logbuf& );
121     void operator= ( const logbuf& );
122 };
123
124 inline int
125 logbuf::sync()
126 {
127 #ifdef SG_HAVE_STD_INCLUDES
128         return sbuf->pubsync();
129 #else
130         return sbuf->sync();
131 #endif
132 }
133
134 inline void
135 logbuf::set_log_state( fgDebugClass c, fgDebugPriority p )
136 {
137     logging_enabled = ((c & logClass) != 0 && p >= logPriority);
138 }
139
140 inline logbuf::int_type
141 logbuf::overflow( int c )
142 {
143     return logging_enabled ? sbuf->sputc(c) : (EOF == 0 ? 1: 0);
144 }
145
146 //-----------------------------------------------------------------------------
147 //
148 // logstream manipulator for setting the log level of a message.
149 //
150 struct loglevel
151 {
152     loglevel( fgDebugClass c, fgDebugPriority p )
153         : logClass(c), logPriority(p) {}
154
155     fgDebugClass logClass;
156     fgDebugPriority logPriority;
157 };
158
159 //-----------------------------------------------------------------------------
160 //
161 // A helper class that ensures a streambuf and ostream are constructed and
162 // destroyed in the correct order.  The streambuf must be created before the
163 // ostream but bases are constructed before members.  Thus, making this class
164 // a private base of logstream, declared to the left of ostream, we ensure the
165 // correct order of construction and destruction.
166 //
167 struct logstream_base
168 {
169 //     logstream_base( streambuf* sb ) : lbuf(sb) {}
170     logstream_base() {}
171
172     logbuf lbuf;
173 };
174
175 //-----------------------------------------------------------------------------
176 //
177 // 
178 //
179 class logstream : private logstream_base, public ostream
180 {
181 public:
182     // The default is to send messages to cerr.
183     logstream( ostream& out )
184 //      : logstream_base(out.rdbuf()),
185         : logstream_base(),
186           ostream(&lbuf) { lbuf.set_sb(out.rdbuf());}
187
188     void set_output( ostream& out ) { lbuf.set_sb( out.rdbuf() ); }
189
190     // Set the global log class and priority level.
191      void setLogLevels( fgDebugClass c, fgDebugPriority p );
192
193     // Output operator to capture the debug level and priority of a message.
194     inline ostream& operator<< ( const loglevel& l );
195 };
196
197 inline ostream&
198 logstream::operator<< ( const loglevel& l )
199 {
200     lbuf.set_log_state( l.logClass, l.logPriority );
201     return *this;
202 }
203
204 //-----------------------------------------------------------------------------
205 //
206 // Return the one and only logstream instance.
207 // We use a function instead of a global object so we are assured that cerr
208 // has been initialised.
209 //
210 inline logstream&
211 fglog()
212 {
213     static logstream logstrm( cerr );
214     return logstrm;
215 }
216
217 #ifdef FG_NDEBUG
218 # define FG_LOG(C,P,M)
219 #elif defined( __MWERKS__ )
220 # define FG_LOG(C,P,M) ::fglog() << ::loglevel(C,P) << M << std::endl
221 #else
222 # define FG_LOG(C,P,M) fglog() << loglevel(C,P) << M << endl
223 #endif
224
225 #endif // _LOGSTREAM_H
226