1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4 
5 This file is part of GtkRadiant.
6 
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 
12 GtkRadiant 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
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21 
22 #if !defined(INCLUDED_DEBUGGING_DEBUGGING_H)
23 #define INCLUDED_DEBUGGING_DEBUGGING_H
24 
25 /**
26  * @file
27  * @brief Debugging macros for fatal error/assert messages.
28  */
29 
30 #include "../../../../shared/cxx.h"
31 #include "stream/textstream.h"
32 #include "generic/static.h"
33 
34 #if defined __i386__ && GCC_ATLEAST(2, 0)
35 #define DEBUGGER_BREAKPOINT() __asm__ __volatile__ ("int $03")
36 #else
37 #include <signal.h>
38 #define DEBUGGER_BREAKPOINT() raise(SIGTRAP);
39 #endif
40 
41 #define STR(x)	#x
42 #define STR2(x)	STR(x)
43 #define FILE_LINE __FILE__ ":" STR2(__LINE__)
44 
45 class DebugMessageHandler {
46 public:
~DebugMessageHandler()47 	virtual ~DebugMessageHandler(){}
48 	virtual TextOutputStream& getOutputStream() = 0;
49 	virtual bool handleMessage() = 0;
50 };
51 
52 class NullDebugMessageHandler : public NullOutputStream, public DebugMessageHandler {
53 public:
getOutputStream()54 	virtual TextOutputStream& getOutputStream() {
55 		return *this;
56 	}
handleMessage()57 	virtual bool handleMessage() {
58 		return false;
59 	}
60 };
61 
62 class DefaultDebugMessageHandler : public DebugMessageHandler {
63 public:
getOutputStream()64 	virtual TextOutputStream& getOutputStream() {
65 		return globalErrorStream();
66 	}
handleMessage()67 	virtual bool handleMessage() {
68 #if defined(DEBUG)
69 		return false; // send debug-break
70 #else
71 		return true;
72 #endif
73 	}
74 };
75 
76 class DebugMessageHandlerRef : public DefaultDebugMessageHandler {
77 	DebugMessageHandler* m_handler;
78 public:
DebugMessageHandlerRef()79 	DebugMessageHandlerRef()
80 			: m_handler(this) {
81 	}
setHandler(DebugMessageHandler & handler)82 	void setHandler(DebugMessageHandler& handler) {
83 		m_handler = &handler;
84 	}
getHandler()85 	DebugMessageHandler& getHandler() {
86 		return *m_handler;
87 	}
88 };
89 
90 typedef Static<DebugMessageHandlerRef> GlobalDebugMessageHandler;
91 
globalDebugMessageHandler()92 inline DebugMessageHandler& globalDebugMessageHandler() {
93 	return GlobalDebugMessageHandler::instance().getHandler();
94 }
95 
96 #ifdef DEBUG
97 
98 /// \brief Sends a \p message to the current debug-message-handler text-output-stream if \p condition evaluates to false.
99 #define ASSERT_MESSAGE(condition, message) do{\
100 if(!(condition))\
101 {\
102   globalDebugMessageHandler().getOutputStream() << FILE_LINE "\nassertion failure: " << message << "\n";\
103   if(!globalDebugMessageHandler().handleMessage()) { DEBUGGER_BREAKPOINT(); }\
104 }} while(0)
105 
106 /// \brief Sends a \p message to the current debug-message-handler text-output-stream.
107 #define ERROR_MESSAGE(message) do{\
108 globalDebugMessageHandler().getOutputStream() << FILE_LINE "\nruntime error: " << message << "\n";\
109 if(!globalDebugMessageHandler().handleMessage()) { DEBUGGER_BREAKPOINT(); }} while(0)
110 
111 #define ASSERT_NOTNULL(ptr) ASSERT_MESSAGE(ptr != 0, "pointer \"" #ptr "\" is null")
112 
113 #else
114 
115 #define ASSERT_MESSAGE(condition, message)
116 #define ERROR_MESSAGE(message)
117 #define ASSERT_NOTNULL(ptr)
118 
119 #endif
120 
121 #endif
122