1 //------------------------------------------------------------------------
2 // Project     : SDK Base
3 // Version     : 1.0
4 //
5 // Category    : Helpers
6 // Filename    : base/source/fdebug.h
7 // Created by  : Steinberg, 1995
8 // Description : There are 2 levels of debugging messages:
9 //	             DEVELOPMENT               During development
10 //	             RELEASE                   Program is shipping.
11 //
12 //-----------------------------------------------------------------------------
13 // LICENSE
14 // (c) 2019, Steinberg Media Technologies GmbH, All Rights Reserved
15 //-----------------------------------------------------------------------------
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistributions of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //   * Redistributions in binary form must reproduce the above copyright notice,
22 //     this list of conditions and the following disclaimer in the documentation
23 //     and/or other materials provided with the distribution.
24 //   * Neither the name of the Steinberg Media Technologies nor the names of its
25 //     contributors may be used to endorse or promote products derived from this
26 //     software without specific prior written permission.
27 //
28 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
29 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31 // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
32 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
36 // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
37 // OF THE POSSIBILITY OF SUCH DAMAGE.
38 //-----------------------------------------------------------------------------
39 
40 //-----------------------------------------------------------------------------
41 /** @file base/source/fdebug.h
42 	Debugging tools.
43 
44 	There are 2 levels of debugging messages:
45 	- DEVELOPMENT
46 	  - During development
47 	- RELEASE
48 	  - Program is shipping.
49 */
50 //-----------------------------------------------------------------------------
51 #pragma once
52 
53 #include "pluginterfaces/base/ftypes.h"
54 #include <string.h>
55 
56 #if SMTG_OS_MACOS
57 #include <new>
58 #endif
59 
60 //-----------------------------------------------------------------------------
61 // development / release
62 //-----------------------------------------------------------------------------
63 #if !defined (DEVELOPMENT) && !defined (RELEASE)
64 	#ifdef _DEBUG
65 		#define DEVELOPMENT 1
66 	#elif defined (NDEBUG)
67 		#define RELEASE 1
68 	#else
69 		#error DEVELOPMENT, RELEASE, _DEBUG, or NDEBUG  must be defined!
70 	#endif
71 #endif
72 
73 //-----------------------------------------------------------------------------
74 #if SMTG_OS_WINDOWS
75 
76 /** Disable compiler warning:
77  * C4291: "No matching operator delete found; memory will not be freed if initialization throws an
78  * exception. A placement new is used for which there is no placement delete." */
79 #if DEVELOPMENT && defined(_MSC_VER)
80 #pragma warning(disable : 4291)
81 #pragma warning(disable : 4985)
82 #endif
83 
84 #endif // SMTG_OS_WINDOWS
85 
86 #if DEVELOPMENT
87 //-----------------------------------------------------------------------------
88 /** If "f" is not true and a debugger is present, send an error string to the debugger for display
89    and cause a breakpoint exception to occur in the current process. SMTG_ASSERT is removed
90    completely in RELEASE configuration. So do not pass methods calls to this macro that are expected
91    to exist in the RELEASE build (for method calls that need to be present in a RELEASE build, use
92    the VERIFY macros instead)*/
93 #define SMTG_ASSERT(f) \
94 	if (!(f))          \
95 		FDebugBreak ("%s(%d) : Assert failed: %s\n", __FILE__, __LINE__, #f);
96 
97 /** Send "comment" string to the debugger for display. */
98 #define SMTG_WARNING(comment) FDebugPrint ("%s(%d) : %s\n", __FILE__, __LINE__, comment);
99 
100 /** Send the last error string to the debugger for display. */
101 #define SMTG_PRINTSYSERROR FPrintLastError (__FILE__, __LINE__);
102 
103 /** If a debugger is present, send string "s" to the debugger for display and
104     cause a breakpoint exception to occur in the current process. */
105 #define SMTG_DEBUGSTR(s) FDebugBreak (s);
106 
107 /** Use VERIFY for calling methods "f" having a bool result (expecting them to return 'true')
108      The call of "f" is not removed in RELEASE builds, only the result verification. eg: SMTG_VERIFY
109    (isValid ()) */
110 #define SMTG_VERIFY(f) SMTG_ASSERT (f)
111 
112 /** Use VERIFY_IS for calling methods "f" and expect a certain result "r".
113     The call of "f" is not removed in RELEASE builds, only the result verification. eg:
114    SMTG_VERIFY_IS (callMethod (), kResultOK) */
115 #define SMTG_VERIFY_IS(f, r) \
116 	if ((f) != (r))          \
117 		FDebugBreak ("%s(%d) : Assert failed: %s\n", __FILE__, __LINE__, #f);
118 
119 /** Use VERIFY_NOT for calling methods "f" and expect the result to be anything else but "r".
120      The call of "f" is not removed in RELEASE builds, only the result verification. eg:
121    SMTG_VERIFY_NOT (callMethod (), kResultError) */
122 #define SMTG_VERIFY_NOT(f, r) \
123 	if ((f) == (r))           \
124 		FDebugBreak ("%s(%d) : Assert failed: %s\n", __FILE__, __LINE__, #f);
125 
126 /** @name Shortcut macros for sending strings to the debugger for display.
127 	First parameter is always the format string (printf like).
128 */
129 
130 ///@{
131 #define SMTG_DBPRT0(a) FDebugPrint (a);
132 #define SMTG_DBPRT1(a, b) FDebugPrint (a, b);
133 #define SMTG_DBPRT2(a, b, c) FDebugPrint (a, b, c);
134 #define SMTG_DBPRT3(a, b, c, d) FDebugPrint (a, b, c, d);
135 #define SMTG_DBPRT4(a, b, c, d, e) FDebugPrint (a, b, c, d, e);
136 #define SMTG_DBPRT5(a, b, c, d, e, f) FDebugPrint (a, b, c, d, e, f);
137 ///@}
138 
139 /** @name Helper functions for the above defined macros.
140 
141     You shouldn't use them directly (if you do so, don't forget "#if DEVELOPMENT")!
142     It is recommended to use the macros instead.
143 */
144 ///@{
145 void FDebugPrint (const char* format, ...);
146 void FDebugBreak (const char* format, ...);
147 void FPrintLastError (const char* file, int line);
148 ///@}
149 
150 /** @name Provide a custom assertion handler and debug print handler, eg
151         so that we can provide an assert with a custom dialog, or redirect
152         the debug output to a file or stream.
153 */
154 ///@{
155 typedef bool (*AssertionHandler) (const char* message);
156 extern AssertionHandler gAssertionHandler;
157 extern AssertionHandler gPreAssertionHook;
158 typedef void (*DebugPrintLogger) (const char* message);
159 extern DebugPrintLogger gDebugPrintLogger;
160 ///@}
161 
162 /** Definition of memory allocation macros:
163     Use "NEW" to allocate storage for individual objects.
164     Use "NEWVEC" to allocate storage for an array of objects. */
165 #if SMTG_OS_MACOS
166 void* operator new (size_t, int, const char*, int);
167 void* operator new[] (size_t, int, const char*, int);
168 void operator delete (void* p, int, const char* file, int line);
169 void operator delete[] (void* p, int, const char* file, int line);
170 #ifndef NEW
171 #define NEW new (1, __FILE__, __LINE__)
172 #define NEWVEC new (1, __FILE__, __LINE__)
173 #endif
174 
175 #define DEBUG_NEW DEBUG_NEW_LEAKS
176 
177 #elif SMTG_OS_WINDOWS && defined(_MSC_VER)
178 #ifndef NEW
179 void* operator new (size_t, int, const char*, int);
180 #define NEW new (1, __FILE__, __LINE__)
181 #define NEWVEC new (1, __FILE__, __LINE__)
182 #endif
183 
184 #else
185 #ifndef NEW
186 #define NEW new
187 #define NEWVEC new
188 #endif
189 #endif
190 
191 #else
192 /** if DEVELOPMENT is not set, these macros will do nothing. */
193 #define SMTG_ASSERT(f)
194 #define SMTG_WARNING(s)
195 #define SMTG_PRINTSYSERROR
196 #define SMTG_DEBUGSTR(s)
197 #define SMTG_VERIFY(f) f;
198 #define SMTG_VERIFY_IS(f, r) f;
199 #define SMTG_VERIFY_NOT(f, r) f;
200 
201 #define SMTG_DBPRT0(a)
202 #define SMTG_DBPRT1(a, b)
203 #define SMTG_DBPRT2(a, b, c)
204 #define SMTG_DBPRT3(a, b, c, d)
205 #define SMTG_DBPRT4(a, b, c, d, e)
206 #define SMTG_DBPRT5(a, b, c, d, e, f)
207 
208 #ifndef NEW
209 #define NEW new
210 #define NEWVEC new
211 
212 #endif
213 #endif
214 
215 #if SMTG_CPPUNIT_TESTING
216 #define SMTG_IS_TEST true
217 #else
218 #define SMTG_IS_TEST false
219 #endif
220 
221 #if !SMTG_RENAME_ASSERT
222 #if SMTG_OS_WINDOWS
223 #undef ASSERT
224 #endif
225 
226 #define ASSERT				SMTG_ASSERT
227 #define WARNING				SMTG_WARNING
228 #define DEBUGSTR			SMTG_DEBUGSTR
229 #define VERIFY				SMTG_VERIFY
230 #define VERIFY_IS			SMTG_VERIFY_IS
231 #define VERIFY_NOT			SMTG_VERIFY_NOT
232 #define PRINTSYSERROR		SMTG_PRINTSYSERROR
233 
234 #define DBPRT0				SMTG_DBPRT0
235 #define DBPRT1				SMTG_DBPRT1
236 #define DBPRT2				SMTG_DBPRT2
237 #define DBPRT3				SMTG_DBPRT3
238 #define DBPRT4				SMTG_DBPRT4
239 #define DBPRT5				SMTG_DBPRT5
240 #endif
241