diff --git a/src/emu/clifront.c b/src/emu/clifront.c index 8e86d2971a0..8ab3900520e 100644 --- a/src/emu/clifront.c +++ b/src/emu/clifront.c @@ -20,6 +20,7 @@ #include "romload.h" #include "sound/samples.h" +#include #include #ifdef MESS @@ -111,67 +112,89 @@ static const options_entry cli_options[] = int cli_execute(int argc, char **argv, const options_entry *osd_options) { - core_options *options; + core_options *options = NULL; astring *gamename = astring_alloc(); astring *exename = astring_alloc(); const char *gamename_option; const game_driver *driver; - int result; + int result = MAMERR_FATALERROR; - /* initialize the options manager and add the CLI-specific options */ - options = mame_options_init(osd_options); - options_add_entries(options, cli_options); - - /* parse the command line first; if we fail here, we're screwed */ - if (options_parse_command_line(options, argc, argv, OPTION_PRIORITY_CMDLINE)) + try { - result = MAMERR_INVALID_CONFIG; - goto error; + /* initialize the options manager and add the CLI-specific options */ + options = mame_options_init(osd_options); + options_add_entries(options, cli_options); + + /* parse the command line first; if we fail here, we're screwed */ + if (options_parse_command_line(options, argc, argv, OPTION_PRIORITY_CMDLINE)) + { + result = MAMERR_INVALID_CONFIG; + goto error; + } + + /* parse the simple commmands before we go any further */ + core_filename_extract_base(exename, argv[0], TRUE); + result = execute_simple_commands(options, astring_c(exename)); + if (result != -1) + goto error; + + /* find out what game we might be referring to */ + gamename_option = options_get_string(options, OPTION_GAMENAME); + core_filename_extract_base(gamename, gamename_option, TRUE); + driver = driver_get_name(astring_c(gamename)); + + /* execute any commands specified */ + result = execute_commands(options, astring_c(exename), driver); + if (result != -1) + goto error; + + /* if we don't have a valid driver selected, offer some suggestions */ + if (strlen(gamename_option) > 0 && driver == NULL) + { + const game_driver *matches[10]; + int drvnum; + + /* get the top 10 approximate matches */ + driver_list_get_approx_matches(drivers, gamename_option, ARRAY_LENGTH(matches), matches); + + /* print them out */ + fprintf(stderr, "\n\"%s\" approximately matches the following\n" + "supported " GAMESNOUN " (best match first):\n\n", gamename_option); + for (drvnum = 0; drvnum < ARRAY_LENGTH(matches); drvnum++) + if (matches[drvnum] != NULL) + fprintf(stderr, "%-18s%s\n", matches[drvnum]->name, matches[drvnum]->description); + + /* exit with an error */ + result = MAMERR_NO_SUCH_GAME; + goto error; + } + + /* run the game */ + result = mame_execute(options); } - - /* parse the simple commmands before we go any further */ - core_filename_extract_base(exename, argv[0], TRUE); - result = execute_simple_commands(options, astring_c(exename)); - if (result != -1) - goto error; - - /* find out what game we might be referring to */ - gamename_option = options_get_string(options, OPTION_GAMENAME); - core_filename_extract_base(gamename, gamename_option, TRUE); - driver = driver_get_name(astring_c(gamename)); - - /* execute any commands specified */ - result = execute_commands(options, astring_c(exename), driver); - if (result != -1) - goto error; - - /* if we don't have a valid driver selected, offer some suggestions */ - if (strlen(gamename_option) > 0 && driver == NULL) + catch (emu_fatalerror &fatal) { - const game_driver *matches[10]; - int drvnum; - - /* get the top 10 approximate matches */ - driver_list_get_approx_matches(drivers, gamename_option, ARRAY_LENGTH(matches), matches); - - /* print them out */ - fprintf(stderr, "\n\"%s\" approximately matches the following\n" - "supported " GAMESNOUN " (best match first):\n\n", gamename_option); - for (drvnum = 0; drvnum < ARRAY_LENGTH(matches); drvnum++) - if (matches[drvnum] != NULL) - fprintf(stderr, "%-18s%s\n", matches[drvnum]->name, matches[drvnum]->description); - - /* exit with an error */ - result = MAMERR_NO_SUCH_GAME; - goto error; + fprintf(stderr, "%s\n", fatal.string()); + if (fatal.exitcode() != 0) + result = fatal.exitcode(); + } + catch (emu_exception &exception) + { + fprintf(stderr, "Caught unhandled emulator exception\n"); + } + catch (std::bad_alloc &) + { + fprintf(stderr, "Out of memory!\n"); + } + catch (...) + { + fprintf(stderr, "Caught unhandled exception\n"); } - - /* run the game */ - result = mame_execute(options); error: /* free our options and exit */ - options_free(options); + if (options != NULL) + options_free(options); astring_free(gamename); astring_free(exename); return result; diff --git a/src/emu/config.c b/src/emu/config.c index f7842cb6a59..a2290fb1216 100644 --- a/src/emu/config.c +++ b/src/emu/config.c @@ -133,11 +133,11 @@ int config_load_settings(running_machine *machine) astring_free(fname); if (filerr != FILERR_NONE) - fatalerror("Could not load controller file %s.cfg", controller); + throw emu_fatalerror("Could not load controller file %s.cfg", controller); /* load the XML */ if (!config_load_xml(machine, file, CONFIG_TYPE_CONTROLLER)) - fatalerror("Could not load controller file %s.cfg", controller); + throw emu_fatalerror("Could not load controller file %s.cfg", controller); mame_fclose(file); } diff --git a/src/emu/mame.c b/src/emu/mame.c index 394a5a4281e..40152ac661f 100644 --- a/src/emu/mame.c +++ b/src/emu/mame.c @@ -19,7 +19,6 @@ mame_execute() [mame.c] - calls mame_validitychecks() [validity.c] to perform validity checks on all compiled drivers - - calls setjmp to prepare for deep error handling - begins resource tracking (level 1) - calls create_machine [mame.c] to initialize the running_machine structure - calls init_machine() [mame.c] @@ -87,8 +86,8 @@ #include "streams.h" #include "debug/debugcon.h" +#include #include -#include #include @@ -153,10 +152,6 @@ struct _mame_private region_info * regionlist; tagmap * regionmap; - /* error recovery and exiting */ - jmp_buf fatal_error_jmpbuf; - int fatal_error_jmpbuf_valid; - /* random number seed */ UINT32 rand_seed; @@ -298,10 +293,8 @@ int mame_execute(core_options *options) init_resource_tracking(); - /* use setjmp/longjmp for deep error recovery */ - mame->fatal_error_jmpbuf_valid = TRUE; - error = setjmp(mame->fatal_error_jmpbuf); - if (error == 0) + /* use try/catch for deep error recovery */ + try { int settingsloaded; @@ -372,7 +365,23 @@ int mame_execute(core_options *options) nvram_save(machine); config_save_settings(machine); } - mame->fatal_error_jmpbuf_valid = FALSE; + catch (emu_fatalerror &fatal) + { + mame_printf_error("%s\n", fatal.string()); + error = MAMERR_FATALERROR; + if (fatal.exitcode() != 0) + error = fatal.exitcode(); + } + catch (emu_exception &exception) + { + mame_printf_error("Caught unhandled emulator exception\n"); + error = MAMERR_FATALERROR; + } + catch (std::bad_alloc &) + { + mame_printf_error("Out of memory!\n"); + error = MAMERR_FATALERROR; + } /* call all exit callbacks registered */ for (cb = mame->exit_callback_list; cb; cb = cb->next) @@ -1119,56 +1128,6 @@ void mame_printf_log(const char *format, ...) MISCELLANEOUS ***************************************************************************/ -/*------------------------------------------------- - fatalerror - print a message and escape back - to the OSD layer --------------------------------------------------*/ - -DECL_NORETURN static void fatalerror_common(running_machine *machine, int exitcode, const char *buffer) ATTR_NORETURN; - -static void fatalerror_common(running_machine *machine, int exitcode, const char *buffer) -{ - /* output and return */ - mame_printf_error("%s\n", giant_string_buffer); - - /* break into the debugger if attached */ - osd_break_into_debugger(giant_string_buffer); - - /* longjmp back if we can; otherwise, exit */ - if (machine != NULL && machine->mame_data != NULL && machine->mame_data->fatal_error_jmpbuf_valid) - longjmp(machine->mame_data->fatal_error_jmpbuf, exitcode); - else - exit(exitcode); -} - - -void CLIB_DECL fatalerror(const char *text, ...) -{ - running_machine *machine = global_machine; - va_list arg; - - /* dump to the buffer; assume no one writes >2k lines this way */ - va_start(arg, text); - vsnprintf(giant_string_buffer, GIANT_STRING_BUFFER_SIZE, text, arg); - va_end(arg); - - fatalerror_common(machine, MAMERR_FATALERROR, giant_string_buffer); -} - - -void CLIB_DECL fatalerror_exitcode(running_machine *machine, int exitcode, const char *text, ...) -{ - va_list arg; - - /* dump to the buffer; assume no one writes >2k lines this way */ - va_start(arg, text); - vsnprintf(giant_string_buffer, GIANT_STRING_BUFFER_SIZE, text, arg); - va_end(arg); - - fatalerror_common(machine, exitcode, giant_string_buffer); -} - - /*------------------------------------------------- popmessage - pop up a user-visible message -------------------------------------------------*/ diff --git a/src/emu/mamecore.h b/src/emu/mamecore.h index 248b2111082..94dc687f648 100644 --- a/src/emu/mamecore.h +++ b/src/emu/mamecore.h @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "osdcomm.h" #include "bitmap.h" #include "coreutil.h" @@ -318,13 +320,76 @@ inline void operator--(type &value, int) { value = (type)((int)value - 1); } +/*************************************************************************** + EXCEPTION CLASSES +***************************************************************************/ + +// emu_exception is the base class for all emu-related exceptions +class emu_exception : public std::exception +{ +}; + + +// emu_fatalerror is a generic fatal exception that provides an error string +class emu_fatalerror : public emu_exception +{ +public: + emu_fatalerror(const char *format, ...) + : m_exitcode(0) + { + va_list ap; + va_start(ap, format); + sprintf(m_text, format, ap); + va_end(ap); + osd_break_into_debugger(m_text); + } + + emu_fatalerror(const char *format, va_list ap) + : m_exitcode(0) + { + vsprintf(m_text, format, ap); + osd_break_into_debugger(m_text); + } + + emu_fatalerror(int _exitcode, const char *format, va_list ap) + : m_exitcode(_exitcode) + { + vsprintf(m_text, format, ap); + osd_break_into_debugger(m_text); + } + + const char *string() const { return m_text; } + int exitcode() const { return m_exitcode; } + +private: + char m_text[1024]; + int m_exitcode; +}; + + + /*************************************************************************** FUNCTION PROTOTYPES ***************************************************************************/ -/* Used by assert(), so definition here instead of mame.h */ -DECL_NORETURN void CLIB_DECL fatalerror(const char *text, ...) ATTR_PRINTF(1,2) ATTR_NORETURN; -DECL_NORETURN void CLIB_DECL fatalerror_exitcode(running_machine *machine, int exitcode, const char *text, ...) ATTR_PRINTF(3,4) ATTR_NORETURN; +DECL_NORETURN void fatalerror(const char *format, ...) ATTR_PRINTF(1,2) ATTR_NORETURN; +DECL_NORETURN void fatalerror_exitcode(running_machine *machine, int exitcode, const char *format, ...) ATTR_PRINTF(3,4) ATTR_NORETURN; + +inline void fatalerror(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + throw emu_fatalerror(format, ap); + va_end(ap); +} + +inline void fatalerror_exitcode(running_machine *machine, int exitcode, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + throw emu_fatalerror(exitcode, format, ap); + va_end(ap); +} @@ -333,7 +398,7 @@ DECL_NORETURN void CLIB_DECL fatalerror_exitcode(running_machine *machine, int e ***************************************************************************/ /* population count */ -INLINE int popcount(UINT32 val) +inline int popcount(UINT32 val) { int count; @@ -344,7 +409,7 @@ INLINE int popcount(UINT32 val) /* convert a series of 32 bits into a float */ -INLINE float u2f(UINT32 v) +inline float u2f(UINT32 v) { union { float ff; @@ -356,7 +421,7 @@ INLINE float u2f(UINT32 v) /* convert a float into a series of 32 bits */ -INLINE UINT32 f2u(float f) +inline UINT32 f2u(float f) { union { float ff; @@ -368,7 +433,7 @@ INLINE UINT32 f2u(float f) /* convert a series of 64 bits into a double */ -INLINE double u2d(UINT64 v) +inline double u2d(UINT64 v) { union { double dd; @@ -380,7 +445,7 @@ INLINE double u2d(UINT64 v) /* convert a double into a series of 64 bits */ -INLINE UINT64 d2u(double d) +inline UINT64 d2u(double d) { union { double dd;