From 7641a5bfed3ebca5f8eb1f9d0fcfa201f09fd5fa Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Thu, 16 Jan 2014 22:16:06 -0800 Subject: [PATCH] Logging nice fatal errors when dying, w/ a msgbox when not in a console. --- src/xenia/logging.cc | 82 ++++++++++++++++++++++++++---------- src/xenia/logging.h | 8 ++++ src/xenia/platform.cc | 12 ++++++ src/xenia/platform.h | 1 + tools/xenia-run/xenia-run.cc | 5 +++ 5 files changed, 85 insertions(+), 23 deletions(-) diff --git a/src/xenia/logging.cc b/src/xenia/logging.cc index 5405e2553..99f3963e6 100644 --- a/src/xenia/logging.cc +++ b/src/xenia/logging.cc @@ -12,11 +12,11 @@ #include -void xe_log_line(const char* file_path, const uint32_t line_number, - const char* function_name, const char level_char, - const char* fmt, ...) { - const int kLogMax = 2048; - +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, 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); +} diff --git a/src/xenia/logging.h b/src/xenia/logging.h index b2430761e..e6496c158 100644 --- a/src/xenia/logging.h +++ b/src/xenia/logging.h @@ -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 diff --git a/src/xenia/platform.cc b/src/xenia/platform.cc index bc1ca6e63..d5d0a14eb 100644 --- a/src/xenia/platform.cc +++ b/src/xenia/platform.cc @@ -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) { diff --git a/src/xenia/platform.h b/src/xenia/platform.h index dfe11c9e7..976216172 100644 --- a/src/xenia/platform.h +++ b/src/xenia/platform.h @@ -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[], diff --git a/tools/xenia-run/xenia-run.cc b/tools/xenia-run/xenia-run.cc index ee6ad6fa8..a2a424918 100644 --- a/tools/xenia-run/xenia-run.cc +++ b/tools/xenia-run/xenia-run.cc @@ -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");