diff --git a/driver.c b/driver.c index 5c8d7a1bd8..cc0eaa8e8e 100644 --- a/driver.c +++ b/driver.c @@ -139,7 +139,7 @@ static void find_audio_driver(void) for (size_t i = 0; i < sizeof(audio_drivers) / sizeof(audio_driver_t*); i++) fprintf(stderr, "\t%s\n", audio_drivers[i]->ident); - exit(1); + ssnes_fail(1, "find_audio_driver()"); } static void find_video_driver(void) @@ -157,7 +157,7 @@ static void find_video_driver(void) for (size_t i = 0; i < sizeof(video_drivers) / sizeof(video_driver_t*); i++) fprintf(stderr, "\t%s\n", video_drivers[i]->ident); - exit(1); + ssnes_fail(1, "find_video_driver()"); } static void find_input_driver(void) @@ -175,7 +175,7 @@ static void find_input_driver(void) for (size_t i = 0; i < sizeof(input_drivers) / sizeof(input_driver_t*); i++) fprintf(stderr, "\t%s\n", input_drivers[i]->ident); - exit(1); + ssnes_fail(1, "find_input_driver()"); } void init_drivers(void) @@ -549,7 +549,7 @@ void init_video_input(void) if (driver.video_data == NULL) { SSNES_ERR("Cannot open video driver ... Exiting ...\n"); - exit(1); + ssnes_fail(1, "init_video_input()"); } // Video driver didn't provide an input driver so we use configured one. @@ -562,13 +562,13 @@ void init_video_input(void) if (driver.input_data == NULL) { SSNES_ERR("Cannot init input driver. Exiting ...\n"); - exit(1); + ssnes_fail(1, "init_video_input()"); } } else { SSNES_ERR("Cannot find input driver. Exiting ...\n"); - exit(1); + ssnes_fail(1, "init_video_input()"); } } } diff --git a/dynamic.c b/dynamic.c index ac9b86030f..a6190943c8 100644 --- a/dynamic.c +++ b/dynamic.c @@ -40,7 +40,7 @@ #define SYM(type, x) do { \ p##x = (type)DLSYM(lib_handle, x); \ - if (p##x == NULL) { SSNES_ERR("Failed to load symbol: \"%s\"\n", #x); exit(1); } \ + if (p##x == NULL) { SSNES_ERR("Failed to load symbol: \"%s\"\n", #x); ssnes_fail(1, "init_libsnes_sym()"); } \ } while (0) #define OPT_SYM(type, x) do { \ @@ -114,7 +114,7 @@ static void load_dynamic(void) if (!lib_handle) { SSNES_ERR("Failed to open dynamic library: \"%s\"\n", g_settings.libsnes); - exit(1); + ssnes_fail(1, "load_dynamic()"); } SYM(void (*)(void), snes_init); @@ -202,7 +202,7 @@ void init_libsnes_sym(void) SSNES_ERR("Serious problem! SSNES wants to load libsnes dyamically, but it is already linked!\n"); SSNES_ERR("This could happen if other modules SSNES depends on link against libsnes directly.\n"); SSNES_ERR("Proceeding could cause a crash! Aborting ...\n"); - exit(1); + ssnes_fail(1, "init_libsnes_sym()"); } if (!*g_settings.libsnes) diff --git a/general.h b/general.h index 05e3e70a56..0cd2efa7aa 100644 --- a/general.h +++ b/general.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "driver.h" #include "record/ffemu.h" #include "message.h" @@ -32,6 +33,7 @@ #include "dynamic.h" #include "cheats.h" #include "audio/ext/ssnes_dsp.h" +#include "strl.h" #ifdef __CELLOS_LV2__ #include @@ -354,11 +356,16 @@ struct global #ifdef HAVE_XML cheat_manager_t *cheat; #endif + + bool error_in_init; + char error_string[1024]; + jmp_buf error_sjlj_context; }; void parse_config(void); void config_set_defaults(void); +void ssnes_main_clear_state(void); int ssnes_main_init(int argc, char *argv[]); bool ssnes_main_iterate(void); void ssnes_main_deinit(void); @@ -444,6 +451,16 @@ static inline void ssnes_sleep(unsigned msec) #define ssnes_assert(cond) \ if (!(cond)) { SSNES_ERR("Assertion failed at %s:%d!\n", __FILE__, __LINE__); exit(2); } +static inline void ssnes_fail(int error_code, const char *error) +{ + // We cannot longjmp unless we're in ssnes_main_init(). + // If not, something went very wrong, and we should just exit right away. + ssnes_assert(g_extern.error_in_init); + + strlcpy(g_extern.error_string, error, sizeof(g_extern.error_string)); + longjmp(g_extern.error_sjlj_context, error_code); +} + #endif diff --git a/movie.c b/movie.c index f771142152..6ddb452fb0 100644 --- a/movie.c +++ b/movie.c @@ -179,7 +179,7 @@ static bool init_playback(bsv_movie_t *handle, const char *path) if (psnes_serialize_size() != state_size) { SSNES_ERR("Movie format seems to have a different serializer version. Cannot continue.\n"); - exit(1); + ssnes_fail(1, "init_playback()"); } // Unserialize to start playback. diff --git a/settings.c b/settings.c index c7df27deca..b86cee461e 100644 --- a/settings.c +++ b/settings.c @@ -323,7 +323,7 @@ static void parse_config_file(void) if (!conf) { SSNES_ERR("Couldn't find config at path: \"%s\"\n", g_extern.config_path); - exit(1); + ssnes_fail(1, "parse_config_file()"); } } else diff --git a/ssnes.c b/ssnes.c index 0e126d12f9..1f91d502b6 100644 --- a/ssnes.c +++ b/ssnes.c @@ -529,7 +529,7 @@ static void set_paths(const char *path) if (g_extern.rom_file == NULL) { SSNES_ERR("Could not open file: \"%s\"\n", path); - exit(1); + ssnes_fail(1, "set_paths()"); } if (!g_extern.has_set_save_path) @@ -568,26 +568,26 @@ static void verify_stdin_paths(void) { SSNES_ERR("Need savefile path argument (--save) when reading rom from stdin.\n"); print_help(); - exit(1); + ssnes_fail(1, "verify_stdin_paths()"); } else if (strlen(g_extern.savestate_name) == 0) { SSNES_ERR("Need savestate path argument (--savestate) when reading rom from stdin.\n"); print_help(); - exit(1); + ssnes_fail(1, "verify_stdin_paths()"); } if (path_is_directory(g_extern.savefile_name_srm)) { SSNES_ERR("Cannot specify directory for path argument (--save) when reading from stdin.\n"); print_help(); - exit(1); + ssnes_fail(1, "verify_stdin_paths()"); } else if (path_is_directory(g_extern.savestate_name)) { SSNES_ERR("Cannot specify directory for path argument (--savestate) when reading from stdin.\n"); print_help(); - exit(1); + ssnes_fail(1, "verify_stdin_paths()"); } #ifdef HAVE_CONFIGFILE @@ -595,7 +595,7 @@ static void verify_stdin_paths(void) { SSNES_ERR("Cannot specify directory for config file (--config) when reading from stdin.\n"); print_help(); - exit(1); + ssnes_fail(1, "verify_stdin_paths()"); } #endif } @@ -605,7 +605,7 @@ static void parse_input(int argc, char *argv[]) if (argc < 2) { print_help(); - exit(1); + ssnes_fail(1, "parse_input()"); } int val = 0; @@ -756,7 +756,7 @@ static void parse_input(int argc, char *argv[]) { SSNES_ERR("Connect mouse to port 1 or 2.\n"); print_help(); - exit(1); + ssnes_fail(1, "parse_input()"); } g_extern.has_mouse[port - 1] = true; break; @@ -767,7 +767,7 @@ static void parse_input(int argc, char *argv[]) { SSNES_ERR("Disconnected device from port 1 or 2.\n"); print_help(); - exit(1); + ssnes_fail(1, "parse_input()"); } g_extern.disconnect_device[port - 1] = true; break; @@ -817,7 +817,7 @@ static void parse_input(int argc, char *argv[]) { SSNES_ERR("Invalid argument in --sram-mode!\n"); print_help(); - exit(1); + ssnes_fail(1, "parse_input()"); } break; @@ -881,7 +881,7 @@ static void parse_input(int argc, char *argv[]) { SSNES_ERR("Wrong format for --size.\n"); print_help(); - exit(1); + ssnes_fail(1, "parse_input()"); } ptr++; @@ -890,7 +890,7 @@ static void parse_input(int argc, char *argv[]) { SSNES_ERR("Wrong format for --size.\n"); print_help(); - exit(1); + ssnes_fail(1, "parse_input()"); } break; } @@ -906,11 +906,11 @@ static void parse_input(int argc, char *argv[]) case '?': print_help(); - exit(1); + ssnes_fail(1, "parse_input()"); default: SSNES_ERR("Error parsing arguments.\n"); - exit(1); + ssnes_fail(1, "parse_input()"); } } @@ -1173,7 +1173,7 @@ static void init_movie(void) if (!g_extern.bsv.movie) { SSNES_ERR("Failed to load movie file: \"%s\"!\n", g_extern.bsv.movie_start_path); - exit(1); + ssnes_fail(1, "init_movie()"); } g_extern.bsv.movie_playback = true; @@ -2041,12 +2041,26 @@ static void init_state(void) g_extern.game_type = SSNES_CART_NORMAL; } +void ssnes_main_clear_state(void) +{ + memset(&g_settings, 0, sizeof(g_settings)); + memset(&g_extern, 0, sizeof(g_extern)); + init_state(); +} + int ssnes_main_init(int argc, char *argv[]) { init_state(); - parse_input(argc, argv); + int sjlj_ret; + if ((sjlj_ret = setjmp(g_extern.error_sjlj_context)) > 0) + { + SSNES_ERR("Fatal error received in: \"%s\"\n", g_extern.error_string); + return sjlj_ret; + } + g_extern.error_in_init = true; + if (g_extern.verbose) { fprintf(stderr, "=== Build ======================================="); @@ -2120,6 +2134,7 @@ int ssnes_main_init(int argc, char *argv[]) init_cheats(); #endif + g_extern.error_in_init = false; return 0; error: