1 // $Header$
2 //
3 // Copyright (C) 2000 - 2004, by
4 //
5 // Carlo Wood, Run on IRC <carlo@alinoe.com>
6 // RSA-1024 0x624ACAD5 1997-01-26                    Sign & Encrypt
7 // Fingerprint16 = 32 EC A7 B6 AC DB 65 A6  F6 F6 55 DD 1C DC FF 61
8 //
9 // This file may be distributed under the terms of the Q Public License
10 // version 1.0 as appearing in the file LICENSE.QPL included in the
11 // packaging of this file.
12 //
13 
14 /** \file class_debug.h
15  * Do not include this header file directly, instead include \ref preparation_step2 "debug.h".
16  */
17 
18 #ifndef LIBCWD_CLASS_DEBUG_H
19 #define LIBCWD_CLASS_DEBUG_H
20 
21 #ifndef LIBCWD_CONFIG_H
22 #include <libcwd/config.h>
23 #endif
24 #ifndef LIBCWD_CLASS_CHANNEL_SET_H
25 #include <libcwd/class_channel_set.h>
26 #endif
27 #ifndef LIBCWD_PRIVATE_STRUCT_TSD_H
28 #include <libcwd/private_struct_TSD.h>
29 #endif
30 #ifndef LIBCWD_STRUCT_DEBUG_TSD_H
31 #include <libcwd/struct_debug_tsd.h>
32 #endif
33 #ifndef LIBCWD_PRIVATE_LOCK_INTERFACE_H
34 #include <libcwd/private_lock_interface.h>
35 #endif
36 #ifndef LIBCW_IOSFWD
37 #define LIBCW_IOSFWD
38 #include <iosfwd>
39 #endif
40 
41 namespace libcwd {
42 
43 class buffer_ct;
44 
45 #if CWDEBUG_ALLOC
46 namespace _private_ {
47 
48 struct debug_message_st {
49   struct debug_message_st* next;
50   struct debug_message_st* prev;
51   int curlen;
52   char buf[sizeof(int)];
53 };
54 
55 } // namespace _private_
56 #endif
57 
58 //===================================================================================================
59 // class debug_ct
60 //
61 // Note: Debug output is printed already *before* this object is constructed,
62 // and is still printed when this object is already destructed.
63 // This is why initialization is done with method init() *before* construction
64 // and debug is turned off when this object is destructed.
65 // I hope that this is no problem because libcwd::libcw_do is a global object.
66 // It means however that this object can not contain any attributes that have
67 // a constructor of their own!
68 
69 /**
70  * \class debug_ct debug.h libcwd/debug.h
71  * \ingroup group_debug_object
72  *
73  * \brief The %Debug Object class, this object represents one output device (<code>ostream</code>).
74  *
75  * See \ref group_debug_object.
76  */
77 class debug_ct {
78   friend void debug_tsd_st::start(debug_ct&, channel_set_data_st& LIBCWD_COMMA_TSD_PARAM);
79   friend void debug_tsd_st::finish(debug_ct &, channel_set_data_st& LIBCWD_COMMA_TSD_PARAM);
80 #ifdef LIBCWD_DOXYGEN
81 protected:
82 #else
83 public: // Only public because macro LibcwDout needs acces, don't access this directly.
84 #endif
85 #if LIBCWD_THREAD_SAFE
86   int WNS_index;
87   static int S_index_count;
88 #else
89   //-------------------------------------------------------------------------------------------------
90   // Put the otherwise Thread Specific Data of this debug object
91   // directly into the object when we don't use threads.
92   //
93 
94   debug_tsd_st tsd;
95 #endif
96 
97 protected:
98   //-------------------------------------------------------------------------------------------------
99   // Protected attributes.
100   //
101 
102   std::ostream* real_os;
103     // The original output ostream (as set with set_ostream()).
104     //
105 #if LIBCWD_THREAD_SAFE
106   friend class libcwd::buffer_ct;		// buffer_ct::writeto() needs access.
107   _private_::lock_interface_base_ct* M_mutex;
108     // Pointer to the mutex that should be used for `real_os' or NULL when no lock is used.
109     // A value of NULL is only allowed prior to creating a second thread.
110 
111   buffer_ct* unfinished_oss;
112   void const* newlineless_tsd;
113 #endif
114 
115 private:
116   //-------------------------------------------------------------------------------------------------
117   // Private attributes:
118   //
119 
120   bool WNS_initialized;
121     // Set to true when this object is initialized (by a call to NS_init()).
122 
123   bool NS_being_initialized;
124     // Set to true when this object is being initialized (by a call to NS_init()).
125 
126 #if CWDEBUG_DEBUG
127   long init_magic;
128     // Used to check if the trick with `WNS_initialized' really works.
129 #endif
130 
131   bool interactive;
132     // Set true if the last or current debug output is to cerr
133 
134 #if CWDEBUG_ALLOC
135 public:
136   _private_::debug_message_st* queue;
137   _private_::debug_message_st* queue_top;
138     // Queue of messages written inside malloc/realloc/calloc/free/new/delete.
139     // Locked by mutex provided through set_ostream.
140 #endif
141 
142 public:
143   /** \addtogroup group_formatting */
144   /** \{ */
145 
146   /**
147    * \brief The margin
148    *
149    * This is printed before the label.&nbsp;
150    * The margin can be manipulated directly using the methods of class debug_string_ct.
151    *
152    * \sa push_margin()
153    *  \n pop_margin()
154    */
155   debug_string_ct& margin(void);
156   debug_string_ct const& margin(void) const;
157 
158   /**
159    * \brief The marker
160    *
161    * This is printed after the label.&nbsp;
162    * The marker can be manipulated directly using the methods of class debug_string_ct.
163    *
164    * \sa push_marker()
165    *  \n pop_marker()
166    */
167   debug_string_ct& marker(void);
168   debug_string_ct const& marker(void) const;
169 
170   /** \} */
171 
172 public:
173   //-------------------------------------------------------------------------------------------------
174   // Manipulators and accessors for the "format" attributes:
175   //
176 
177   void set_indent(unsigned short indentation);
178   void inc_indent(unsigned short indentation);
179   void dec_indent(unsigned short indentation);
180   unsigned short get_indent(void) const;
181 
182   void push_margin(void);
183   void pop_margin(void);
184   void push_marker(void);
185   void pop_marker(void);
186 
187   //-------------------------------------------------------------------------------------------------
188   // Other accessors
189   //
190 
191   std::ostream* get_ostream(void) const;		// The original ostream set with set_ostream.
192 
193 private:
194   //-------------------------------------------------------------------------------------------------
195   // Initialization function.
196   //
197 
198   friend class channel_ct;
199   friend class fatal_channel_ct;
200   friend void ST_initialize_globals(LIBCWD_TSD_PARAM);
201 #if CWDEBUG_LOCATION
202   friend bool cwbfd::ST_init(LIBCWD_TSD_PARAM);
203 #endif
204   bool NS_init(LIBCWD_TSD_PARAM);
205     // Initialize this object, needed because debug output can be written
206     // from the constructors of (other) global objects, and from the malloc()
207     // family when CWDEBUG_ALLOC is set to 1.
208     // This will return false when it is called recursively which can happen
209     // as part of initialization of libcwd via a call to malloc while creating
210     // laf_ct -> buffer_ct --> basic_stringbuf.  In that case the initialization
211     // failed thus.  On success, it returns true.
212 
213 public:
214   //-------------------------------------------------------------------------------------------------
215   // Constructors and destructors.
216   //
217 
218   debug_ct(void);
219 
220 private:
221   void private_set_ostream(std::ostream* os);
222 
223 public:
224   //-------------------------------------------------------------------------------------------------
225   // Manipulators:
226   //
227 
228   void set_ostream(std::ostream* os);
229 #if LIBCWD_THREAD_SAFE || defined(LIBCWD_DOXYGEN)
230   template<class T>
231     void set_ostream(std::ostream* os, T* mutex);
232 #ifdef LIBCWD_DOXYGEN
233   // Specialization.
234   template<>
235     void set_ostream(std::ostream* os, pthread_mutex_t* mutex);
236 #endif
237 #endif
238   void off(void);
239   void on(void);
240 
241   struct OnOffState {
242     int _off;
243 #if CWDEBUG_DEBUGOUTPUT
244     bool first_time;
245 #endif
246   };
247 
248   void force_on(OnOffState& state);
249   void restore(OnOffState const& state);
250 };
251 
252 #if LIBCWD_THREAD_SAFE && !defined(LIBCWD_DOXYGEN)
253 // Specialization.
254 template<>
255   void debug_ct::set_ostream(std::ostream* os, pthread_mutex_t* mutex);
256 #endif
257 
258 }  // namespace libcwd
259 
260 #ifndef LIBCWD_SET_OSTREAM_INL
261 #include <libcwd/set_ostream.inl>
262 #endif
263 
264 #endif // LIBCWD_CLASS_DEBUG_H
265 
266