diff options
author | npwoods <npwoods@alumni.cmu.edu> | 2017-06-24 22:48:56 -0400 |
---|---|---|
committer | Vas Crabb <cuavas@users.noreply.github.com> | 2017-06-25 12:48:56 +1000 |
commit | b193e05cd7c8456a2648d43854645da84f56ddbd (patch) | |
tree | 406d4dca91e403acdcea26379bcf65e567ca4834 /src/frontend | |
parent | 1b28df0b39225c3017e7bc843c14b58f548162ac (diff) |
Overhaul to how MAME handles options, take two (#2341)
Diffstat (limited to 'src/frontend')
-rw-r--r-- | src/frontend/mame/clifront.cpp | 96 | ||||
-rw-r--r-- | src/frontend/mame/clifront.h | 6 | ||||
-rw-r--r-- | src/frontend/mame/info.cpp | 2 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.cpp | 23 | ||||
-rw-r--r-- | src/frontend/mame/mame.cpp | 45 | ||||
-rw-r--r-- | src/frontend/mame/mameopts.cpp | 685 | ||||
-rw-r--r-- | src/frontend/mame/mameopts.h | 36 | ||||
-rw-r--r-- | src/frontend/mame/pluginopts.cpp | 2 | ||||
-rw-r--r-- | src/frontend/mame/ui/custui.cpp | 38 | ||||
-rw-r--r-- | src/frontend/mame/ui/dirmenu.cpp | 15 | ||||
-rw-r--r-- | src/frontend/mame/ui/info.cpp | 3 | ||||
-rw-r--r-- | src/frontend/mame/ui/miscmenu.cpp | 28 | ||||
-rw-r--r-- | src/frontend/mame/ui/selgame.cpp | 14 | ||||
-rw-r--r-- | src/frontend/mame/ui/selsoft.cpp | 26 | ||||
-rw-r--r-- | src/frontend/mame/ui/slotopt.cpp | 93 | ||||
-rw-r--r-- | src/frontend/mame/ui/slotopt.h | 7 | ||||
-rw-r--r-- | src/frontend/mame/ui/sndmenu.cpp | 10 | ||||
-rw-r--r-- | src/frontend/mame/ui/submenu.cpp | 26 | ||||
-rw-r--r-- | src/frontend/mame/ui/submenu.h | 2 | ||||
-rw-r--r-- | src/frontend/mame/ui/ui.cpp | 33 |
20 files changed, 335 insertions, 855 deletions
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp index 6e5d77c40e0..a36b47da683 100644 --- a/src/frontend/mame/clifront.cpp +++ b/src/frontend/mame/clifront.cpp @@ -190,26 +190,30 @@ cli_frontend::cli_frontend(emu_options &options, osd_interface &osd) cli_frontend::~cli_frontend() { - // nuke any device options since they will leak memory - mame_options::remove_device_options(m_options); } -void cli_frontend::start_execution(mame_machine_manager *manager, std::vector<std::string> &args) +void cli_frontend::start_execution(mame_machine_manager *manager, const std::vector<std::string> &args) { - std::string option_errors; + std::ostringstream option_errors; + + // because softlist evaluation relies on hashpath being populated, we are going to go through + // a special step to force it to be evaluated + mame_options::populate_hashpath_from_args_and_inis(m_options, args); // parse the command line, adding any system-specific options - if (!mame_options::parse_command_line(m_options, args, option_errors)) + try + { + m_options.parse_command_line(args, OPTION_PRIORITY_CMDLINE); + } + catch (options_exception &ex) { // if we failed, check for no command and a system name first; in that case error on the name - if (m_options.command().empty() && mame_options::system(m_options) == nullptr && *(m_options.system_name()) != 0) - throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.system_name()); + if (m_options.command().empty() && mame_options::system(m_options) == nullptr && !m_options.attempted_system_name().empty()) + throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.attempted_system_name().c_str()); // otherwise, error on the options - throw emu_fatalerror(EMU_ERR_INVALID_CONFIG, "%s", strtrimspace(option_errors).c_str()); + throw emu_fatalerror(EMU_ERR_INVALID_CONFIG, "%s", ex.message().c_str()); } - if (!option_errors.empty()) - osd_printf_error("Error in command line:\n%s\n", strtrimspace(option_errors).c_str()); // determine the base name of the EXE std::string exename = core_filename_extract_base(args[0], true); @@ -232,8 +236,11 @@ void cli_frontend::start_execution(mame_machine_manager *manager, std::vector<st manager->start_luaengine(); - if (!option_errors.empty()) - osd_printf_error("Error in command line:\n%s\n", strtrimspace(option_errors).c_str()); + if (option_errors.tellp() > 0) + { + std::string option_errors_string = option_errors.str(); + osd_printf_error("Error in command line:\n%s\n", strtrimspace(option_errors_string).c_str()); + } // if we can't find it, give an appropriate error const game_driver *system = mame_options::system(m_options); @@ -269,16 +276,19 @@ int cli_frontend::execute(std::vector<std::string> &args) // if a game was specified, wasn't a wildcard, and our error indicates this was the // reason for failure, offer some suggestions - if (m_result == EMU_ERR_NO_SUCH_GAME && *(m_options.system_name()) != 0 && !core_iswildstr(m_options.system_name()) && mame_options::system(m_options) == nullptr) + if (m_result == EMU_ERR_NO_SUCH_GAME + && !m_options.attempted_system_name().empty() + && !core_iswildstr(m_options.attempted_system_name().c_str()) + && mame_options::system(m_options) == nullptr) { // get the top 16 approximate matches driver_enumerator drivlist(m_options); int matches[16]; - drivlist.find_approximate_matches(m_options.system_name(), ARRAY_LENGTH(matches), matches); + drivlist.find_approximate_matches(m_options.attempted_system_name().c_str(), ARRAY_LENGTH(matches), matches); // print them out osd_printf_error("\n\"%s\" approximately matches the following\n" - "supported machines (best match first):\n\n", m_options.system_name()); + "supported machines (best match first):\n\n", m_options.attempted_system_name().c_str()); for (auto & matche : matches) if (matche != -1) osd_printf_error("%-18s%s\n", drivlist.driver(matche).name, drivlist.driver(matche).type.fullname()); @@ -1441,8 +1451,7 @@ void cli_frontend::romident(const std::vector<std::string> &args) // create our own copy of options for the purposes of ROM identification // so we are not "polluted" with driver-specific slot/image options emu_options options; - std::string error_string; - options.set_value(OPTION_MEDIAPATH, m_options.media_path(), OPTION_PRIORITY_DEFAULT, error_string); + options.set_value(OPTION_MEDIAPATH, m_options.media_path(), OPTION_PRIORITY_DEFAULT); media_identifier ident(options); @@ -1470,24 +1479,24 @@ const cli_frontend::info_command_struct *cli_frontend::find_command(const std::s { static const info_command_struct s_info_commands[] = { - { CLICOMMAND_LISTXML, 0, -1, false, &cli_frontend::listxml, "[pattern] ..." }, - { CLICOMMAND_LISTFULL, 0, 1, false, &cli_frontend::listfull, "[system name]" }, - { CLICOMMAND_LISTSOURCE, 0, 1, false, &cli_frontend::listsource, "[system name]" }, - { CLICOMMAND_LISTCLONES, 0, 1, false, &cli_frontend::listclones, "[system name]" }, - { CLICOMMAND_LISTBROTHERS, 0, 1, false, &cli_frontend::listbrothers, "[system name]" }, - { CLICOMMAND_LISTCRC, 0, 1, false, &cli_frontend::listcrc, "[system name]" }, - { CLICOMMAND_LISTDEVICES, 0, 1, true, &cli_frontend::listdevices, "[system name]" }, - { CLICOMMAND_LISTSLOTS, 0, 1, true, &cli_frontend::listslots, "[system name]" }, - { CLICOMMAND_LISTROMS, 0, -1, false, &cli_frontend::listroms, "[pattern] ..." }, - { CLICOMMAND_LISTSAMPLES, 0, 1, false, &cli_frontend::listsamples, "[system name]" }, - { CLICOMMAND_VERIFYROMS, 0, -1, false, &cli_frontend::verifyroms, "[pattern] ..." }, - { CLICOMMAND_VERIFYSAMPLES, 0, 1, false, &cli_frontend::verifysamples, "[system name|*]" }, - { CLICOMMAND_LISTMEDIA, 0, 1, true, &cli_frontend::listmedia, "[system name]" }, - { CLICOMMAND_LISTSOFTWARE, 0, 1, false, &cli_frontend::listsoftware, "[system name]" }, - { CLICOMMAND_VERIFYSOFTWARE, 0, 1, false, &cli_frontend::verifysoftware, "[system name|*]" }, - { CLICOMMAND_ROMIDENT, 1, 1, false, &cli_frontend::romident, "(file or directory path)" }, - { CLICOMMAND_GETSOFTLIST, 0, 1, false, &cli_frontend::getsoftlist, "[system name|*]" }, - { CLICOMMAND_VERIFYSOFTLIST, 0, 1, false, &cli_frontend::verifysoftlist, "[system name|*]" } + { CLICOMMAND_LISTXML, 0, -1, &cli_frontend::listxml, "[pattern] ..." }, + { CLICOMMAND_LISTFULL, 0, 1, &cli_frontend::listfull, "[system name]" }, + { CLICOMMAND_LISTSOURCE, 0, 1, &cli_frontend::listsource, "[system name]" }, + { CLICOMMAND_LISTCLONES, 0, 1, &cli_frontend::listclones, "[system name]" }, + { CLICOMMAND_LISTBROTHERS, 0, 1, &cli_frontend::listbrothers, "[system name]" }, + { CLICOMMAND_LISTCRC, 0, 1, &cli_frontend::listcrc, "[system name]" }, + { CLICOMMAND_LISTDEVICES, 0, 1, &cli_frontend::listdevices, "[system name]" }, + { CLICOMMAND_LISTSLOTS, 0, 1, &cli_frontend::listslots, "[system name]" }, + { CLICOMMAND_LISTROMS, 0, -1, &cli_frontend::listroms, "[pattern] ..." }, + { CLICOMMAND_LISTSAMPLES, 0, 1, &cli_frontend::listsamples, "[system name]" }, + { CLICOMMAND_VERIFYROMS, 0, -1, &cli_frontend::verifyroms, "[pattern] ..." }, + { CLICOMMAND_VERIFYSAMPLES, 0, 1, &cli_frontend::verifysamples, "[system name|*]" }, + { CLICOMMAND_LISTMEDIA, 0, 1, &cli_frontend::listmedia, "[system name]" }, + { CLICOMMAND_LISTSOFTWARE, 0, 1, &cli_frontend::listsoftware, "[system name]" }, + { CLICOMMAND_VERIFYSOFTWARE, 0, 1, &cli_frontend::verifysoftware, "[system name|*]" }, + { CLICOMMAND_ROMIDENT, 1, 1, &cli_frontend::romident, "(file or directory path)" }, + { CLICOMMAND_GETSOFTLIST, 0, 1, &cli_frontend::getsoftlist, "[system name|*]" }, + { CLICOMMAND_VERIFYSOFTLIST, 0, 1, &cli_frontend::verifysoftlist, "[system name|*]" } }; for (const auto &info_command : s_info_commands) @@ -1500,17 +1509,6 @@ const cli_frontend::info_command_struct *cli_frontend::find_command(const std::s //------------------------------------------------- -// parse_slot_options_for_auxverb -//------------------------------------------------- - -bool cli_frontend::parse_slot_options_for_auxverb(const std::string &auxverb) -{ - const info_command_struct *command = find_command(auxverb); - return command && command->specify_system; -} - - -//------------------------------------------------- // execute_commands - execute various frontend // commands //------------------------------------------------- @@ -1545,10 +1543,10 @@ void cli_frontend::execute_commands(const char *exename) } // other commands need the INIs parsed - std::string option_errors; + std::ostringstream option_errors; mame_options::parse_standard_inis(m_options,option_errors); - if (!option_errors.empty()) - osd_printf_error("%s\n", option_errors.c_str()); + if (option_errors.tellp() > 0) + osd_printf_error("%s\n", option_errors.str().c_str()); // createconfig? if (m_options.command() == CLICOMMAND_CREATECONFIG) diff --git a/src/frontend/mame/clifront.h b/src/frontend/mame/clifront.h index 7e19fdd2e84..71e161dba07 100644 --- a/src/frontend/mame/clifront.h +++ b/src/frontend/mame/clifront.h @@ -34,16 +34,12 @@ public: // execute based on the incoming argc/argv int execute(std::vector<std::string> &args); - // should we parse slot options for the auxillary verb in question? - static bool parse_slot_options_for_auxverb(const std::string &auxverb); - private: struct info_command_struct { const char *option; int min_args; int max_args; - bool specify_system; void (cli_frontend::*function)(const std::vector<std::string> &args); const char *usage; }; @@ -72,7 +68,7 @@ private: void execute_commands(const char *exename); void display_help(const char *exename); void output_single_softlist(FILE *out, software_list_device &swlist); - void start_execution(mame_machine_manager *manager, std::vector<std::string> &args); + void start_execution(mame_machine_manager *manager, const std::vector<std::string> &args); static const info_command_struct *find_command(const std::string &s); // internal state diff --git a/src/frontend/mame/info.cpp b/src/frontend/mame/info.cpp index 4aebe5b29c6..fa836b27abe 100644 --- a/src/frontend/mame/info.cpp +++ b/src/frontend/mame/info.cpp @@ -191,9 +191,7 @@ const char info_xml_creator::s_dtd_string[] = info_xml_creator::info_xml_creator(emu_options const &options) : m_output(nullptr) - , m_lookup_options(options) { - mame_options::remove_device_options(m_lookup_options); } diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 0dde20fe611..6b62cfe726b 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -721,7 +721,7 @@ void lua_engine::initialize() emu["app_version"] = &emulator_info::get_bare_build_version; emu["gamename"] = [this](){ return machine().system().type.fullname(); }; emu["romname"] = [this](){ return machine().basename(); }; - emu["softname"] = [this](){ return machine().options().software_name(); }; + emu["softname"] = [this]() { return machine().options().software_name(); }; emu["keypost"] = [this](const char *keys){ machine().ioport().natkeyboard().post_utf8(keys); }; emu["time"] = [this](){ return machine().time().as_double(); }; emu["start"] = [this](const char *driver) { @@ -1016,9 +1016,11 @@ void lua_engine::initialize() "entries", sol::property([this](core_options &options) { sol::table table = sol().create_table(); int unadorned_index = 0; - for(core_options::entry &curentry : options) + for (auto &curentry : options.entries()) { - const char *name = curentry.name(); + const char *name = curentry->names().size() > 0 + ? curentry->name().c_str() + : nullptr; bool is_unadorned = false; // check if it's unadorned if (name && strlen(name) && !strcmp(name, options.unadorned(unadorned_index))) @@ -1026,8 +1028,8 @@ void lua_engine::initialize() unadorned_index++; is_unadorned = true; } - if (!curentry.is_header() && !curentry.is_command() && !curentry.is_internal() && !is_unadorned) - table[name] = &curentry; + if (curentry->type() != core_options::option_type::HEADER && curentry->type() != core_options::option_type::COMMAND && !is_unadorned) + table[name] = &*curentry; } return table; })); @@ -1068,18 +1070,19 @@ void lua_engine::initialize() e.set_value(val, OPTION_PRIORITY_CMDLINE); }, [this](core_options::entry &e) -> sol::object { - if(!e.type()) + if (e.type() == core_options::option_type::INVALID) return sol::make_object(sol(), sol::nil); switch(e.type()) { - case OPTION_BOOLEAN: + case core_options::option_type::BOOLEAN: return sol::make_object(sol(), atoi(e.value()) != 0); - case OPTION_INTEGER: + case core_options::option_type::INTEGER: return sol::make_object(sol(), atoi(e.value())); - case OPTION_FLOAT: + case core_options::option_type::FLOAT: return sol::make_object(sol(), atof(e.value())); + default: + return sol::make_object(sol(), e.value()); } - return sol::make_object(sol(), e.value()); }), "description", &core_options::entry::description, "default_value", &core_options::entry::default_value, diff --git a/src/frontend/mame/mame.cpp b/src/frontend/mame/mame.cpp index cdab8e4d9c9..bc9d9b334b7 100644 --- a/src/frontend/mame/mame.cpp +++ b/src/frontend/mame/mame.cpp @@ -124,36 +124,38 @@ void mame_machine_manager::start_luaengine() std::vector<std::string> exclude = split(options().no_plugin(),','); { // parse the file - std::string error; // attempt to open the output file emu_file file(options().ini_path(), OPEN_FLAG_READ); if (file.open("plugin.ini") == osd_file::error::NONE) { - bool result = m_plugins->parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_MAME_INI < OPTION_PRIORITY_DRIVER_INI, error); - if (!result) + try + { + m_plugins->parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_MAME_INI < OPTION_PRIORITY_DRIVER_INI, false); + } + catch (options_exception &) + { osd_printf_error("**Error loading plugin.ini**\n"); + } } } - for (auto &curentry : *m_plugins) + for (auto &curentry : m_plugins->entries()) { - if (!curentry.is_header()) + if (curentry->type() != core_options::option_type::HEADER) { - if (std::find(include.begin(), include.end(), curentry.name()) != include.end()) + if (std::find(include.begin(), include.end(), curentry->name()) != include.end()) { - std::string error_string; - m_plugins->set_value(curentry.name(), "1", OPTION_PRIORITY_CMDLINE, error_string); + m_plugins->set_value(curentry->name(), "1", OPTION_PRIORITY_CMDLINE); } - if (std::find(exclude.begin(), exclude.end(), curentry.name()) != exclude.end()) + if (std::find(exclude.begin(), exclude.end(), curentry->name()) != exclude.end()) { - std::string error_string; - m_plugins->set_value(curentry.name(), "0", OPTION_PRIORITY_CMDLINE, error_string); + m_plugins->set_value(curentry->name(), "0", OPTION_PRIORITY_CMDLINE); } } } } - if (options().console()) { - std::string error_string; - m_plugins->set_value("console", "1", OPTION_PRIORITY_CMDLINE, error_string); + if (options().console()) + { + m_plugins->set_value("console", "1", OPTION_PRIORITY_CMDLINE); } m_lua->initialize(); @@ -202,9 +204,8 @@ int mame_machine_manager::execute() // parse any INI files as the first thing if (m_options.read_config()) { - m_options.revert(OPTION_PRIORITY_INI); - std::string errors; - mame_options::parse_standard_inis(m_options,errors); + std::ostringstream errors; + mame_options::parse_standard_inis(m_options, errors); } // otherwise, perform validity checks before anything else @@ -216,11 +217,6 @@ int mame_machine_manager::execute() valid.check_shared_source(*system); } - // reevaluate slot options until nothing changes - while (mame_options::reevaluate_slot_options(m_options)) - { - } - // create the machine configuration machine_config config(*system, m_options); @@ -237,12 +233,13 @@ int mame_machine_manager::execute() if (m_new_driver_pending) { // set up new system name and adjust device options accordingly - mame_options::set_system_name(m_options,m_new_driver_pending->name); + m_options.set_system_name(m_new_driver_pending->name); m_firstrun = true; } else { - if (machine.exit_pending()) mame_options::set_system_name(m_options,""); + if (machine.exit_pending()) + m_options.set_system_name(""); } if (machine.exit_pending() && (!started_empty || is_empty)) diff --git a/src/frontend/mame/mameopts.cpp b/src/frontend/mame/mameopts.cpp index 9a00f1543e2..fc73c36a9f7 100644 --- a/src/frontend/mame/mameopts.cpp +++ b/src/frontend/mame/mameopts.cpp @@ -22,511 +22,21 @@ #include <stack> -int mame_options::m_slot_options = 0; -int mame_options::m_device_options = 0; - -//------------------------------------------------- -// add_slot_options - add all of the slot -// options for the configured system -//------------------------------------------------- - -bool mame_options::add_slot_options(emu_options &options, value_specifier_func value_specifier) -{ - // look up the system configured by name; if no match, do nothing - const game_driver *cursystem = system(options); - if (cursystem == nullptr) - return false; - - // create the configuration - machine_config config(*cursystem, options); - - // iterate through all slot devices - int starting_count = options.options_count(); - for (const device_slot_interface &slot : slot_interface_iterator(config.root_device())) - { - // skip fixed slots - if (slot.fixed()) - continue; - - // retrieve info about the device instance - const char *name = slot.device().tag() + 1; - if (!options.exists(name)) - { - // first device? add the header as to be pretty - if (m_slot_options++ == 0) - options.add_entry(nullptr, "SLOT DEVICES", OPTION_HEADER | OPTION_FLAG_DEVICE); - - // add the option - options.add_entry(name, nullptr, OPTION_STRING | OPTION_FLAG_DEVICE, slot.default_option(), true); - options.slot_options()[name] = slot_option(slot.default_option()); - - // allow opportunity to specify this value - if (value_specifier) - { - std::string specified_value = value_specifier(name); - if (specified_value != value_specifier_invalid_value()) - options.slot_options()[name].specify(std::move(specified_value)); - } - } - } - return (options.options_count() != starting_count); -} - - -//------------------------------------------------- -// update_slot_options - update slot values -// depending of image mounted -//------------------------------------------------- - -void mame_options::update_slot_options(emu_options &options, const software_part *swpart) -{ - // look up the system configured by name; if no match, do nothing - const game_driver *cursystem = system(options); - if (cursystem == nullptr) - return; - machine_config config(*cursystem, options); - - // iterate through all slot devices - for (device_slot_interface &slot : slot_interface_iterator(config.root_device())) - { - // retrieve info about the device instance - const char *name = slot.device().tag() + 1; - if (options.exists(name) && !slot.option_list().empty()) - { - std::string defvalue = get_default_card_software(slot, options); - if (defvalue.empty()) - { - // keep any non-default setting - if (options.priority(name) > OPTION_PRIORITY_DEFAULT) - continue; - - // reinstate the actual default value as configured - if (slot.default_option() != nullptr) - defvalue.assign(slot.default_option()); - } - - // set the value and hide the option if not selectable - options.set_default_value(name, defvalue.c_str()); - const device_slot_option *option = slot.option(defvalue.c_str()); - options.set_flag(name, ~OPTION_FLAG_INTERNAL, (option != nullptr && !option->selectable()) ? OPTION_FLAG_INTERNAL : 0); - } - } - add_device_options(options); -} - - -//------------------------------------------------- -// get_default_card_software -//------------------------------------------------- - -std::string mame_options::get_default_card_software(device_slot_interface &slot, const emu_options &options) -{ - std::string image_path; - std::function<bool(util::core_file &, std::string&)> get_hashfile_extrainfo; - - // figure out if an image option has been specified, and if so, get the image path out of the options - device_image_interface *image = dynamic_cast<device_image_interface *>(&slot); - if (image) - { - auto iter = options.image_options().find(image->instance_name()); - if (iter != options.image_options().end()) - image_path = iter->second; - - get_hashfile_extrainfo = [image, &options](util::core_file &file, std::string &extrainfo) - { - util::hash_collection hashes = image->calculate_hash_on_file(file); - - return hashfile_extrainfo( - options.hash_path(), - image->device().mconfig().gamedrv(), - hashes, - extrainfo); - }; - } - - // create the hook - get_default_card_software_hook hook(image_path, std::move(get_hashfile_extrainfo)); - - // and invoke the slot's implementation of get_default_card_software() - return slot.get_default_card_software(hook); -} - - -//------------------------------------------------- -// add_device_options - add all of the device -// options for the configured system -//------------------------------------------------- - -void mame_options::add_device_options(emu_options &options, value_specifier_func value_specifier) -{ - // look up the system configured by name; if no match, do nothing - const game_driver *cursystem = system(options); - if (cursystem == nullptr) - return; - machine_config config(*cursystem, options); - - // iterate through all image devices - for (device_image_interface &image : image_interface_iterator(config.root_device())) - { - if (!image.user_loadable()) - continue; - - // add the option - if (!options.exists(image.instance_name().c_str())) - { - // first device? add the header as to be pretty - if (m_device_options++ == 0) - options.add_entry(nullptr, "IMAGE DEVICES", OPTION_HEADER | OPTION_FLAG_DEVICE); - - // add the option - std::string option_name = get_full_option_name(image); - options.add_entry(option_name.c_str(), nullptr, OPTION_STRING | OPTION_FLAG_DEVICE, nullptr, true); - options.image_options()[image.instance_name()] = ""; - - // allow opportunity to specify this value - if (value_specifier) - { - std::string value = value_specifier(image.instance_name()); - if (value != value_specifier_invalid_value()) - options.image_options()[image.instance_name()] = std::move(value); - } - } - } -} - - -//------------------------------------------------- -// remove_device_options - remove device options -//------------------------------------------------- - -std::string mame_options::get_full_option_name(const device_image_interface &image) -{ - std::ostringstream option_name; - util::stream_format(option_name, "%s;%s", image.instance_name(), image.brief_instance_name()); - if (strcmp(image.device_typename(image.image_type()), image.instance_name().c_str()) == 0) - util::stream_format(option_name, ";%s1;%s1", image.instance_name(), image.brief_instance_name()); - return option_name.str(); -} - - -//------------------------------------------------- -// remove_device_options - remove device options -//------------------------------------------------- - -void mame_options::remove_device_options(emu_options &options) -{ - // iterate through options and remove interesting ones - core_options::entry *nextentry; - for (auto *curentry = options.first(); curentry != nullptr; curentry = nextentry) - { - // pre-fetch the next entry in case we delete this one - nextentry = curentry->next(); - - // if this is a device option, nuke it - if ((curentry->flags() & OPTION_FLAG_DEVICE) != 0) - options.remove_entry(*curentry); - } - - // take also care of ramsize options - options.set_default_value(OPTION_RAMSIZE, ""); - - // reset counters - m_slot_options = 0; - m_device_options = 0; -} - - -//------------------------------------------------- -// parse_slot_devices - parse the command line -// and update slot and image devices -//------------------------------------------------- - -void mame_options::parse_slot_devices(emu_options &options, value_specifier_func value_specifier) -{ - bool still_adding = true; - while (still_adding) - { - // keep adding slot options until we stop seeing new stuff - still_adding = false; - while (add_slot_options(options, value_specifier)) - still_adding = true; - - // add device options - add_device_options(options, value_specifier); - - if (reevaluate_slot_options(options)) - still_adding = true; - } -} - - -//------------------------------------------------- -// reevaluate_slot_options - based on recent changes -// in what images are mounted, give drivers a chance -// to specify new default slot options -//------------------------------------------------- - -bool mame_options::reevaluate_slot_options(emu_options &options) -{ - bool result = false; - - // look up the system configured by name; if no match, do nothing - const game_driver *cursystem = system(options); - if (cursystem == nullptr) - return result; - machine_config config(*cursystem, options); - - // iterate through all slot devices - for (device_slot_interface &slot : slot_interface_iterator(config.root_device())) - { - // retrieve info about the device instance - const char *name = slot.device().tag() + 1; - if (options.exists(name) && !slot.option_list().empty()) - { - // device_slot_interface::get_default_card_software() is essentially a hook - // that lets devices provide a feedback loop to force a specified software - // list entry to be loaded - // - // In the repeated cycle of adding slots and slot devices, this gives a chance - // for devices to "plug in" default software list items. Of course, the fact - // that this is all shuffling options is brittle and roundabout, but such is - // the nature of software lists. - // - // In reality, having some sort of hook into the pipeline of slot/device evaluation - // makes sense, but the fact that it is joined at the hip to device_image_interface - // and device_slot_interface is unfortunate - std::string default_card_software = get_default_card_software(slot, options); - if (!default_card_software.empty()) - { - // we have default card software - is this resulting in the slot option being mutated? - if (options.slot_options()[name].default_card_software() != default_card_software) - { - options.slot_options()[name].set_default_card_software(std::move(default_card_software)); - result = true; - } - } - } - } - return result; -} - - -//------------------------------------------------- -// parse_command_line - parse the command line -// and update the devices -//------------------------------------------------- - -bool mame_options::parse_command_line(emu_options &options, std::vector<std::string> &args, std::string &error_string) -{ - // parse the command line - if (!options.parse_command_line(args, OPTION_PRIORITY_CMDLINE, error_string)) - return false; - - // in order to evaluate softlist options, we need to fish any hashpath variable out of INI files; this is - // because hashpath in particular can affect softlist evaluation - if (options.software_name()[0] != '\0' && options.read_config()) - populate_hashpath_from_ini_files(options); - - // identify any options as a result of softlists - auto softlist_opts = evaluate_initial_softlist_options(options); - - // assemble a "value specifier" that will be used to specify options set up as a consequence - // of slot and device setup - auto value_specifier = [&options, &softlist_opts, &args, &error_string](const std::string &arg) - { - // first find within the command line - std::string arg_value; - bool success = options.pluck_from_command_line(args, arg, arg_value); - - // next try to find within softlist-specified options - if (!success) - { - auto iter = softlist_opts.find(arg); - if (iter != softlist_opts.end()) - { - arg_value = iter->second; - success = true; - } - } - - // did we find something? - return success - ? arg_value - : value_specifier_invalid_value(); - }; - - // some auxillary verbs expect that slot options are specified; and to do this we need to figure - // out if this is necessary for this particular auxillary verb, and if so, set the system name - if (!options.command().empty() - && cli_frontend::parse_slot_options_for_auxverb(options.command()) - && !options.command_arguments().empty() - && !core_iswildstr(options.command_arguments()[0].c_str())) - { - std::string error_string; - options.set_value(OPTION_SYSTEMNAME, options.command_arguments()[0].c_str(), OPTION_PRIORITY_CMDLINE, error_string); - - const game_driver *system = mame_options::system(options); - if (!system) - throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "Unknown system '%s'", options.system_name()); - } - - // parse the slot devices - parse_slot_devices(options, value_specifier); - - // at this point, we should have handled all arguments; the only argument that shouldn't have - // been handled is the file name - if (args.size() > 1) - { - error_string.append(string_format("Error: unknown option: %s\n", args[1])); - return false; - } - - return true; -} - - -//------------------------------------------------- -// evaluate_initial_softlist_options -//------------------------------------------------- - -std::map<std::string, std::string> mame_options::evaluate_initial_softlist_options(emu_options &options) -{ - std::map<std::string, std::string> results; - - // load software specified at the command line (if any of course) - std::string software_identifier = options.software_name(); - if (!software_identifier.empty()) - { - // we have software; first identify the proper game_driver - const game_driver *system = mame_options::system(options); - if (system == nullptr && *(options.system_name()) != 0) - throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "Unknown system '%s'", options.system_name()); - - // and set up a configuration - machine_config config(*system, options); - software_list_device_iterator iter(config.root_device()); - if (iter.count() == 0) - throw emu_fatalerror(EMU_ERR_FATALERROR, "Error: unknown option: %s\n", options.software_name()); - - // and finally set up the stack - std::stack<std::string> software_identifier_stack; - software_identifier_stack.push(software_identifier); - - // we need to keep evaluating softlist identifiers until the stack is empty - while (!software_identifier_stack.empty()) - { - // pop the identifier - software_identifier = std::move(software_identifier_stack.top()); - software_identifier_stack.pop(); - - // and parse it - std::string list_name, software_name; - auto colon_pos = software_identifier.find_first_of(':'); - if (colon_pos != std::string::npos) - { - list_name = software_identifier.substr(0, colon_pos); - software_name = software_identifier.substr(colon_pos + 1); - } - else - { - software_name = software_identifier; - } - - // loop through all softlist devices, and try to find one capable of handling the requested software - bool found = false; - bool compatible = false; - for (software_list_device &swlistdev : iter) - { - if (list_name.empty() || (list_name == swlistdev.list_name())) - { - const software_info *swinfo = swlistdev.find(software_name); - if (swinfo != nullptr) - { - // loop through all parts - for (const software_part &swpart : swinfo->parts()) - { - // only load compatible software this way - if (swlistdev.is_compatible(swpart) == SOFTWARE_IS_COMPATIBLE) - { - // we need to find a mountable image slot, but we need to ensure it is a slot - // for which we have not already distributed a part to - device_image_interface *image = software_list_device::find_mountable_image( - config, - swpart, - [&results](const device_image_interface &candidate) { return results.count(candidate.instance_name()) == 0; }); - - // did we find a slot to put this part into? - if (image != nullptr) - { - // we've resolved this software - results[image->instance_name()] = string_format("%s:%s:%s", swlistdev.list_name(), software_name, swpart.name()); - - // does this software part have a requirement on another part? - const char *requirement = swpart.feature("requirement"); - if (requirement) - software_identifier_stack.push(requirement); - } - compatible = true; - } - found = true; - } - - // identify other shared features specified as '<<slot name>>_default' - // - // example from SMS: - // - // <software name = "alexbmx"> - // ... - // <sharedfeat name = "ctrl1_default" value = "paddle" /> - // </software> - for (const feature_list_item &fi : swinfo->shared_info()) - { - const std::string default_suffix = "_default"; - if (fi.name().size() > default_suffix.size() - && fi.name().compare(fi.name().size() - default_suffix.size(), default_suffix.size(), default_suffix) == 0) - { - std::string slot_name = fi.name().substr(0, fi.name().size() - default_suffix.size()); - results[slot_name] = fi.value(); - } - } - } - } - if (compatible) - break; - } - - if (!compatible) - { - software_list_device::display_matches(config, nullptr, software_name); - if (!found) - throw emu_fatalerror(EMU_ERR_FATALERROR, nullptr); - else - throw emu_fatalerror(EMU_ERR_FATALERROR, "Software '%s' is incompatible with system '%s'\n", software_name.c_str(), options.system_name()); - } - } - } - return results; -} - - //------------------------------------------------- // parse_standard_inis - parse the standard set // of INI files //------------------------------------------------- -void mame_options::parse_standard_inis(emu_options &options, std::string &error_string, const game_driver *driver) +void mame_options::parse_standard_inis(emu_options &options, std::ostream &error_stream, const game_driver *driver) { - // start with an empty string - error_string.clear(); - // parse the INI file defined by the platform (e.g., "mame.ini") // we do this twice so that the first file can change the INI path - parse_one_ini(options,emulator_info::get_configname(), OPTION_PRIORITY_MAME_INI); - parse_one_ini(options,emulator_info::get_configname(), OPTION_PRIORITY_MAME_INI, &error_string); + parse_one_ini(options, emulator_info::get_configname(), OPTION_PRIORITY_MAME_INI); + parse_one_ini(options, emulator_info::get_configname(), OPTION_PRIORITY_MAME_INI, &error_stream); // debug mode: parse "debug.ini" as well if (options.debug()) - parse_one_ini(options,"debug", OPTION_PRIORITY_DEBUG_INI, &error_string); + parse_one_ini(options, "debug", OPTION_PRIORITY_DEBUG_INI, &error_stream); // if we have a valid system driver, parse system-specific INI files const game_driver *cursystem = (driver == nullptr) ? system(options) : driver; @@ -535,18 +45,18 @@ void mame_options::parse_standard_inis(emu_options &options, std::string &error_ // parse "vertical.ini" or "horizont.ini" if (cursystem->flags & ORIENTATION_SWAP_XY) - parse_one_ini(options,"vertical", OPTION_PRIORITY_ORIENTATION_INI, &error_string); + parse_one_ini(options, "vertical", OPTION_PRIORITY_ORIENTATION_INI, &error_stream); else - parse_one_ini(options,"horizont", OPTION_PRIORITY_ORIENTATION_INI, &error_string); + parse_one_ini(options, "horizont", OPTION_PRIORITY_ORIENTATION_INI, &error_stream); if (cursystem->flags & MACHINE_TYPE_ARCADE) - parse_one_ini(options,"arcade", OPTION_PRIORITY_SYSTYPE_INI, &error_string); + parse_one_ini(options, "arcade", OPTION_PRIORITY_SYSTYPE_INI, &error_stream); else if (cursystem->flags & MACHINE_TYPE_CONSOLE) - parse_one_ini(options,"console", OPTION_PRIORITY_SYSTYPE_INI, &error_string); + parse_one_ini(options ,"console", OPTION_PRIORITY_SYSTYPE_INI, &error_stream); else if (cursystem->flags & MACHINE_TYPE_COMPUTER) - parse_one_ini(options,"computer", OPTION_PRIORITY_SYSTYPE_INI, &error_string); + parse_one_ini(options, "computer", OPTION_PRIORITY_SYSTYPE_INI, &error_stream); else if (cursystem->flags & MACHINE_TYPE_OTHER) - parse_one_ini(options,"othersys", OPTION_PRIORITY_SYSTYPE_INI, &error_string); + parse_one_ini(options, "othersys", OPTION_PRIORITY_SYSTYPE_INI, &error_stream); machine_config config(*cursystem, options); for (const screen_device &device : screen_device_iterator(config.root_device())) @@ -554,35 +64,35 @@ void mame_options::parse_standard_inis(emu_options &options, std::string &error_ // parse "raster.ini" for raster games if (device.screen_type() == SCREEN_TYPE_RASTER) { - parse_one_ini(options,"raster", OPTION_PRIORITY_SCREEN_INI, &error_string); + parse_one_ini(options, "raster", OPTION_PRIORITY_SCREEN_INI, &error_stream); break; } // parse "vector.ini" for vector games if (device.screen_type() == SCREEN_TYPE_VECTOR) { - parse_one_ini(options,"vector", OPTION_PRIORITY_SCREEN_INI, &error_string); + parse_one_ini(options, "vector", OPTION_PRIORITY_SCREEN_INI, &error_stream); break; } // parse "lcd.ini" for lcd games if (device.screen_type() == SCREEN_TYPE_LCD) { - parse_one_ini(options,"lcd", OPTION_PRIORITY_SCREEN_INI, &error_string); + parse_one_ini(options, "lcd", OPTION_PRIORITY_SCREEN_INI, &error_stream); break; } } // next parse "source/<sourcefile>.ini" std::string sourcename = core_filename_extract_base(cursystem->type.source(), true).insert(0, "source" PATH_SEPARATOR); - parse_one_ini(options,sourcename.c_str(), OPTION_PRIORITY_SOURCE_INI, &error_string); + parse_one_ini(options, sourcename.c_str(), OPTION_PRIORITY_SOURCE_INI, &error_stream); // then parse the grandparent, parent, and system-specific INIs int parent = driver_list::clone(*cursystem); int gparent = (parent != -1) ? driver_list::clone(parent) : -1; if (gparent != -1) - parse_one_ini(options,driver_list::driver(gparent).name, OPTION_PRIORITY_GPARENT_INI, &error_string); + parse_one_ini(options, driver_list::driver(gparent).name, OPTION_PRIORITY_GPARENT_INI, &error_stream); if (parent != -1) - parse_one_ini(options,driver_list::driver(parent).name, OPTION_PRIORITY_PARENT_INI, &error_string); - parse_one_ini(options,cursystem->name, OPTION_PRIORITY_DRIVER_INI, &error_string); + parse_one_ini(options, driver_list::driver(parent).name, OPTION_PRIORITY_PARENT_INI, &error_stream); + parse_one_ini(options, cursystem->name, OPTION_PRIORITY_DRIVER_INI, &error_stream); } @@ -599,136 +109,89 @@ const game_driver *mame_options::system(const emu_options &options) //------------------------------------------------- -// set_system_name - set a new system name -//------------------------------------------------- - -void mame_options::set_system_name(emu_options &options, const char *name) -{ - // remember the original system name - std::string old_system_name(options.system_name()); - bool new_system = old_system_name.compare(name) != 0; - - // if the system name changed, fix up the device options - if (new_system) - { - // first set the new name - std::string error; - options.set_value(OPTION_SYSTEMNAME, name, OPTION_PRIORITY_CMDLINE, error); - assert(error.empty()); - - // remove any existing device options - remove_device_options(options); - } - else - { - // revert device options set for the old software - options.revert(OPTION_PRIORITY_SUBCMD, OPTION_PRIORITY_SUBCMD); - } - - // get the new system - const game_driver *cursystem = system(options); - if (cursystem == nullptr) - return; - - if (*options.software_name() != 0) - { - std::string sw_load(options.software_name()); - std::string sw_list, sw_name, sw_part, sw_instance, error_string; - int left = sw_load.find_first_of(':'); - int middle = sw_load.find_first_of(':', left + 1); - int right = sw_load.find_last_of(':'); - - sw_list = sw_load.substr(0, left); - sw_name = sw_load.substr(left + 1, middle - left - 1); - sw_part = sw_load.substr(middle + 1, right - middle - 1); - sw_instance = sw_load.substr(right + 1); - sw_load.assign(sw_load.substr(0, right)); - - // look up the software part - machine_config config(*cursystem, options); - software_list_device *swlist = software_list_device::find_by_name(config, sw_list.c_str()); - const software_info *swinfo = swlist != nullptr ? swlist->find(sw_name.c_str()) : nullptr; - const software_part *swpart = swinfo != nullptr ? swinfo->find_part(sw_part.c_str()) : nullptr; - if (swpart == nullptr) - osd_printf_warning("Could not find %s in software list\n", options.software_name()); - - // then add the options - if (new_system) - { - while (add_slot_options(options)) {} - add_device_options(options); - } - - options.set_value(OPTION_SOFTWARENAME, sw_name.c_str(), OPTION_PRIORITY_CMDLINE, error_string); - if (options.exists(sw_instance.c_str())) - options.set_value(sw_instance.c_str(), sw_load.c_str(), OPTION_PRIORITY_SUBCMD, error_string); - - int num; - do { - num = options.options_count(); - update_slot_options(options,swpart); - } while (num != options.options_count()); - } - else if (new_system) - { - // add the options afresh - while (add_slot_options(options)) {} - add_device_options(options); - int num; - do { - num = options.options_count(); - update_slot_options(options); - } while (num != options.options_count()); - } -} - -//------------------------------------------------- // parse_one_ini - parse a single INI file //------------------------------------------------- -bool mame_options::parse_one_ini(emu_options &options, const char *basename, int priority, std::string *error_string) +void mame_options::parse_one_ini(emu_options &options, const char *basename, int priority, std::ostream *error_stream) { // don't parse if it has been disabled if (!options.read_config()) - return false; + return; // open the file; if we fail, that's ok emu_file file(options.ini_path(), OPEN_FLAG_READ); osd_printf_verbose("Attempting load of %s.ini\n", basename); osd_file::error filerr = file.open(basename, ".ini"); if (filerr != osd_file::error::NONE) - return false; + return; // parse the file osd_printf_verbose("Parsing %s.ini\n", basename); - std::string error; - bool result = options.parse_ini_file((util::core_file&)file, priority, priority < OPTION_PRIORITY_DRIVER_INI, error); - - // append errors if requested - if (!error.empty() && error_string) - error_string->append(string_format("While parsing %s:\n%s\n", file.fullpath(), error)); + try + { + options.parse_ini_file((util::core_file&)file, priority, priority < OPTION_PRIORITY_DRIVER_INI, false); + } + catch (options_exception &ex) + { + if (error_stream) + util::stream_format(*error_stream, "While parsing %s:\n%s\n", ex.message(), file.fullpath(), ex.message()); + return; + } - return result; } //------------------------------------------------- -// populate_hashpath_from_ini_files +// populate_hashpath_from_args_and_inis //------------------------------------------------- -void mame_options::populate_hashpath_from_ini_files(emu_options &options) +void mame_options::populate_hashpath_from_args_and_inis(emu_options &options, const std::vector<std::string> &args) { - // create temporary emu_options for the purposes of evaluating the INI files - emu_options temp_options; - std::string temp_error_string; - temp_options.set_value(OPTION_SYSTEMNAME, options.system_name(), OPTION_PRIORITY_MAXIMUM, temp_error_string); - temp_options.set_value(OPTION_INIPATH, options.ini_path(), OPTION_PRIORITY_MAXIMUM, temp_error_string); + // The existence of this function comes from the fact that for softlist options to be properly + // evaluated, we need to have the hashpath variable set. The problem is that the hashpath may + // be set anywhere on the command line, but also in any of the myriad INI files that we parse, some + // of which may be system specific (e.g. - nes.ini) or otherwise influenced by the system (e.g. - vector.ini) + // + // I think that it is terrible that we have to do a completely independent pass on the command line and every + // argument simply because any one of these things might be setting - hashpath.Unless we invest the effort in + // building some sort of "late binding" apparatus for options(e.g. - delay evaluation of softlist options until + // we've scoured all INIs for hashpath) that can completely straddle the command line and the INI worlds, doing + // this is the best that we can do IMO. + + // parse the command line + emu_options temp_options(emu_options::option_support::GENERAL_AND_SYSTEM); + try + { + temp_options.parse_command_line(args, OPTION_PRIORITY_CMDLINE, true); + } + catch (options_exception &) + { + // Something is very long; we have bigger problems than -hashpath possibly + // being in never-never land. Punt and let the main code fail + return; + } + + // if we have an auxillary verb, hashpath is irrelevant + if (!temp_options.command().empty()) + return; - // read the INIs into temp_options - parse_standard_inis(temp_options, temp_error_string); + // read INI files + if (temp_options.read_config()) + { + std::ostringstream error_stream; + parse_standard_inis(temp_options, error_stream); + } // and fish out hashpath const auto entry = temp_options.get_entry(OPTION_HASHPATH); if (entry) - options.set_value(OPTION_HASHPATH, entry->value(), entry->priority(), temp_error_string); + { + try + { + options.set_value(OPTION_HASHPATH, entry->value(), entry->priority()); + } + catch (options_exception &) + { + } + } } diff --git a/src/frontend/mame/mameopts.h b/src/frontend/mame/mameopts.h index f9ee3325e52..2b178fb2ead 100644 --- a/src/frontend/mame/mameopts.h +++ b/src/frontend/mame/mameopts.h @@ -50,45 +50,15 @@ class software_part; class mame_options { - static const uint32_t OPTION_FLAG_DEVICE = 0x80000000; - public: - typedef std::function<std::string (const std::string &)> value_specifier_func; - // parsing wrappers - static bool parse_command_line(emu_options &options, std::vector<std::string> &args, std::string &error_string); - static void parse_standard_inis(emu_options &options, std::string &error_string, const game_driver *driver = nullptr); - // FIXME: Couriersud: This should be in image_device_exit - static void remove_device_options(emu_options &options); - + static void parse_standard_inis(emu_options &options, std::ostream &error_stream, const game_driver *driver = nullptr); static const game_driver *system(const emu_options &options); - static void set_system_name(emu_options &options, const char *name); - static bool add_slot_options(emu_options &options, value_specifier_func value_specifier = nullptr); - static bool reevaluate_slot_options(emu_options &options); + static void populate_hashpath_from_args_and_inis(emu_options &options, const std::vector<std::string> &args); private: - // device-specific option handling - static void add_device_options(emu_options &options, value_specifier_func value_specifier = nullptr); - static void update_slot_options(emu_options &options, const software_part *swpart = nullptr); - static void parse_slot_devices(emu_options &options, value_specifier_func value_specifier); - static std::string get_full_option_name(const device_image_interface &image); - static std::string get_default_card_software(device_slot_interface &slot, const emu_options &options); - // INI parsing helper - static bool parse_one_ini(emu_options &options, const char *basename, int priority, std::string *error_string = nullptr); - - // softlist handling - static std::map<std::string, std::string> evaluate_initial_softlist_options(emu_options &options); - - // special function to fish hashpath out of INI files - needed for softlist processing - static void populate_hashpath_from_ini_files(emu_options &options); - - // represents an "invalid" value (an empty string is valid so we can't use that; what I - // really want to return is std::optional<std::string> but C++17 isn't here yet) - static std::string value_specifier_invalid_value() { return std::string("\x01\x02\x03"); } - - static int m_slot_options; - static int m_device_options; + static void parse_one_ini(emu_options &options, const char *basename, int priority, std::ostream *error_stream = nullptr); }; #endif // MAME_FRONTEND_MAMEOPTS_H diff --git a/src/frontend/mame/pluginopts.cpp b/src/frontend/mame/pluginopts.cpp index 779ac6ff709..b9a9e8d3c3b 100644 --- a/src/frontend/mame/pluginopts.cpp +++ b/src/frontend/mame/pluginopts.cpp @@ -75,7 +75,7 @@ void plugin_options::parse_json(std::string path) if (type=="plugin") { - add_entry(core_strdup(plugin_name.c_str()),core_strdup(description.c_str()), OPTION_BOOLEAN, start ? "1" : "0"); + add_entry({ std::move(plugin_name) }, core_strdup(description.c_str()), option_type::BOOLEAN, start ? "1" : "0"); } } diff --git a/src/frontend/mame/ui/custui.cpp b/src/frontend/mame/ui/custui.cpp index 21b2f196440..8f1614861cb 100644 --- a/src/frontend/mame/ui/custui.cpp +++ b/src/frontend/mame/ui/custui.cpp @@ -64,12 +64,10 @@ menu_custom_ui::menu_custom_ui(mame_ui_manager &mui, render_container &container menu_custom_ui::~menu_custom_ui() { - std::string error_string; - ui().options().set_value(OPTION_HIDE_PANELS, ui_globals::panels_status, OPTION_PRIORITY_CMDLINE, error_string); + ui().options().set_value(OPTION_HIDE_PANELS, ui_globals::panels_status, OPTION_PRIORITY_CMDLINE); if (!m_lang.empty()) { - machine().options().set_value(OPTION_LANGUAGE, m_lang[m_currlang].c_str(), OPTION_PRIORITY_CMDLINE, error_string); - machine().options().mark_changed(OPTION_LANGUAGE); + machine().options().set_value(OPTION_LANGUAGE, m_lang[m_currlang].c_str(), OPTION_PRIORITY_CMDLINE); load_translation(machine().options()); } ui_globals::reset = true; @@ -215,22 +213,10 @@ menu_font_ui::menu_font_ui(mame_ui_manager &mui, render_container &container) : m_info_size = moptions.infos_size(); m_font_size = moptions.font_rows(); - - for (ui_options::entry &f_entry : moptions) - { - const char *entry_name = f_entry.name(); - if (entry_name && strlen(entry_name) && !strcmp(OPTION_INFOS_SIZE, f_entry.name())) - { - m_info_max = atof(f_entry.maximum()); - m_info_min = atof(f_entry.minimum()); - } - else if (entry_name && strlen(entry_name) && !strcmp(OPTION_FONT_ROWS, f_entry.name())) - { - m_font_max = atof(f_entry.maximum()); - m_font_min = atof(f_entry.minimum()); - } - } - + m_info_max = atof(moptions.get_entry(OPTION_INFOS_SIZE)->maximum()); + m_info_min = atof(moptions.get_entry(OPTION_INFOS_SIZE)->minimum()); + m_font_max = atof(moptions.get_entry(OPTION_FONT_ROWS)->maximum()); + m_font_max = atof(moptions.get_entry(OPTION_FONT_ROWS)->minimum()); } //------------------------------------------------- @@ -264,11 +250,9 @@ menu_font_ui::~menu_font_ui() name.insert(0, "[B]"); } #endif - machine().options().set_value(OPTION_UI_FONT, name.c_str(), OPTION_PRIORITY_CMDLINE, error_string); - machine().options().mark_changed(OPTION_UI_FONT); - - moptions.set_value(OPTION_INFOS_SIZE, m_info_size, OPTION_PRIORITY_CMDLINE, error_string); - moptions.set_value(OPTION_FONT_ROWS, m_font_size, OPTION_PRIORITY_CMDLINE, error_string); + machine().options().set_value(OPTION_UI_FONT, name, OPTION_PRIORITY_CMDLINE); + moptions.set_value(OPTION_INFOS_SIZE, m_info_size, OPTION_PRIORITY_CMDLINE); + moptions.set_value(OPTION_FONT_ROWS, m_font_size, OPTION_PRIORITY_CMDLINE); } //------------------------------------------------- @@ -463,11 +447,11 @@ menu_colors_ui::menu_colors_ui(mame_ui_manager &mui, render_container &container menu_colors_ui::~menu_colors_ui() { - std::string error_string, dec_color; + std::string dec_color; for (int index = 1; index < MUI_RESTORE; index++) { dec_color = string_format("%x", (uint32_t)m_color_table[index].color); - ui().options().set_value(m_color_table[index].option, dec_color.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + ui().options().set_value(m_color_table[index].option, dec_color.c_str(), OPTION_PRIORITY_CMDLINE); } } diff --git a/src/frontend/mame/ui/dirmenu.cpp b/src/frontend/mame/ui/dirmenu.cpp index baea5973efb..bb1494e37c5 100644 --- a/src/frontend/mame/ui/dirmenu.cpp +++ b/src/frontend/mame/ui/dirmenu.cpp @@ -352,11 +352,10 @@ void menu_add_change_folder::handle() if (m_change) { if (ui().options().exists(s_folders[m_ref].option)) - ui().options().set_value(s_folders[m_ref].option, m_current_path.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + ui().options().set_value(s_folders[m_ref].option, m_current_path.c_str(), OPTION_PRIORITY_CMDLINE); else if (strcmp(machine().options().value(s_folders[m_ref].option), m_current_path.c_str()) != 0) { - machine().options().set_value(s_folders[m_ref].option, m_current_path.c_str(), OPTION_PRIORITY_CMDLINE, error_string); - machine().options().mark_changed(s_folders[m_ref].option); + machine().options().set_value(s_folders[m_ref].option, m_current_path.c_str(), OPTION_PRIORITY_CMDLINE); } } else @@ -371,11 +370,10 @@ void menu_add_change_folder::handle() } if (ui().options().exists(s_folders[m_ref].option)) - ui().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + ui().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE); else if (strcmp(machine().options().value(s_folders[m_ref].option), tmppath.c_str()) != 0) { - machine().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE, error_string); - machine().options().mark_changed(s_folders[m_ref].option); + machine().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE); } } @@ -592,11 +590,10 @@ void menu_remove_folder::handle() } if (ui().options().exists(s_folders[m_ref].option)) - ui().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + ui().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE); else if (strcmp(machine().options().value(s_folders[m_ref].option),tmppath.c_str())!=0) { - machine().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE, error_string); - machine().options().mark_changed(s_folders[m_ref].option); + machine().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE); } reset_parent(reset_options::REMEMBER_REF); diff --git a/src/frontend/mame/ui/info.cpp b/src/frontend/mame/ui/info.cpp index dfcffcac1fb..e4abb6ce94d 100644 --- a/src/frontend/mame/ui/info.cpp +++ b/src/frontend/mame/ui/info.cpp @@ -326,8 +326,7 @@ std::string machine_info::mandatory_images() { if (image.must_be_loaded()) { - auto iter = m_machine.options().image_options().find(image.instance_name()); - if (iter == m_machine.options().image_options().end() || iter->second.empty()) + if (m_machine.options().image_option(image.instance_name()).value().empty()) { if (is_first) is_first = false; diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp index 6d797bc8dda..e48b042b53d 100644 --- a/src/frontend/mame/ui/miscmenu.cpp +++ b/src/frontend/mame/ui/miscmenu.cpp @@ -127,12 +127,10 @@ void menu_bios_selection::handle() if (val>cnt) val=1; dev->set_system_bios(val); if (strcmp(dev->tag(),":")==0) { - std::string error; - machine().options().set_value("bios", val-1, OPTION_PRIORITY_CMDLINE, error); - assert(error.empty()); + machine().options().set_value("bios", val-1, OPTION_PRIORITY_CMDLINE); } else { const char *slot_option_name = dev->owner()->tag() + 1; - machine().options().slot_options()[slot_option_name].set_bios(string_format("%d", val - 1)); + machine().options().slot_option(slot_option_name).set_bios(string_format("%d", val - 1)); } reset(reset_options::REMEMBER_REF); } @@ -671,15 +669,14 @@ void menu_export::populate(float &customtop, float &custombottom) menu_machine_configure::menu_machine_configure(mame_ui_manager &mui, render_container &container, const game_driver *prev, float _x0, float _y0) : menu(mui, container) , m_drv(prev) - , m_opts(mui.machine().options()) , x0(_x0) , y0(_y0) , m_curbios(0) , m_fav_reset(false) { // parse the INI file - std::string error; - mame_options::parse_standard_inis(m_opts,error, m_drv); + std::ostringstream error; + mame_options::parse_standard_inis(m_opts, error, m_drv); setup_bios(); } @@ -750,9 +747,7 @@ void menu_machine_configure::handle() else if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT) { (menu_event->iptkey == IPT_UI_LEFT) ? --m_curbios : ++m_curbios; - std::string error; - m_opts.set_value(OPTION_BIOS, m_bios[m_curbios].second, OPTION_PRIORITY_CMDLINE, error); - m_opts.mark_changed(OPTION_BIOS); + m_opts.set_value(OPTION_BIOS, m_bios[m_curbios].second, OPTION_PRIORITY_CMDLINE); reset(reset_options::REMEMBER_POSITION); } } @@ -914,8 +909,7 @@ void menu_plugins_configure::handle() if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT || menu_event->iptkey == IPT_UI_SELECT) { int oldval = plugins.int_value((const char*)menu_event->itemref); - std::string error_string; - plugins.set_value((const char*)menu_event->itemref, oldval == 1 ? 0 : 1, OPTION_PRIORITY_CMDLINE, error_string); + plugins.set_value((const char*)menu_event->itemref, oldval == 1 ? 0 : 1, OPTION_PRIORITY_CMDLINE); changed = true; } } @@ -931,13 +925,13 @@ void menu_plugins_configure::populate(float &customtop, float &custombottom) { plugin_options& plugins = mame_machine_manager::instance()->plugins(); - for (auto &curentry : plugins) + for (auto &curentry : plugins.entries()) { - if (!curentry.is_header()) + if (curentry->type() != OPTION_HEADER) { - auto enabled = std::string(curentry.value()) == "1"; - item_append(curentry.description(), enabled ? _("On") : _("Off"), - enabled ? FLAG_RIGHT_ARROW : FLAG_LEFT_ARROW, (void *)(uintptr_t)curentry.name()); + auto enabled = !strcmp(curentry->value(), "1"); + item_append(curentry->description(), enabled ? _("On") : _("Off"), + enabled ? FLAG_RIGHT_ARROW : FLAG_LEFT_ARROW, (void *)(uintptr_t)curentry->name().c_str()); } } item_append(menu_item_type::SEPARATOR); diff --git a/src/frontend/mame/ui/selgame.cpp b/src/frontend/mame/ui/selgame.cpp index faeb1f33aff..33cebb00083 100644 --- a/src/frontend/mame/ui/selgame.cpp +++ b/src/frontend/mame/ui/selgame.cpp @@ -116,8 +116,7 @@ menu_select_game::menu_select_game(mame_ui_manager &mui, render_container &conta if (!moptions.remember_last()) reselect_last::reset(); - mui.machine().options().set_value(OPTION_SNAPNAME, "%g/%i", OPTION_PRIORITY_CMDLINE, error_string); - mui.machine().options().set_value(OPTION_SOFTWARENAME, "", OPTION_PRIORITY_CMDLINE, error_string); + mui.machine().options().set_value(OPTION_SNAPNAME, "%g/%i", OPTION_PRIORITY_CMDLINE); ui_globals::curimage_view = FIRST_VIEW; ui_globals::curdats_view = 0; @@ -155,9 +154,9 @@ menu_select_game::~menu_select_game() filter.append(",").append(c_year::ui[c_year::actual]); ui_options &mopt = ui().options(); - mopt.set_value(OPTION_LAST_USED_FILTER, filter.c_str(), OPTION_PRIORITY_CMDLINE, error_string); - mopt.set_value(OPTION_LAST_USED_MACHINE, last_driver.c_str(), OPTION_PRIORITY_CMDLINE, error_string); - mopt.set_value(OPTION_HIDE_PANELS, ui_globals::panels_status, OPTION_PRIORITY_CMDLINE, error_string); + mopt.set_value(OPTION_LAST_USED_FILTER, filter.c_str(), OPTION_PRIORITY_CMDLINE); + mopt.set_value(OPTION_LAST_USED_MACHINE, last_driver.c_str(), OPTION_PRIORITY_CMDLINE); + mopt.set_value(OPTION_HIDE_PANELS, ui_globals::panels_status, OPTION_PRIORITY_CMDLINE); ui().save_ui_options(); } @@ -942,11 +941,10 @@ void menu_select_game::inkey_select_favorite(const event *menu_event) return; } - std::string error_string; std::string string_list = string_format("%s:%s:%s:%s", ui_swinfo->listname, ui_swinfo->shortname, ui_swinfo->part, ui_swinfo->instance); - mopt.set_value(OPTION_SOFTWARENAME, string_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + mopt.set_value(OPTION_SOFTWARENAME, string_list.c_str(), OPTION_PRIORITY_CMDLINE); std::string snap_list = std::string(ui_swinfo->listname).append(PATH_SEPARATOR).append(ui_swinfo->shortname); - mopt.set_value(OPTION_SNAPNAME, snap_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + mopt.set_value(OPTION_SNAPNAME, snap_list.c_str(), OPTION_PRIORITY_CMDLINE); reselect_last::driver = drv.driver().name; reselect_last::software = ui_swinfo->shortname; reselect_last::swlist = ui_swinfo->listname; diff --git a/src/frontend/mame/ui/selsoft.cpp b/src/frontend/mame/ui/selsoft.cpp index 5d95d4c9a2e..305cd3b76c1 100644 --- a/src/frontend/mame/ui/selsoft.cpp +++ b/src/frontend/mame/ui/selsoft.cpp @@ -144,9 +144,6 @@ menu_select_software::menu_select_software(mame_ui_manager &mui, render_containe ui_globals::switch_image = true; ui_globals::cur_sw_dats_view = 0; ui_globals::cur_sw_dats_total = 1; - - std::string error_string; - mui.machine().options().set_value(OPTION_SOFTWARENAME, "", OPTION_PRIORITY_CMDLINE, error_string); } //------------------------------------------------- @@ -718,11 +715,10 @@ void menu_select_software::inkey_select(const event *menu_event) return; } - std::string error_string; - std::string string_list = std::string(ui_swinfo->listname).append(":").append(ui_swinfo->shortname).append(":").append(ui_swinfo->part).append(":").append(ui_swinfo->instance); - machine().options().set_value(OPTION_SOFTWARENAME, string_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + machine().options().set_system_name(m_driver->name); + machine().options().set_value(OPTION_SOFTWARENAME, ui_swinfo->shortname, OPTION_PRIORITY_CMDLINE); std::string snap_list = std::string(ui_swinfo->listname).append(PATH_SEPARATOR).append(ui_swinfo->shortname); - machine().options().set_value(OPTION_SNAPNAME, snap_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + machine().options().set_value(OPTION_SNAPNAME, snap_list.c_str(), OPTION_PRIORITY_CMDLINE); reselect_last::driver = drivlist.driver().name; reselect_last::software = ui_swinfo->shortname; reselect_last::swlist = ui_swinfo->listname; @@ -1288,9 +1284,8 @@ void software_parts::handle() { if ((void*)&elem == menu_event->itemref) { - std::string error_string; std::string string_list = std::string(m_uiinfo->listname).append(":").append(m_uiinfo->shortname).append(":").append(elem.first).append(":").append(m_uiinfo->instance); - machine().options().set_value(OPTION_SOFTWARENAME, string_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + machine().options().set_value(OPTION_SOFTWARENAME, string_list.c_str(), OPTION_PRIORITY_CMDLINE); reselect_last::driver = m_uiinfo->driver->name; reselect_last::software = m_uiinfo->shortname; @@ -1298,7 +1293,7 @@ void software_parts::handle() reselect_last::set(true); std::string snap_list = std::string(m_uiinfo->listname).append("/").append(m_uiinfo->shortname); - machine().options().set_value(OPTION_SNAPNAME, snap_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + machine().options().set_value(OPTION_SNAPNAME, snap_list.c_str(), OPTION_PRIORITY_CMDLINE); mame_machine_manager::instance()->schedule_new_driver(*m_uiinfo->driver); machine().schedule_hard_reset(); @@ -1400,8 +1395,7 @@ void bios_selection::handle() reselect_last::set(true); } - std::string error; - moptions.set_value(OPTION_BIOS, elem.second, OPTION_PRIORITY_CMDLINE, error); + moptions.set_value(OPTION_BIOS, elem.second, OPTION_PRIORITY_CMDLINE); mame_machine_manager::instance()->schedule_new_driver(*s_driver); machine().schedule_hard_reset(); stack_reset(); @@ -1409,8 +1403,7 @@ void bios_selection::handle() else { ui_software_info *ui_swinfo = (ui_software_info *)m_driver; - std::string error; - machine().options().set_value(OPTION_BIOS, elem.second, OPTION_PRIORITY_CMDLINE, error); + machine().options().set_value(OPTION_BIOS, elem.second, OPTION_PRIORITY_CMDLINE); driver_enumerator drivlist(machine().options(), *ui_swinfo->driver); drivlist.next(); software_list_device *swlist = software_list_device::find_by_name(*drivlist.config(), ui_swinfo->listname.c_str()); @@ -1431,11 +1424,10 @@ void bios_selection::handle() menu::stack_push<software_parts>(ui(), container(), parts, ui_swinfo); return; } - std::string error_string; std::string string_list = std::string(ui_swinfo->listname).append(":").append(ui_swinfo->shortname).append(":").append(ui_swinfo->part).append(":").append(ui_swinfo->instance); - moptions.set_value(OPTION_SOFTWARENAME, string_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + moptions.set_value(OPTION_SOFTWARENAME, string_list.c_str(), OPTION_PRIORITY_CMDLINE); std::string snap_list = std::string(ui_swinfo->listname).append(PATH_SEPARATOR).append(ui_swinfo->shortname); - moptions.set_value(OPTION_SNAPNAME, snap_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string); + moptions.set_value(OPTION_SNAPNAME, snap_list.c_str(), OPTION_PRIORITY_CMDLINE); reselect_last::driver = drivlist.driver().name; reselect_last::software = ui_swinfo->shortname; reselect_last::swlist = ui_swinfo->listname; diff --git a/src/frontend/mame/ui/slotopt.cpp b/src/frontend/mame/ui/slotopt.cpp index 1e3d8faff88..71507bf426f 100644 --- a/src/frontend/mame/ui/slotopt.cpp +++ b/src/frontend/mame/ui/slotopt.cpp @@ -100,10 +100,10 @@ device_slot_option *menu_slot_devices::get_current_option(device_slot_interface { std::string current; - const char *slot_option_name = slot.slot_name(); - if (!slot.fixed() && machine().options().slot_options().count(slot_option_name) > 0) + if (!slot.fixed()) { - current = machine().options().slot_options()[slot_option_name].value(); + const char *slot_option_name = slot.slot_name(); + current = machine().options().slot_option(slot_option_name).value(); } else { @@ -185,9 +185,82 @@ const char *menu_slot_devices::get_previous_slot(device_slot_interface &slot) co void menu_slot_devices::set_slot_device(device_slot_interface &slot, const char *val) { - std::string error; - machine().options().set_value(slot.slot_name(), val, OPTION_PRIORITY_CMDLINE, error); - assert(error.empty()); + // we might change slot options; in the spirit of user friendliness, we should record all current + // options + record_current_options(); + + // find the slot option + slot_option &opt(machine().options().slot_option(slot.slot_name())); + + // specify it + opt.specify(val); + + // erase this from our recorded options list - this is the slot we're trying to change! + m_slot_options.erase(slot.slot_name()); + + // refresh any options that we might have annotated earlier + while (try_refresh_current_options()) + ; + + // changing the options may result in options changing; we need to reset + reset(reset_options::REMEMBER_POSITION); +} + + +//------------------------------------------------- +// record_current_options +//------------------------------------------------- + +void menu_slot_devices::record_current_options() +{ + for (device_slot_interface &slot : slot_interface_iterator(m_config->root_device())) + { + // we're doing this out of a desire to honor user-selectable options; therefore it only + // makes sense to record values for selectable options + if (slot.has_selectable_options()) + { + // get the slot option + const slot_option &opt(machine().options().slot_option(slot.slot_name())); + + // and record the value in our local cache + m_slot_options[slot.slot_name()] = opt.specified_value(); + } + } +} + + +//------------------------------------------------- +// try_refresh_current_options +//------------------------------------------------- + +bool menu_slot_devices::try_refresh_current_options() +{ + // enumerate through all slot options that we've tracked + for (const auto &opt : m_slot_options) + { + // do we have a value different than what we're tracking? + slot_option *slotopt = machine().options().find_slot_option(opt.first); + if (slotopt && slotopt->specified_value() != opt.second) + { + // specify this option (but catch errors) + try + { + slotopt->specify(opt.second); + + // the option was successfully specified; it isn't safe to continue + // checking slots as the act of specifying the slot may have drastically + // changed the options list + return true; + } + catch (options_exception &) + { + // this threw an exception - that is fine; we can just proceed + } + } + } + + // we've went through all options without changing anything + return false; } @@ -197,8 +270,12 @@ void menu_slot_devices::set_slot_device(device_slot_interface &slot, const char void menu_slot_devices::populate(float &customtop, float &custombottom) { + // we need to keep our own copy of the machine_config because we + // can change this out from under the caller + m_config = std::make_unique<machine_config>(machine().system(), machine().options()); + // cycle through all devices for this system - for (device_slot_interface &slot : slot_interface_iterator(machine().root_device())) + for (device_slot_interface &slot : slot_interface_iterator(m_config->root_device())) { // does this slot have any selectable options? bool has_selectable_options = slot.has_selectable_options(); @@ -238,7 +315,6 @@ void menu_slot_devices::handle() { if (menu_event->itemref == ITEMREF_RESET && menu_event->iptkey == IPT_UI_SELECT) { - mame_options::add_slot_options(machine().options()); machine().schedule_hard_reset(); } else if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT) @@ -246,7 +322,6 @@ void menu_slot_devices::handle() device_slot_interface *slot = (device_slot_interface *)menu_event->itemref; const char *val = (menu_event->iptkey == IPT_UI_LEFT) ? get_previous_slot(*slot) : get_next_slot(*slot); set_slot_device(*slot, val); - reset(reset_options::REMEMBER_REF); } else if (menu_event->iptkey == IPT_UI_SELECT) { diff --git a/src/frontend/mame/ui/slotopt.h b/src/frontend/mame/ui/slotopt.h index a3a08bb9590..eabec934c33 100644 --- a/src/frontend/mame/ui/slotopt.h +++ b/src/frontend/mame/ui/slotopt.h @@ -15,6 +15,7 @@ #include "ui/menu.h" +#include <unordered_map> namespace ui { class menu_slot_devices : public menu @@ -32,6 +33,12 @@ private: const char *get_next_slot(device_slot_interface &slot) const; const char *get_previous_slot(device_slot_interface &slot) const; void set_slot_device(device_slot_interface &slot, const char *val); + void record_current_options(); + bool try_refresh_current_options(); + + // variables + std::unique_ptr<machine_config> m_config; + std::unordered_map<std::string, std::string> m_slot_options; }; } // namespace ui diff --git a/src/frontend/mame/ui/sndmenu.cpp b/src/frontend/mame/ui/sndmenu.cpp index 0a0d1c019ed..f2304b529ea 100644 --- a/src/frontend/mame/ui/sndmenu.cpp +++ b/src/frontend/mame/ui/sndmenu.cpp @@ -45,23 +45,19 @@ menu_sound_options::menu_sound_options(mame_ui_manager &mui, render_container &c menu_sound_options::~menu_sound_options() { - std::string error_string; emu_options &moptions = machine().options(); if (strcmp(moptions.value(OSDOPTION_SOUND),m_sound ? OSDOPTVAL_AUTO : OSDOPTVAL_NONE)!=0) { - moptions.set_value(OSDOPTION_SOUND, m_sound ? OSDOPTVAL_AUTO : OSDOPTVAL_NONE, OPTION_PRIORITY_CMDLINE, error_string); - machine().options().mark_changed(OSDOPTION_SOUND); + moptions.set_value(OSDOPTION_SOUND, m_sound ? OSDOPTVAL_AUTO : OSDOPTVAL_NONE, OPTION_PRIORITY_CMDLINE); } if (moptions.int_value(OPTION_SAMPLERATE)!=m_sound_rate[m_cur_rates]) { - moptions.set_value(OPTION_SAMPLERATE, m_sound_rate[m_cur_rates], OPTION_PRIORITY_CMDLINE, error_string); - machine().options().mark_changed(OPTION_SAMPLERATE); + moptions.set_value(OPTION_SAMPLERATE, m_sound_rate[m_cur_rates], OPTION_PRIORITY_CMDLINE); } if (moptions.bool_value(OPTION_SAMPLES)!=m_samples) { - moptions.set_value(OPTION_SAMPLES, m_samples, OPTION_PRIORITY_CMDLINE, error_string); - machine().options().mark_changed(OPTION_SAMPLES); + moptions.set_value(OPTION_SAMPLES, m_samples, OPTION_PRIORITY_CMDLINE); } } diff --git a/src/frontend/mame/ui/submenu.cpp b/src/frontend/mame/ui/submenu.cpp index e28b0c58125..01d3d58027e 100644 --- a/src/frontend/mame/ui/submenu.cpp +++ b/src/frontend/mame/ui/submenu.cpp @@ -240,8 +240,7 @@ void submenu::handle() { case OPTION_BOOLEAN: changed = true; - sm_option.options->set_value(sm_option.name, !strcmp(sm_option.entry->value(),"1") ? "0" : "1", OPTION_PRIORITY_CMDLINE, error_string); - sm_option.entry->mark_changed(); + sm_option.options->set_value(sm_option.name, !strcmp(sm_option.entry->value(),"1") ? "0" : "1", OPTION_PRIORITY_CMDLINE); break; case OPTION_INTEGER: if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT) @@ -249,8 +248,7 @@ void submenu::handle() changed = true; int i_cur = atoi(sm_option.entry->value()); (menu_event->iptkey == IPT_UI_LEFT) ? i_cur-- : i_cur++; - sm_option.options->set_value(sm_option.name, i_cur, OPTION_PRIORITY_CMDLINE, error_string); - sm_option.entry->mark_changed(); + sm_option.options->set_value(sm_option.name, i_cur, OPTION_PRIORITY_CMDLINE); } break; case OPTION_FLOAT: @@ -260,17 +258,19 @@ void submenu::handle() f_cur = atof(sm_option.entry->value()); if (sm_option.entry->has_range()) { - f_step = atof(sm_option.entry->minimum()); + const char *minimum = sm_option.entry->minimum(); + const char *maximum = sm_option.entry->maximum(); + f_step = atof(minimum); if (f_step <= 0.0f) { - int pmin = getprecisionchr(sm_option.entry->minimum()); - int pmax = getprecisionchr(sm_option.entry->maximum()); + int pmin = getprecisionchr(minimum); + int pmax = getprecisionchr(maximum); tmptxt = '1' + std::string((pmin > pmax) ? pmin : pmax, '0'); f_step = 1 / atof(tmptxt.c_str()); } } else { - int precision = getprecisionchr(sm_option.entry->default_value()); + int precision = getprecisionchr(sm_option.entry->default_value().c_str()); tmptxt = '1' + std::string(precision, '0'); f_step = 1 / atof(tmptxt.c_str()); } @@ -279,8 +279,7 @@ void submenu::handle() else f_cur += f_step; tmptxt = string_format("%g", f_cur); - sm_option.options->set_value(sm_option.name, tmptxt.c_str(), OPTION_PRIORITY_CMDLINE, error_string); - sm_option.entry->mark_changed(); + sm_option.options->set_value(sm_option.name, tmptxt.c_str(), OPTION_PRIORITY_CMDLINE); } break; case OPTION_STRING: @@ -293,10 +292,11 @@ void submenu::handle() v_cur = sm_option.value[--cur_value]; else v_cur = sm_option.value[++cur_value]; - sm_option.options->set_value(sm_option.name, v_cur.c_str(), OPTION_PRIORITY_CMDLINE, error_string); - sm_option.entry->mark_changed(); + sm_option.options->set_value(sm_option.name, v_cur.c_str(), OPTION_PRIORITY_CMDLINE); } break; + default: + break; } break; default: @@ -391,7 +391,7 @@ void submenu::populate(float &customtop, float &custombottom) break; case OPTION_STRING: { - std::string const v_cur(sm_option->entry->value()); + std::string v_cur(sm_option->entry->value()); int const cur_value = std::distance(sm_option->value.begin(), std::find(sm_option->value.begin(), sm_option->value.end(), v_cur)); arrow_flags = get_arrow_flags(0, int(unsigned(sm_option->value.size() - 1)), cur_value); item_append(_(sm_option->description), diff --git a/src/frontend/mame/ui/submenu.h b/src/frontend/mame/ui/submenu.h index acaf28d90e4..f17b6fe53ff 100644 --- a/src/frontend/mame/ui/submenu.h +++ b/src/frontend/mame/ui/submenu.h @@ -48,7 +48,7 @@ public: option_type type; const char *description; const char *name; - core_options::entry *entry; + core_options::entry::shared_ptr entry; core_options *options; std::vector<std::string> value; }; diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp index 7ea8b4c71bb..f669321092f 100644 --- a/src/frontend/mame/ui/ui.cpp +++ b/src/frontend/mame/ui/ui.cpp @@ -2117,14 +2117,18 @@ void mame_ui_manager::popup_time_string(int seconds, std::string message) void mame_ui_manager::load_ui_options() { // parse the file - std::string error; // attempt to open the output file emu_file file(machine().options().ini_path(), OPEN_FLAG_READ); if (file.open("ui.ini") == osd_file::error::NONE) { - bool result = options().parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_MAME_INI < OPTION_PRIORITY_DRIVER_INI, error); - if (!result) + try + { + options().parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_MAME_INI < OPTION_PRIORITY_DRIVER_INI, true); + } + catch (options_exception &) + { osd_printf_error("**Error loading ui.ini**\n"); + } } } @@ -2155,28 +2159,37 @@ void mame_ui_manager::save_main_option() { // parse the file std::string error; - emu_options options(machine().options()); // This way we make sure that all OSD parts are in - std::string error_string; + emu_options options(emu_options::option_support::GENERAL_ONLY); // This way we make sure that all OSD parts are in + + options.copy_from(machine().options()); // attempt to open the main ini file { emu_file file(machine().options().ini_path(), OPEN_FLAG_READ); if (file.open(emulator_info::get_configname(), ".ini") == osd_file::error::NONE) { - bool result = options.parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_MAME_INI < OPTION_PRIORITY_DRIVER_INI, error); - if (!result) + try + { + options.parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_MAME_INI < OPTION_PRIORITY_DRIVER_INI, true); + } + catch(options_error_exception &) { osd_printf_error("**Error loading %s.ini**\n", emulator_info::get_configname()); return; } + catch (options_exception &) + { + // ignore other exceptions related to options + } } } - for (emu_options::entry &f_entry : machine().options()) + for (const auto &f_entry : machine().options().entries()) { - if (f_entry.is_changed()) + const char *value = f_entry->value(); + if (value && strcmp(value, options.value(f_entry->name().c_str()))) { - options.set_value(f_entry.name(), f_entry.value(), OPTION_PRIORITY_CMDLINE, error_string); + options.set_value(f_entry->name(), *f_entry->value(), OPTION_PRIORITY_CMDLINE); } } |