1 /****************************************************************************
2 * Copyright (C) 2014-2015 Intel Corporation. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 ****************************************************************************/
23
24 #include "common/os.h"
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <assert.h>
28 #include <algorithm>
29 #include <mutex>
30
31 #if SWR_ENABLE_ASSERTS || SWR_ENABLE_REL_ASSERTS
32
33 #if defined(_MSC_VER)
34 #pragma comment(lib, "user32.lib")
35 #endif // _WIN32
36
37 namespace ConsoleUtils
38 {
39 enum class TextColor
40 {
41 BLACK = 0,
42 #if defined(_WIN32)
43 RED = 4,
44 GREEN = 2,
45 BLUE = 1,
46 #else
47 RED = 1,
48 GREEN = 2,
49 BLUE = 4,
50 #endif // _WIN32
51 PURPLE = static_cast<uint32_t>(RED) | static_cast<uint32_t>(BLUE),
52 CYAN = static_cast<uint32_t>(GREEN) | static_cast<uint32_t>(BLUE),
53 YELLOW = static_cast<uint32_t>(RED) | static_cast<uint32_t>(GREEN),
54 WHITE =
55 static_cast<uint32_t>(RED) | static_cast<uint32_t>(GREEN) | static_cast<uint32_t>(BLUE),
56 };
57
58 enum class TextStyle
59 {
60 NORMAL = 0,
61 INTENSITY = 1,
62 };
63
SetTextColor(FILE * stream,TextColor color=TextColor::WHITE,TextStyle style=TextStyle::NORMAL)64 void SetTextColor(FILE* stream,
65 TextColor color = TextColor::WHITE,
66 TextStyle style = TextStyle::NORMAL)
67 {
68 #if defined(_WIN32)
69
70 HANDLE hConsoleHandle = nullptr;
71 if (stream == stderr)
72 {
73 hConsoleHandle = GetStdHandle(STD_ERROR_HANDLE);
74 }
75 else if (stream == stdout)
76 {
77 hConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
78 }
79 else
80 {
81 // Not a console stream, do nothing
82 return;
83 }
84
85 WORD textAttributes = static_cast<WORD>(color);
86 if (style == TextStyle::INTENSITY)
87 {
88 textAttributes |= FOREGROUND_INTENSITY;
89 }
90 SetConsoleTextAttribute(hConsoleHandle, textAttributes);
91
92 #else // !_WIN32
93
94 // Print ANSI codes
95 uint32_t cc =
96 30 + ((style == TextStyle::INTENSITY) ? 60 : 0) + static_cast<uint32_t>(color);
97 fprintf(stream, "\033[0m\033[%d;%dm", static_cast<uint32_t>(style), cc);
98
99 #endif
100 }
101
ResetTextColor(FILE * stream)102 void ResetTextColor(FILE* stream)
103 {
104 #if defined(_WIN32)
105
106 SetTextColor(stream);
107
108 #else // !_WIN32
109
110 // Print ANSI codes
111 fprintf(stream, "\033[0m");
112
113 #endif
114 }
115
116 static std::mutex g_stderrMutex;
117 } // namespace ConsoleUtils
118
SwrAssert(bool chkDebugger,bool & enabled,const char * pExpression,const char * pFileName,uint32_t lineNum,const char * pFunction,const char * pFmtString,...)119 bool SwrAssert(bool chkDebugger,
120 bool& enabled,
121 const char* pExpression,
122 const char* pFileName,
123 uint32_t lineNum,
124 const char* pFunction,
125 const char* pFmtString,
126 ...)
127 {
128 using namespace ConsoleUtils;
129 std::lock_guard<std::mutex> l(g_stderrMutex);
130
131 SetTextColor(stderr, TextColor::CYAN, TextStyle::NORMAL);
132
133 fprintf(stderr, "%s(%d): ", pFileName, lineNum);
134
135 SetTextColor(stderr, TextColor::RED, TextStyle::INTENSITY);
136
137 fprintf(stderr, "ASSERT: %s\n", pExpression);
138
139 SetTextColor(stderr, TextColor::CYAN, TextStyle::INTENSITY);
140 fprintf(stderr, "\t%s\n", pFunction);
141
142 if (pFmtString)
143 {
144 SetTextColor(stderr, TextColor::YELLOW, TextStyle::INTENSITY);
145 fprintf(stderr, "\t");
146 va_list args;
147 va_start(args, pFmtString);
148 vfprintf(stderr, pFmtString, args);
149 va_end(args);
150 fprintf(stderr, "\n");
151 }
152 ResetTextColor(stderr);
153 fflush(stderr);
154
155 #if defined(_WIN32)
156 static const int MAX_MESSAGE_LEN = 2048;
157 char msgBuf[MAX_MESSAGE_LEN];
158
159 sprintf_s(msgBuf, "%s(%d): ASSERT: %s\n", pFileName, lineNum, pExpression);
160 msgBuf[MAX_MESSAGE_LEN - 2] = '\n';
161 msgBuf[MAX_MESSAGE_LEN - 1] = 0;
162 OutputDebugStringA(msgBuf);
163
164 sprintf_s(msgBuf, "\t%s\n", pFunction);
165 msgBuf[MAX_MESSAGE_LEN - 2] = '\n';
166 msgBuf[MAX_MESSAGE_LEN - 1] = 0;
167 OutputDebugStringA(msgBuf);
168
169 int offset = 0;
170
171 if (pFmtString)
172 {
173 va_list args;
174 va_start(args, pFmtString);
175 offset = _vsnprintf_s(msgBuf, sizeof(msgBuf), sizeof(msgBuf), pFmtString, args);
176 va_end(args);
177
178 if (offset < 0)
179 {
180 return true;
181 }
182
183 OutputDebugStringA("\t");
184 OutputDebugStringA(msgBuf);
185 OutputDebugStringA("\n");
186 }
187
188 if (enabled && KNOB_ENABLE_ASSERT_DIALOGS)
189 {
190 int retval = sprintf_s(&msgBuf[offset],
191 MAX_MESSAGE_LEN - offset,
192 "\n\n"
193 "File: %s\n"
194 "Line: %d\n"
195 "\n"
196 "Expression: %s\n\n"
197 "Cancel: Disable this assert for the remainder of the process\n"
198 "Try Again: Break into the debugger\n"
199 "Continue: Continue execution (but leave assert enabled)",
200 pFileName,
201 lineNum,
202 pExpression);
203
204 if (retval < 0)
205 {
206 return true;
207 }
208
209 offset += retval;
210
211 if (!IsDebuggerPresent())
212 {
213 sprintf_s(&msgBuf[offset],
214 MAX_MESSAGE_LEN - offset,
215 "\n\n*** NO DEBUGGER DETECTED ***\n\nPressing \"Try Again\" will cause a "
216 "program crash!");
217 }
218
219 retval = MessageBoxA(nullptr,
220 msgBuf,
221 "Assert Failed",
222 MB_CANCELTRYCONTINUE | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
223
224 switch (retval)
225 {
226 case IDCANCEL:
227 enabled = false;
228 return false;
229
230 case IDTRYAGAIN:
231 return true;
232
233 case IDCONTINUE:
234 return false;
235 }
236 }
237 else
238 {
239 return (IsDebuggerPresent() || !chkDebugger) && enabled;
240 }
241 #endif // _WIN32
242
243 return enabled;
244 }
245
SwrTrace(const char * pFileName,uint32_t lineNum,const char * pFunction,const char * pFmtString,...)246 void SwrTrace(
247 const char* pFileName, uint32_t lineNum, const char* pFunction, const char* pFmtString, ...)
248 {
249 using namespace ConsoleUtils;
250 std::lock_guard<std::mutex> l(g_stderrMutex);
251
252 SetTextColor(stderr, TextColor::CYAN, TextStyle::NORMAL);
253
254 fprintf(stderr, "%s(%d): TRACE in %s:\n", pFileName, lineNum, pFunction);
255
256 if (pFmtString)
257 {
258 SetTextColor(stderr, TextColor::PURPLE, TextStyle::INTENSITY);
259 fprintf(stderr, "\t");
260 va_list args;
261 va_start(args, pFmtString);
262 vfprintf(stderr, pFmtString, args);
263 va_end(args);
264 fprintf(stderr, "\n");
265 }
266 ResetTextColor(stderr);
267 fflush(stderr);
268
269 #if defined(_WIN32)
270 static const int MAX_MESSAGE_LEN = 2048;
271 char msgBuf[MAX_MESSAGE_LEN];
272
273 sprintf_s(msgBuf, "%s(%d): TRACE in %s\n", pFileName, lineNum, pFunction);
274 msgBuf[MAX_MESSAGE_LEN - 2] = '\n';
275 msgBuf[MAX_MESSAGE_LEN - 1] = 0;
276 OutputDebugStringA(msgBuf);
277
278 int offset = 0;
279
280 if (pFmtString)
281 {
282 va_list args;
283 va_start(args, pFmtString);
284 offset = _vsnprintf_s(msgBuf, sizeof(msgBuf), sizeof(msgBuf), pFmtString, args);
285 va_end(args);
286
287 if (offset < 0)
288 {
289 return;
290 }
291
292 OutputDebugStringA("\t");
293 OutputDebugStringA(msgBuf);
294 OutputDebugStringA("\n");
295 }
296 #endif // _WIN32
297 }
298
299 #endif // SWR_ENABLE_ASSERTS
300