642283fd712ac2ebab842de4b576529ca1b6248a
[xonotic/netradiant.git] / libs / debugging / debugging.h
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 /// \file
26 /// \brief Debugging macros for fatal error/assert messages.
27
28 #include "stream/textstream.h"
29 #include "warnings.h"
30 #include "generic/static.h"
31
32 #if defined(_MSC_VER) && defined(_M_IX86)
33 #define DEBUGGER_BREAKPOINT() __asm { int 3 }
34 #elif defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2
35 #define DEBUGGER_BREAKPOINT() __asm__ __volatile__ ("int $03")
36 #else
37 #include <signal.h>
38
39 #define DEBUGGER_BREAKPOINT() raise(SIGTRAP);
40 #endif
41
42 #define STR(x)  #x
43 #define STR2(x) STR(x)
44 #define FILE_LINE __FILE__ ":" STR2(__LINE__)
45
46 #if defined(_DEBUG) || 1
47 #define DEBUG_ASSERTS
48 #endif
49
50 class DebugMessageHandler
51 {
52 public:
53   virtual TextOutputStream& getOutputStream() = 0;
54   virtual bool handleMessage() = 0;
55 };
56
57 class NullDebugMessageHandler : public NullOutputStream, public DebugMessageHandler
58 {
59 public:
60   virtual TextOutputStream& getOutputStream()
61   {
62     return *this;
63   }
64   virtual bool handleMessage()
65   {
66     return false;
67   }
68 };
69
70 class DefaultDebugMessageHandler : public DebugMessageHandler
71 {
72 public:
73   virtual TextOutputStream& getOutputStream()
74   {
75     return globalErrorStream();
76   }
77   virtual bool handleMessage()
78   {
79 #if defined(_DEBUG)
80     return false; // send debug-break
81 #else
82     return true;
83 #endif
84   }
85 };
86
87 class DebugMessageHandlerRef : public DefaultDebugMessageHandler
88 {
89   DebugMessageHandler* m_handler;
90 public:
91   DebugMessageHandlerRef()
92     : m_handler(this)
93   {
94   }
95   void setHandler(DebugMessageHandler& handler)
96   {
97     m_handler = &handler;
98   }
99   DebugMessageHandler& getHandler()
100   {
101     return *m_handler;
102   }
103 };
104
105 typedef Static<DebugMessageHandlerRef> GlobalDebugMessageHandler;
106
107 inline DebugMessageHandler& globalDebugMessageHandler()
108 {
109   return GlobalDebugMessageHandler::instance().getHandler();
110 }
111
112 #if defined(DEBUG_ASSERTS)
113
114 /// \brief Sends a \p message to the current debug-message-handler text-output-stream if \p condition evaluates to false.
115 #define ASSERT_MESSAGE(condition, message)\
116 if(!(condition))\
117 {\
118   globalDebugMessageHandler().getOutputStream() << FILE_LINE "\nassertion failure: " << message << "\n";\
119   if(!globalDebugMessageHandler().handleMessage()) { DEBUGGER_BREAKPOINT(); }\
120 } else\
121
122 /// \brief Sends a \p message to the current debug-message-handler text-output-stream.
123 #define ERROR_MESSAGE(message)\
124 globalDebugMessageHandler().getOutputStream() << FILE_LINE "\nruntime error: " << message << "\n";\
125 if(!globalDebugMessageHandler().handleMessage()) { DEBUGGER_BREAKPOINT(); } else\
126
127 #define ASSERT_NOTNULL(ptr) ASSERT_MESSAGE(ptr != 0, "pointer \"" #ptr "\" is null")
128
129 #else
130
131 #define ASSERT_MESSAGE(condition, message)
132 #define ERROR_MESSAGE(message)
133 #define ASSERT_NOTNULL(ptr)
134
135 #endif
136
137 #endif