Logging nice fatal errors when dying, w/ a msgbox when not in a console.

This commit is contained in:
Ben Vanik 2014-01-16 22:16:06 -08:00
parent 4741e3581a
commit 7641a5bfed
5 changed files with 85 additions and 23 deletions

View File

@ -12,11 +12,11 @@
#include <xenia/common.h>
void xe_log_line(const char* file_path, const uint32_t line_number,
void xe_format_log_line(
char* buffer, size_t buffer_count,
const char* file_path, const uint32_t line_number,
const char* function_name, const char level_char,
const char* fmt, ...) {
const int kLogMax = 2048;
const char* fmt, va_list args) {
// Strip out just the filename from the path.
const char* filename = xestrrchra(file_path, XE_PATH_SEPARATOR);
if (filename) {
@ -27,32 +27,68 @@ void xe_log_line(const char* file_path, const uint32_t line_number,
filename = file_path;
}
// Format string - add a trailing newline if required.
const char* outfmt = "XE[%c] %s:%d: ";
char* buffer_ptr = buffer + xesnprintfa(
buffer, buffer_count - 1, outfmt, level_char, filename, line_number);
// Scribble args into the print buffer.
buffer_ptr = buffer_ptr + xevsnprintfa(
buffer_ptr, buffer_count - (buffer_ptr - buffer) - 1, fmt, args);
// Add a trailing newline.
if (buffer_ptr[-1] != '\n') {
buffer_ptr[0] = '\n';
buffer_ptr[1] = 0;
}
}
void xe_log_line(const char* file_path, const uint32_t line_number,
const char* function_name, const char level_char,
const char* fmt, ...) {
char buffer[2048];
va_list args;
va_start(args, fmt);
char buffer[kLogMax];
int buffer_length = xevsnprintfa(buffer, XECOUNT(buffer), fmt, args);
xe_format_log_line(buffer, XECOUNT(buffer),
file_path, line_number, function_name, level_char,
fmt, args);
va_end(args);
if (buffer_length < 0) {
return;
}
// Format string - add a trailing newline if required.
const char* outfmt;
if ((buffer_length >= 1) && buffer[buffer_length - 1] == '\n') {
outfmt = "XE[%c] %s:%d: %s";
} else {
outfmt = "XE[%c] %s:%d: %s\n";
}
fprintf(stderr, buffer);
fflush(stderr);
#if 0// defined(OutputDebugString)
char full_output[kLogMax];
if (xesnprintfa(full_output, XECOUNT(buffer), outfmt, level_char,
filename, line_number, buffer) >= 0) {
OutputDebugStringA(full_output);
}
OutputDebugStringA(buffer);
#else
XEIGNORE(fprintf(stdout, outfmt, level_char, filename, line_number, buffer));
XEIGNORE(fprintf(stdout, buffer));
fflush(stdout);
#endif // OutputDebugString
}
void xe_handle_fatal(
const char* file_path, const uint32_t line_number,
const char* function_name, const char* fmt, ...) {
char buffer[2048];
va_list args;
va_start(args, fmt);
xe_format_log_line(buffer, XECOUNT(buffer),
file_path, line_number, function_name, 'X',
fmt, args);
va_end(args);
#if defined(OutputDebugString)
OutputDebugStringA(buffer);
#endif // OutputDebugString
fprintf(stderr, buffer);
fflush(stderr);
#if XE_LIKE_WIN32
if (!xe_has_console()) {
MessageBoxA(NULL, buffer, "Xenia Error",
MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
}
#endif // WIN32
exit(1);
}

View File

@ -25,6 +25,9 @@ void xe_log_line(const char* file_path, const uint32_t line_number,
const char* function_name, const char level_char,
const char* fmt, ...) XE_LOG_LINE_ATTRIBUTE;
#undef XE_LOG_LINE_ATTRIBUTE
void xe_handle_fatal(
const char* file_path, const uint32_t line_number,
const char* function_name, const char* fmt, ...);
#if XE_OPTION_ENABLE_LOGGING
#define XELOGCORE(level, fmt, ...) xe_log_line( \
@ -34,6 +37,11 @@ void xe_log_line(const char* file_path, const uint32_t line_number,
#define XELOGCORE(level, fmt, ...) XE_EMPTY_MACRO
#endif // ENABLE_LOGGING
#define XEFATAL(fmt, ...) do { \
xe_handle_fatal(XE_CURRENT_FILE, XE_CURRENT_LINE, XE_CURRENT_FUNCTION, \
fmt, ##__VA_ARGS__); \
} while (false);
#if XE_OPTION_LOG_ERROR
#define XELOGE(fmt, ...) XELOGCORE('!', fmt, ##__VA_ARGS__)
#else

View File

@ -18,6 +18,8 @@ namespace {
typedef int (*user_main_t)(int argc, xechar_t** argv);
bool _has_console = true;
} // namespace
@ -58,14 +60,20 @@ int xe_main_thunk(
return result;
}
bool xe_has_console() {
return _has_console;
}
void xe_attach_console() {
bool has_console = AttachConsole(ATTACH_PARENT_PROCESS) == TRUE;
if (!has_console) {
// We weren't launched from a console, so just return.
// We could alloc our own console, but meh:
// has_console = AllocConsole() == TRUE;
_has_console = false;
return;
}
_has_console = true;
auto std_handle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
auto con_handle = _open_osfhandle(std_handle, _O_TEXT);
@ -100,6 +108,10 @@ int xe_main_window_thunk(
#else
bool xe_has_console() {
return _has_console;
}
int xe_main_thunk(
int argc, char** argv,
void* user_main, const char* usage) {

View File

@ -134,6 +134,7 @@ XE_CPU: 32BIT | 64BIT | BIGENDIAN | LITTLEENDIAN
#define XE_ALIGNMENT 16
#endif // 32BIT
bool xe_has_console();
#if XE_LIKE_WIN32 && defined(UNICODE) && UNICODE
int xe_main_thunk(
int argc, wchar_t* argv[],

View File

@ -27,6 +27,7 @@ int xenia_run(int argc, xechar_t** argv) {
// Grab path from the flag or unnamed argument.
if (!FLAGS_target.size() && argc < 2) {
google::ShowUsageWithFlags("xenia-run");
XEFATAL("Pass a file to launch.");
return 1;
}
const xechar_t* path = NULL;
@ -55,6 +56,7 @@ int xenia_run(int argc, xechar_t** argv) {
const xechar_t* dot = xestrrchr(abs_path, '.');
if (!dot) {
XELOGE("Invalid input path; no extension found");
XEFATAL("Pass a valid file path to launch.");
return 1;
}
@ -85,6 +87,9 @@ int xenia_run(int argc, xechar_t** argv) {
result_code = 0;
XECLEANUP:
delete emulator;
if (result_code) {
XEFATAL("Failed to launch emulator: %d", result_code);
}
return result_code;
}
XE_MAIN_WINDOW_THUNK(xenia_run, XETEXT("xenia-run"), "xenia-run some.xex");