1 /**************************************************************************
2  Copyright:
3       (C) 2008 - 2012  Alexander Shaduri <ashaduri 'at' gmail.com>
4  License: See LICENSE_zlib.txt file
5 ***************************************************************************/
6 /// \file
7 /// \author Alexander Shaduri
8 /// \ingroup hz
9 /// \weakgroup hz
10 /// @{
11 
12 #ifndef HZ_DEBUG_H
13 #define HZ_DEBUG_H
14 
15 #include "hz_config.h"  // feature macros
16 
17 #include <cstdio>  // std::fprintf(), std::vfprintf()
18 
19 #ifndef __GNUC__
20 	#include <cstdarg>  // std::va_start, va_list macro and friends
21 #endif
22 
23 
24 /*
25 #include <cassert>
26 #ifndef ASSERT  // assert() is undefined if NDEBUG is defined.
27 #	define ASSERT(a) assert(a)
28 #endif
29 */
30 
31 /**
32 \file
33 This file is a link between libhz (and its users) and libdebug.
34 It provides a way to write in libdebug-like API without actually
35 using libdebug.
36 
37 Note that it provides only output functions. The setup functions
38 cannot be emulated (but you probably won't need them in libraries
39 anyway).
40 */
41 
42 
43 // Use libdebug as is
44 #if defined(HZ_USE_LIBDEBUG) && (HZ_USE_LIBDEBUG)
45 
46 	// only output functions
47 	#include "libdebug/libdebug_mini.h"
48 
49 
50 #else
51 
52 	// undef them in case libdebug was included
53 	#ifdef debug_out_dump
54 		#undef debug_out_dump
55 	#endif
56 	#ifdef debug_out_info
57 		#undef debug_out_info
58 	#endif
59 	#ifdef debug_out_warn
60 		#undef debug_out_warn
61 	#endif
62 	#ifdef debug_out_error
63 		#undef debug_out_error
64 	#endif
65 	#ifdef debug_out_fatal
66 		#undef debug_out_fatal
67 	#endif
68 
69 	#ifdef debug_print_dump
70 		#undef debug_print_dump
71 	#endif
72 	#ifdef debug_print_info
73 		#undef debug_print_info
74 	#endif
75 	#ifdef debug_print_warn
76 		#undef debug_print_warn
77 	#endif
78 	#ifdef debug_print_error
79 		#undef debug_print_error
80 	#endif
81 	#ifdef debug_print_fatal
82 		#undef debug_print_fatal
83 	#endif
84 
85 	#ifdef DBG_FILE
86 		#undef DBG_FILE
87 	#endif
88 	#ifdef DBG_LINE
89 		#undef DBG_LINE
90 	#endif
91 	#ifdef DBG_FUNC_NAME
92 		#undef DBG_FUNC_NAME
93 	#endif
94 	#ifdef DBG_FUNC_PRNAME
95 		#undef DBG_FUNC_PRNAME
96 	#endif
97 	#ifdef DBG_FUNC
98 		#undef DBG_FUNC
99 	#endif
100 	#ifdef DBG_FUNC_MSG
101 		#undef DBG_FUNC_MSG
102 	#endif
103 
104 	#ifdef DBG_POS
105 		#undef DBG_POS
106 	#endif
107 
108 	#ifdef DBG_TRACE_POINT_MSG
109 		#undef DBG_TRACE_POINT_MSG
110 	#endif
111 	#ifdef DBG_TRACE_POINT_AUTO
112 		#undef DBG_TRACE_POINT_AUTO
113 	#endif
114 
115 	#ifdef DBG_FUNCTION_ENTER_MSG
116 		#undef DBG_FUNCTION_ENTER_MSG
117 	#endif
118 	#ifdef DBG_FUNCTION_EXIT_MSG
119 		#undef DBG_FUNCTION_EXIT_MSG
120 	#endif
121 
122 	#ifdef DBG_ASSERT_MSG
123 		#undef DBG_ASSERT_MSG
124 	#endif
125 	#ifdef DBG_ASSERT
126 		#undef DBG_ASSERT
127 	#endif
128 
129 
130 	// emulate libdebug API through std::cerr
131 	#if defined(HZ_EMULATE_LIBDEBUG) && HZ_EMULATE_LIBDEBUG
132 
133 		#include <iostream>
134 		#include <cstdio>
135 		#include <string>
136 
137 		// cerr / stderr have no buffering, so no need to sync them with each other.
138 
139 
140 		#define debug_out_dump(domain, output) \
141 			std::cerr << "<dump>  [" << (domain) << "] " << output
142 
143 		#define debug_out_info(domain, output) \
144 			std::cerr << "<info>  [" << (domain) << "] " << output
145 
146 		#define debug_out_warn(domain, output) \
147 			std::cerr << "<warn>  [" << (domain) << "] " << output
148 
149 		#define debug_out_error(domain, output) \
150 			std::cerr << "<error> [" << (domain) << "] " << output
151 
152 		#define debug_out_fatal(domain, output) \
153 			std::cerr << "<fatal> [" << (domain) << "] " << output
154 
155 
156 
157 		#ifdef __GNUC__
158 
159 			// The "trim trailing comma" and "##" extensions are GNU features (works with intel too).
160 			// The ## part is needed to avoid requirement of at least one argument after "format".
161 
162 			#define debug_print_dump(domain, format, ...) \
163 				std::fprintf(stderr, (std::string("<dump>  [") + (domain) + "] " + format).c_str(), ## __VA_ARGS__)
164 
165 			#define debug_print_info(domain, format, ...) \
166 				std::fprintf(stderr, (std::string("<info>  [") + (domain) + "] " + format).c_str(), ## __VA_ARGS__)
167 
168 			#define debug_print_warn(domain, format, ...) \
169 				std::fprintf(stderr, (std::string("<warn>  [") + (domain) + "] " + format).c_str(), ## __VA_ARGS__)
170 
171 			#define debug_print_error(domain, format, ...) \
172 				std::fprintf(stderr, (std::string("<error> [") + (domain) + "] " + format).c_str(), ## __VA_ARGS__)
173 
174 			#define debug_print_fatal(domain, format, ...) \
175 				std::fprintf(stderr, (std::string("<fatal> [") + (domain) + "] " + format).c_str(), ## __VA_ARGS__)
176 
177 
178 
179 		#else  // non-gcc compilers:
180 
181 			namespace hz {
182 				namespace internal {
debug_print_impl(const std::string & header,const char * format,...)183 					inline void debug_print_impl(const std::string& header, const char* format, ...)
184 					{
185 						std::va_list ap;
186 						va_start(ap, format);
187 						std::vfprintf(stderr, (header + format).c_str(), ap);
188 						va_end(ap);
189 					}
190 				}
191 			}
192 
193 			#define debug_print_dump(domain, ...) \
194 				hz::internal::debug_print_impl(std::string("<dump> [") + (domain) + "] ", __VA_ARGS__)
195 
196 			#define debug_print_info(domain, ...) \
197 				hz::internal::debug_print_impl(std::string("<info> [") + (domain) + "] ", __VA_ARGS__)
198 
199 			#define debug_print_warn(domain, ...) \
200 				hz::internal::debug_print_impl(std::string("<warn> [") + (domain) + "] ", __VA_ARGS__)
201 
202 			#define debug_print_error(domain, ...) \
203 				hz::internal::debug_print_impl(std::string("<error> [") + (domain) + "] ", __VA_ARGS__)
204 
205 			#define debug_print_fatal(domain, ...) \
206 				hz::internal::debug_print_impl(std::string("<fatal> [") + (domain) + "] ", __VA_ARGS__)
207 
208 
209 		#endif
210 
211 
212 
213 		#define DBG_FILE __FILE__
214 		#define DBG_LINE __LINE__
215 
216 
217 		#if defined HAVE_CXX___func__ && HAVE_CXX___func__
218 			#define DBG_FUNC_NAME __func__
219 		#elif defined HAVE_CXX___FUNCTION__ && HAVE_CXX___FUNCTION__
220 			#define DBG_FUNC_NAME __FUNCTION__
221 		#else
222 			#define DBG_FUNC_NAME "unknown"
223 		#endif
224 
225 		#ifdef __GNUC__
226 			#define DBG_FUNC_PRNAME __PRETTY_FUNCTION__
227 		#else
228 			#define DBG_FUNC_PRNAME DBG_FUNC_NAME
229 		#endif
230 
231 
232 		#include <string>
233 
234 		namespace hz {
235 			namespace internal {
format_function_msg(const std::string & func,bool add_suffix)236 				inline std::string format_function_msg(const std::string& func, bool add_suffix)
237 				{
238 					// if it's "bool<unnamed>::A::func(int)" or "bool test::A::func(int)",
239 					// remove the return type and parameters.
240 					std::string::size_type endpos = func.find('(');
241 					if (endpos == std::string::npos)
242 						endpos = func.size();
243 
244 					// search for first space (after the parameter), or "<unnamed>".
245 					std::string::size_type pos = func.find_first_of(" >");
246 					if (pos != std::string::npos) {
247 						if (func[pos] == '>')
248 							pos += 2;  // skip ::
249 						++pos;  // skip whatever character we're over
250 						// debug_out_info("default", "pos: " << pos << ", endpos: " << endpos << "\n");
251 						return func.substr(pos >= endpos ? 0 : pos, endpos - pos) + (add_suffix ? "(): " : "()");
252 					}
253 					return func.substr(0, endpos) + (add_suffix ? "(): " : "()");
254 				}
255 			}
256 		}
257 
258 		#define DBG_FUNC (hz::internal::format_function_msg(DBG_FUNC_PRNAME, false).c_str())
259 
260 		#define DBG_FUNC_MSG (hz::internal::format_function_msg(DBG_FUNC_PRNAME, true).c_str())
261 
262 
263 		// Note: DBG_POS is not an object if emulated or disabled! Only valid for outputting to streams.
264 		#define DBG_POS "(function: " << DBG_FUNC_NAME << "(), file: " << DBG_FILE \
265 				<< ", line: " << DBG_LINE << ")"
266 
267 
268 		#define DBG_TRACE_POINT_MSG(a) debug_out_dump("default", "Trace point \"" << #a << "\" reached at " << DBG_POS << ".\n")
269 		#define DBG_TRACE_POINT_AUTO debug_out_dump("default", "Trace point reached at " << DBG_POS << ".\n")
270 
271 		#define DBG_FUNCTION_ENTER_MSG debug_out_dump("default", "ENTER: \"" << DBG_FUNC << "\"\n")
272 		#define DBG_FUNCTION_EXIT_MSG debug_out_dump("default", "EXIT:  \"" << DBG_FUNC << "\"\n")
273 
274 
275 		#define DBG_ASSERT_MSG(cond, msg) \
276 		if (true) { \
277 			if (!(cond)) \
278 				debug_out_error("default", (msg) << "\n"); \
279 		} else (void)0
280 
281 		#define DBG_ASSERT(cond) \
282 		if (true) { \
283 			if (!(cond)) \
284 				debug_out_error("default", "ASSERTION FAILED: " << #cond << " at " << DBG_POS << "\n"); \
285 		} else (void)0
286 
287 
288 	// No output at all
289 	#else
290 
291 		// do/while block is needed to:
292 		// 1. make " if(a) debug_out_info(); f(); " work correctly.
293 		// 2. require terminating semicolon.
294 		#define debug_out_dump(domain, output) if(true){}else(void)0
295 		#define debug_out_info(domain, output) if(true){}else(void)0
296 		#define debug_out_warn(domain, output) if(true){}else(void)0
297 		#define debug_out_error(domain, output) if(true){}else(void)0
298 		#define debug_out_fatal(domain, output) if(true){}else(void)0
299 
300 		#define debug_print_dump(domain, format, ...) if(true){}else(void)0
301 		#define debug_print_info(domain, format, ...) if(true){}else(void)0
302 		#define debug_print_warn(domain, format, ...) if(true){}else(void)0
303 		#define debug_print_error(domain, format, ...) if(true){}else(void)0
304 		#define debug_print_fatal(domain, format, ...) if(true){}else(void)0
305 
306 		#define DBG_FILE ""
307 		#define DBG_LINE 0
308 
309 		#define DBG_FUNC_NAME ""
310 		#define DBG_FUNC_PRNAME ""
311 		#define DBG_FUNC ""
312 		#define DBG_FUNC_MSG ""
313 
314 		// Note: DBG_POS is not an object if emulated or disabled!
315 		#define DBG_POS ""
316 
317 		#define DBG_TRACE_POINT_MSG(a) if(true){}else(void)0
318 		#define DBG_TRACE_POINT_AUTO if(true){}else(void)0
319 
320 		#define DBG_FUNCTION_ENTER_MSG if(true){}else(void)0
321 		#define DBG_FUNCTION_EXIT_MSG if(true){}else(void)0
322 
323 		#define DBG_ASSERT_MSG(cond, msg) if(true){}else(void)0
324 		#define DBG_ASSERT(cond) if(true){}else(void)0
325 
326 	#endif
327 
328 
329 	// other stuff, emulated or not
330 
331 // 	#ifdef debug_begin
332 // 		#undef debug_begin
333 // 	#endif
334 	#define debug_begin() if(true){}else(void)0
335 
336 // 	#ifdef debug_end
337 // 		#undef debug_end
338 // 	#endif
339 	#define debug_end() if(true){}else(void)0
340 
341 
342 	#define debug_indent_inc(...) if(true){}else(void)0
343 	#define debug_indent_dec(...) if(true){}else(void)0
344 	#define debug_indent_reset() if(true){}else(void)0
345 
346 	#define debug_indent ""
347 	#define debug_unindent ""
348 	#define debug_resindent ""
349 
350 
351 
352 #endif
353 
354 
355 
356 
357 
358 
359 
360 
361 
362 
363 
364 #endif
365 
366 /// @}
367