1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
15 #include "sjme/stdTypes.h"
17 #if defined(SJME_CONFIG_HAS_WINDOWS)
18 #define WIN32_LEAN_AND_MEAN 1
23 #undef WIN32_LEAN_AND_MEAN
26 #include "sjme/debug.h"
27 #include "sjme/alloc.h"
28 #include "sjme/dylib.h"
30 /** Debug buffer size for messages. */
33 sjme_debug_handlerFunctions
* sjme_debug_handlers
= NULL
;
35 void sjme_debug_abort(void)
37 /* Use specific abort handler? */
38 if (sjme_debug_handlers
!= NULL
&& sjme_debug_handlers
->abort
!= NULL
)
39 if (sjme_debug_handlers
->abort())
42 #if defined(SJME_CONFIG_HAS_WINDOWS)
43 /* When running tests without a debugger this will pop up about 1000 */
44 /* dialogs saying the program aborted, so only abort on debugging. */
45 if (!IsDebuggerPresent())
49 /* Otherwise use C abort handler. */
54 * Potentially debug exits.
56 * @param exitCode The exit code.
59 static void sjme_debug_exit(int exitCode
)
61 /* Use specific exit handler? */
62 if (sjme_debug_handlers
!= NULL
&& sjme_debug_handlers
->exit
!= NULL
)
63 if (sjme_debug_handlers
->exit(exitCode
))
66 /* Fallback to normal exit. */
70 sjme_lpcstr
sjme_debug_shortenFile(sjme_lpcstr file
)
74 /* There is nothing to shorten. */
78 /* Try to find nanocoat in there. */
80 for (i
= (n
- 11 >= 0 ? n
- 11 : 0); i
>= 0; i
--)
82 if (0 == memcmp(&file
[i
], "/nanocoat/", 10) ||
83 0 == memcmp(&file
[i
], "\\nanocoat\\", 10))
87 /* Use the full name regardless. */
91 sjme_errorCode
sjme_error_fatalR(SJME_DEBUG_DECL_FILE_LINE_FUNC
,
92 sjme_attrInValue sjme_errorCode error
)
94 #if defined(SJME_CONFIG_DEBUG)
95 sjme_dieR(file
, line
, func
, "FATAL ERROR: %d!", error
);
98 return sjme_error_default(error
);
101 sjme_errorCode
sjme_error_notImplementedR(SJME_DEBUG_DECL_FILE_LINE_FUNC
,
102 sjme_attrInValue sjme_intPointer context
)
104 #if defined(SJME_CONFIG_DEBUG)
105 sjme_todoR(file
, line
, func
, "NOT IMPLEMENTED: %d %p!",
106 (int)context
, (void*)context
);
109 return SJME_ERROR_NOT_IMPLEMENTED
;
112 sjme_errorCode
sjme_error_outOfMemoryR(SJME_DEBUG_DECL_FILE_LINE_FUNC
,
113 sjme_attrInNullable sjme_alloc_pool
* inPool
,
114 sjme_attrInValue sjme_intPointer context
)
116 #if defined(SJME_CONFIG_DEBUG)
117 /* Dump entire pool contents. */
119 sjme_alloc_poolDump(inPool
);
121 /* It could be huge... */
122 sjme_todoR(file
, line
, func
, "OUT OF MEMORY %p: %d %p!",
123 inPool
, (int)context
, (void*)context
);
126 return SJME_ERROR_OUT_OF_MEMORY
;
129 void sjme_genericMessage(sjme_lpcstr file
, int line
,
130 sjme_lpcstr func
, sjme_lpcstr prefix
, sjme_lpcstr format
, va_list args
)
134 char fullBuf
[DEBUG_BUF
];
136 sjme_jboolean handled
;
138 /* Need to copy because this works differently on other arches. */
141 /* Load message buffer. */
143 strncpy(buf
, "No message", DEBUG_BUF
);
146 memset(buf
, 0, sizeof(buf
));
147 vsnprintf(buf
, DEBUG_BUF
- 1, format
, copy
);
150 /* Cleanup the copy. */
153 /* Print output message. */
154 hasPrefix
= (prefix
!= NULL
&& strlen(prefix
) > 0);
155 memset(fullBuf
, 0, sizeof(fullBuf
));
156 if (file
!= NULL
|| line
> 0 || func
!= NULL
)
157 snprintf(fullBuf
, DEBUG_BUF
- 1,
158 "%s%s(%s:%d in %s()): %s",
159 prefix
, (hasPrefix
? " " : ""),
160 sjme_debug_shortenFile(file
), line
, func
, buf
);
162 snprintf(fullBuf
, DEBUG_BUF
- 1,
164 prefix
, (hasPrefix
? " " : ""), buf
);
166 /* First try to print to the frontend callback, if any. */
167 handled
= SJME_JNI_FALSE
;
168 if (sjme_debug_handlers
!= NULL
&& sjme_debug_handlers
->message
!= NULL
)
169 handled
= sjme_debug_handlers
->message(
173 fprintf(stderr
, "%s\n", fullBuf
);
175 /* Make sure it gets written. */
179 void sjme_messageR(sjme_lpcstr file
, int line
,
180 sjme_lpcstr func
, sjme_jboolean isBlank
, sjme_lpcstr message
, ...)
184 va_start(list
, message
);
186 sjme_genericMessage(file
, line
, func
,
187 (isBlank
? "" : "DB"), message
,
193 void sjme_messageV(SJME_DEBUG_DECL_FILE_LINE_FUNC
,
194 sjme_jboolean isBlank
,
195 sjme_attrInNullable sjme_attrFormatArg sjme_lpcstr message
,
198 sjme_genericMessage(file
, line
, func
,
199 (isBlank
? "" : "DB"), message
,
203 sjme_errorCode
sjme_dieR(sjme_lpcstr file
, int line
,
204 sjme_lpcstr func
, sjme_lpcstr message
, ...)
209 va_start(list
, message
);
211 sjme_genericMessage(file
, line
, func
, "FATAL", message
,
219 /* Exit after abort happens, it can be ignored in debugging. */
220 sjme_debug_exit(EXIT_FAILURE
);
222 /* Never reaches, but returns false naturally. */
223 return SJME_ERROR_UNKNOWN
;
226 static void sjme_message_hexDumpChar(sjme_lpstr
* w
, sjme_lpstr end
,
233 static void sjme_message_hexDumpHex(sjme_lpstr
* w
, sjme_lpstr end
,
237 sjme_message_hexDumpChar(w
, end
, '0' + c
);
239 sjme_message_hexDumpChar(w
, end
, 'A' + (c
- 10));
242 void sjme_message_hexDump(
243 sjme_attrInNullable sjme_buffer inData
,
244 sjme_attrInPositive sjme_jint inLen
)
246 #define SJME_HEX_LINE 12
247 sjme_jint at
, sub
, i
, c
;
248 sjme_cchar buf
[DEBUG_BUF
];
251 if (inData
== NULL
|| inLen
<= 0)
254 /* Print all sequences. */
255 for (at
= 0; at
< inLen
; at
+= SJME_HEX_LINE
)
258 memset(buf
, 0, sizeof(buf
));
260 end
= &buf
[DEBUG_BUF
- 1];
262 /* Print hex first. */
263 for (sub
= at
, i
= 0; sub
< inLen
&& i
< SJME_HEX_LINE
; sub
++, i
++)
265 /* Get byte from the input. */
266 c
= ((sjme_jubyte
*)inData
)[sub
];
269 sjme_message_hexDumpHex(&w
, end
, (c
>> 4) & 0xF);
270 sjme_message_hexDumpHex(&w
, end
, c
& 0xF);
273 sjme_message_hexDumpChar(&w
, end
, ' ');
277 sjme_message_hexDumpChar(&w
, end
, '|');
279 /* Then characters. */
280 for (sub
= at
, i
= 0; sub
< inLen
&& i
< SJME_HEX_LINE
; sub
++, i
++)
282 /* Get byte from the input. */
283 c
= ((sjme_jubyte
*)inData
)[sub
];
285 if (c
>= ' ' && c
< 0x7F)
286 sjme_message_hexDumpChar(&w
, end
, c
);
288 sjme_message_hexDumpChar(&w
, end
, '.');
292 sjme_message_hexDumpChar(&w
, end
, '|');
294 /* Send out the buffer. */
295 sjme_messageR(NULL
, -1, NULL
, SJME_JNI_TRUE
,
302 void sjme_todoR(sjme_lpcstr file
, int line
,
303 sjme_lpcstr func
, sjme_lpcstr message
, ...)
307 va_start(list
, message
);
309 sjme_genericMessage(file
, line
, func
, "TD TODO HIT", message
,
317 /* Exit after abort happens, it can be ignored in debugging. */
318 sjme_debug_exit(EXIT_FAILURE
);