util: use standard name for snprintf()
[mesa.git] / src / util / u_debug.c
1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * Copyright (c) 2008 VMware, Inc.
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29
30 #include "pipe/p_config.h"
31
32 #include "pipe/p_compiler.h"
33 #include "util/u_debug.h"
34 #include "pipe/p_format.h"
35 #include "pipe/p_state.h"
36 #include "util/u_string.h"
37 #include "util/u_math.h"
38 #include <inttypes.h>
39
40 #include <stdio.h>
41 #include <limits.h> /* CHAR_BIT */
42 #include <ctype.h> /* isalnum */
43
44 #ifdef _WIN32
45 #include <windows.h>
46 #include <stdlib.h>
47 #endif
48
49
50 void
51 _debug_vprintf(const char *format, va_list ap)
52 {
53 static char buf[4096] = {'\0'};
54 #if defined(PIPE_OS_WINDOWS) || defined(PIPE_SUBSYSTEM_EMBEDDED)
55 /* We buffer until we find a newline. */
56 size_t len = strlen(buf);
57 int ret = util_vsnprintf(buf + len, sizeof(buf) - len, format, ap);
58 if (ret > (int)(sizeof(buf) - len - 1) || strchr(buf + len, '\n')) {
59 os_log_message(buf);
60 buf[0] = '\0';
61 }
62 #else
63 util_vsnprintf(buf, sizeof(buf), format, ap);
64 os_log_message(buf);
65 #endif
66 }
67
68
69 void
70 _pipe_debug_message(struct pipe_debug_callback *cb,
71 unsigned *id,
72 enum pipe_debug_type type,
73 const char *fmt, ...)
74 {
75 va_list args;
76 va_start(args, fmt);
77 if (cb && cb->debug_message)
78 cb->debug_message(cb->data, id, type, fmt, args);
79 va_end(args);
80 }
81
82
83 void
84 debug_disable_error_message_boxes(void)
85 {
86 #ifdef _WIN32
87 /* When Windows' error message boxes are disabled for this process (as is
88 * typically the case when running tests in an automated fashion) we disable
89 * CRT message boxes too.
90 */
91 UINT uMode = SetErrorMode(0);
92 SetErrorMode(uMode);
93 if (uMode & SEM_FAILCRITICALERRORS) {
94 /* Disable assertion failure message box.
95 * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx
96 */
97 _set_error_mode(_OUT_TO_STDERR);
98 #ifdef _MSC_VER
99 /* Disable abort message box.
100 * http://msdn.microsoft.com/en-us/library/e631wekh.aspx
101 */
102 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
103 #endif
104 }
105 #endif /* _WIN32 */
106 }
107
108
109 #ifdef DEBUG
110 void
111 debug_print_blob(const char *name, const void *blob, unsigned size)
112 {
113 const unsigned *ublob = (const unsigned *)blob;
114 unsigned i;
115
116 debug_printf("%s (%d dwords%s)\n", name, size/4,
117 size%4 ? "... plus a few bytes" : "");
118
119 for (i = 0; i < size/4; i++) {
120 debug_printf("%d:\t%08x\n", i, ublob[i]);
121 }
122 }
123 #endif
124
125
126 static boolean
127 debug_get_option_should_print(void)
128 {
129 static boolean first = TRUE;
130 static boolean value = FALSE;
131
132 if (!first)
133 return value;
134
135 /* Oh hey this will call into this function,
136 * but its cool since we set first to false
137 */
138 first = FALSE;
139 value = debug_get_bool_option("GALLIUM_PRINT_OPTIONS", FALSE);
140 /* XXX should we print this option? Currently it wont */
141 return value;
142 }
143
144
145 const char *
146 debug_get_option(const char *name, const char *dfault)
147 {
148 const char *result;
149
150 result = os_get_option(name);
151 if (!result)
152 result = dfault;
153
154 if (debug_get_option_should_print())
155 debug_printf("%s: %s = %s\n", __FUNCTION__, name,
156 result ? result : "(null)");
157
158 return result;
159 }
160
161
162 boolean
163 debug_get_bool_option(const char *name, boolean dfault)
164 {
165 const char *str = os_get_option(name);
166 boolean result;
167
168 if (str == NULL)
169 result = dfault;
170 else if (!strcmp(str, "n"))
171 result = FALSE;
172 else if (!strcmp(str, "no"))
173 result = FALSE;
174 else if (!strcmp(str, "0"))
175 result = FALSE;
176 else if (!strcmp(str, "f"))
177 result = FALSE;
178 else if (!strcmp(str, "F"))
179 result = FALSE;
180 else if (!strcmp(str, "false"))
181 result = FALSE;
182 else if (!strcmp(str, "FALSE"))
183 result = FALSE;
184 else
185 result = TRUE;
186
187 if (debug_get_option_should_print())
188 debug_printf("%s: %s = %s\n", __FUNCTION__, name,
189 result ? "TRUE" : "FALSE");
190
191 return result;
192 }
193
194
195 long
196 debug_get_num_option(const char *name, long dfault)
197 {
198 long result;
199 const char *str;
200
201 str = os_get_option(name);
202 if (!str) {
203 result = dfault;
204 } else {
205 char *endptr;
206
207 result = strtol(str, &endptr, 0);
208 if (str == endptr) {
209 /* Restore the default value when no digits were found. */
210 result = dfault;
211 }
212 }
213
214 if (debug_get_option_should_print())
215 debug_printf("%s: %s = %li\n", __FUNCTION__, name, result);
216
217 return result;
218 }
219
220
221 static boolean
222 str_has_option(const char *str, const char *name)
223 {
224 /* Empty string. */
225 if (!*str) {
226 return FALSE;
227 }
228
229 /* OPTION=all */
230 if (!strcmp(str, "all")) {
231 return TRUE;
232 }
233
234 /* Find 'name' in 'str' surrounded by non-alphanumeric characters. */
235 {
236 const char *start = str;
237 unsigned name_len = strlen(name);
238
239 /* 'start' is the beginning of the currently-parsed word,
240 * we increment 'str' each iteration.
241 * if we find either the end of string or a non-alphanumeric character,
242 * we compare 'start' up to 'str-1' with 'name'. */
243
244 while (1) {
245 if (!*str || !(isalnum(*str) || *str == '_')) {
246 if (str-start == name_len &&
247 !memcmp(start, name, name_len)) {
248 return TRUE;
249 }
250
251 if (!*str) {
252 return FALSE;
253 }
254
255 start = str+1;
256 }
257
258 str++;
259 }
260 }
261
262 return FALSE;
263 }
264
265
266 uint64_t
267 debug_get_flags_option(const char *name,
268 const struct debug_named_value *flags,
269 uint64_t dfault)
270 {
271 uint64_t result;
272 const char *str;
273 const struct debug_named_value *orig = flags;
274 unsigned namealign = 0;
275
276 str = os_get_option(name);
277 if (!str)
278 result = dfault;
279 else if (!strcmp(str, "help")) {
280 result = dfault;
281 _debug_printf("%s: help for %s:\n", __FUNCTION__, name);
282 for (; flags->name; ++flags)
283 namealign = MAX2(namealign, strlen(flags->name));
284 for (flags = orig; flags->name; ++flags)
285 _debug_printf("| %*s [0x%0*"PRIx64"]%s%s\n", namealign, flags->name,
286 (int)sizeof(uint64_t)*CHAR_BIT/4, flags->value,
287 flags->desc ? " " : "", flags->desc ? flags->desc : "");
288 }
289 else {
290 result = 0;
291 while (flags->name) {
292 if (str_has_option(str, flags->name))
293 result |= flags->value;
294 ++flags;
295 }
296 }
297
298 if (debug_get_option_should_print()) {
299 if (str) {
300 debug_printf("%s: %s = 0x%"PRIx64" (%s)\n",
301 __FUNCTION__, name, result, str);
302 } else {
303 debug_printf("%s: %s = 0x%"PRIx64"\n", __FUNCTION__, name, result);
304 }
305 }
306
307 return result;
308 }
309
310
311 void
312 _debug_assert_fail(const char *expr, const char *file, unsigned line,
313 const char *function)
314 {
315 _debug_printf("%s:%u:%s: Assertion `%s' failed.\n",
316 file, line, function, expr);
317 os_abort();
318 }
319
320
321 const char *
322 debug_dump_enum(const struct debug_named_value *names,
323 unsigned long value)
324 {
325 static char rest[64];
326
327 while (names->name) {
328 if (names->value == value)
329 return names->name;
330 ++names;
331 }
332
333 snprintf(rest, sizeof(rest), "0x%08lx", value);
334 return rest;
335 }
336
337
338 const char *
339 debug_dump_enum_noprefix(const struct debug_named_value *names,
340 const char *prefix,
341 unsigned long value)
342 {
343 static char rest[64];
344
345 while (names->name) {
346 if (names->value == value) {
347 const char *name = names->name;
348 while (*name == *prefix) {
349 name++;
350 prefix++;
351 }
352 return name;
353 }
354 ++names;
355 }
356
357 snprintf(rest, sizeof(rest), "0x%08lx", value);
358 return rest;
359 }
360
361
362 const char *
363 debug_dump_flags(const struct debug_named_value *names, unsigned long value)
364 {
365 static char output[4096];
366 static char rest[256];
367 int first = 1;
368
369 output[0] = '\0';
370
371 while (names->name) {
372 if ((names->value & value) == names->value) {
373 if (!first)
374 strncat(output, "|", sizeof(output) - strlen(output) - 1);
375 else
376 first = 0;
377 strncat(output, names->name, sizeof(output) - strlen(output) - 1);
378 output[sizeof(output) - 1] = '\0';
379 value &= ~names->value;
380 }
381 ++names;
382 }
383
384 if (value) {
385 if (!first)
386 strncat(output, "|", sizeof(output) - strlen(output) - 1);
387 else
388 first = 0;
389
390 snprintf(rest, sizeof(rest), "0x%08lx", value);
391 strncat(output, rest, sizeof(output) - strlen(output) - 1);
392 output[sizeof(output) - 1] = '\0';
393 }
394
395 if (first)
396 return "0";
397
398 return output;
399 }
400
401
402
403 #ifdef DEBUG
404 int fl_indent = 0;
405 const char* fl_function[1024];
406
407 int
408 debug_funclog_enter(const char* f, UNUSED const int line,
409 UNUSED const char* file)
410 {
411 int i;
412
413 for (i = 0; i < fl_indent; i++)
414 debug_printf(" ");
415 debug_printf("%s\n", f);
416
417 assert(fl_indent < 1023);
418 fl_function[fl_indent++] = f;
419
420 return 0;
421 }
422
423 void
424 debug_funclog_exit(const char* f, UNUSED const int line,
425 UNUSED const char* file)
426 {
427 --fl_indent;
428 assert(fl_indent >= 0);
429 assert(fl_function[fl_indent] == f);
430 }
431
432 void
433 debug_funclog_enter_exit(const char* f, UNUSED const int line,
434 UNUSED const char* file)
435 {
436 int i;
437 for (i = 0; i < fl_indent; i++)
438 debug_printf(" ");
439 debug_printf("%s\n", f);
440 }
441 #endif