Logging nice fatal errors when dying, w/ a msgbox when not in a console.
This commit is contained in:
parent
4741e3581a
commit
7641a5bfed
|
@ -12,11 +12,11 @@
|
||||||
#include <xenia/common.h>
|
#include <xenia/common.h>
|
||||||
|
|
||||||
|
|
||||||
void xe_log_line(const char* file_path, const uint32_t line_number,
|
void xe_format_log_line(
|
||||||
const char* function_name, const char level_char,
|
char* buffer, size_t buffer_count,
|
||||||
const char* fmt, ...) {
|
const char* file_path, const uint32_t line_number,
|
||||||
const int kLogMax = 2048;
|
const char* function_name, const char level_char,
|
||||||
|
const char* fmt, va_list args) {
|
||||||
// Strip out just the filename from the path.
|
// Strip out just the filename from the path.
|
||||||
const char* filename = xestrrchra(file_path, XE_PATH_SEPARATOR);
|
const char* filename = xestrrchra(file_path, XE_PATH_SEPARATOR);
|
||||||
if (filename) {
|
if (filename) {
|
||||||
|
@ -27,32 +27,68 @@ void xe_log_line(const char* file_path, const uint32_t line_number,
|
||||||
filename = file_path;
|
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.
|
// 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_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
char buffer[kLogMax];
|
xe_format_log_line(buffer, XECOUNT(buffer),
|
||||||
int buffer_length = xevsnprintfa(buffer, XECOUNT(buffer), fmt, args);
|
file_path, line_number, function_name, level_char,
|
||||||
|
fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
if (buffer_length < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format string - add a trailing newline if required.
|
fprintf(stderr, buffer);
|
||||||
const char* outfmt;
|
fflush(stderr);
|
||||||
if ((buffer_length >= 1) && buffer[buffer_length - 1] == '\n') {
|
|
||||||
outfmt = "XE[%c] %s:%d: %s";
|
|
||||||
} else {
|
|
||||||
outfmt = "XE[%c] %s:%d: %s\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0// defined(OutputDebugString)
|
#if 0// defined(OutputDebugString)
|
||||||
char full_output[kLogMax];
|
OutputDebugStringA(buffer);
|
||||||
if (xesnprintfa(full_output, XECOUNT(buffer), outfmt, level_char,
|
|
||||||
filename, line_number, buffer) >= 0) {
|
|
||||||
OutputDebugStringA(full_output);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
XEIGNORE(fprintf(stdout, outfmt, level_char, filename, line_number, buffer));
|
XEIGNORE(fprintf(stdout, buffer));
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
#endif // OutputDebugString
|
#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);
|
||||||
|
}
|
||||||
|
|
|
@ -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* function_name, const char level_char,
|
||||||
const char* fmt, ...) XE_LOG_LINE_ATTRIBUTE;
|
const char* fmt, ...) XE_LOG_LINE_ATTRIBUTE;
|
||||||
#undef 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
|
#if XE_OPTION_ENABLE_LOGGING
|
||||||
#define XELOGCORE(level, fmt, ...) xe_log_line( \
|
#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
|
#define XELOGCORE(level, fmt, ...) XE_EMPTY_MACRO
|
||||||
#endif // ENABLE_LOGGING
|
#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
|
#if XE_OPTION_LOG_ERROR
|
||||||
#define XELOGE(fmt, ...) XELOGCORE('!', fmt, ##__VA_ARGS__)
|
#define XELOGE(fmt, ...) XELOGCORE('!', fmt, ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace {
|
||||||
|
|
||||||
typedef int (*user_main_t)(int argc, xechar_t** argv);
|
typedef int (*user_main_t)(int argc, xechar_t** argv);
|
||||||
|
|
||||||
|
bool _has_console = true;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,14 +60,20 @@ int xe_main_thunk(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool xe_has_console() {
|
||||||
|
return _has_console;
|
||||||
|
}
|
||||||
|
|
||||||
void xe_attach_console() {
|
void xe_attach_console() {
|
||||||
bool has_console = AttachConsole(ATTACH_PARENT_PROCESS) == TRUE;
|
bool has_console = AttachConsole(ATTACH_PARENT_PROCESS) == TRUE;
|
||||||
if (!has_console) {
|
if (!has_console) {
|
||||||
// We weren't launched from a console, so just return.
|
// We weren't launched from a console, so just return.
|
||||||
// We could alloc our own console, but meh:
|
// We could alloc our own console, but meh:
|
||||||
// has_console = AllocConsole() == TRUE;
|
// has_console = AllocConsole() == TRUE;
|
||||||
|
_has_console = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_has_console = true;
|
||||||
|
|
||||||
auto std_handle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
|
auto std_handle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
auto con_handle = _open_osfhandle(std_handle, _O_TEXT);
|
auto con_handle = _open_osfhandle(std_handle, _O_TEXT);
|
||||||
|
@ -100,6 +108,10 @@ int xe_main_window_thunk(
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
bool xe_has_console() {
|
||||||
|
return _has_console;
|
||||||
|
}
|
||||||
|
|
||||||
int xe_main_thunk(
|
int xe_main_thunk(
|
||||||
int argc, char** argv,
|
int argc, char** argv,
|
||||||
void* user_main, const char* usage) {
|
void* user_main, const char* usage) {
|
||||||
|
|
|
@ -134,6 +134,7 @@ XE_CPU: 32BIT | 64BIT | BIGENDIAN | LITTLEENDIAN
|
||||||
#define XE_ALIGNMENT 16
|
#define XE_ALIGNMENT 16
|
||||||
#endif // 32BIT
|
#endif // 32BIT
|
||||||
|
|
||||||
|
bool xe_has_console();
|
||||||
#if XE_LIKE_WIN32 && defined(UNICODE) && UNICODE
|
#if XE_LIKE_WIN32 && defined(UNICODE) && UNICODE
|
||||||
int xe_main_thunk(
|
int xe_main_thunk(
|
||||||
int argc, wchar_t* argv[],
|
int argc, wchar_t* argv[],
|
||||||
|
|
|
@ -27,6 +27,7 @@ int xenia_run(int argc, xechar_t** argv) {
|
||||||
// Grab path from the flag or unnamed argument.
|
// Grab path from the flag or unnamed argument.
|
||||||
if (!FLAGS_target.size() && argc < 2) {
|
if (!FLAGS_target.size() && argc < 2) {
|
||||||
google::ShowUsageWithFlags("xenia-run");
|
google::ShowUsageWithFlags("xenia-run");
|
||||||
|
XEFATAL("Pass a file to launch.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
const xechar_t* path = NULL;
|
const xechar_t* path = NULL;
|
||||||
|
@ -55,6 +56,7 @@ int xenia_run(int argc, xechar_t** argv) {
|
||||||
const xechar_t* dot = xestrrchr(abs_path, '.');
|
const xechar_t* dot = xestrrchr(abs_path, '.');
|
||||||
if (!dot) {
|
if (!dot) {
|
||||||
XELOGE("Invalid input path; no extension found");
|
XELOGE("Invalid input path; no extension found");
|
||||||
|
XEFATAL("Pass a valid file path to launch.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +87,9 @@ int xenia_run(int argc, xechar_t** argv) {
|
||||||
result_code = 0;
|
result_code = 0;
|
||||||
XECLEANUP:
|
XECLEANUP:
|
||||||
delete emulator;
|
delete emulator;
|
||||||
|
if (result_code) {
|
||||||
|
XEFATAL("Failed to launch emulator: %d", result_code);
|
||||||
|
}
|
||||||
return result_code;
|
return result_code;
|
||||||
}
|
}
|
||||||
XE_MAIN_WINDOW_THUNK(xenia_run, XETEXT("xenia-run"), "xenia-run some.xex");
|
XE_MAIN_WINDOW_THUNK(xenia_run, XETEXT("xenia-run"), "xenia-run some.xex");
|
||||||
|
|
Loading…
Reference in New Issue