diff options
| author | 2017-02-22 07:16:23 -0500 | |
|---|---|---|
| committer | 2017-02-22 23:16:23 +1100 | |
| commit | 709c330a1f2f2deb095967f865d2c638b63cc497 (patch) | |
| tree | f502f6b638d1c538f16bac60026205810048ac2c /src | |
| parent | c2070315db52e43f66b91b385546f2b5885f4eea (diff) | |
Softlist cleanup (#2075)
* Eliminates the need for emu_options::update_cached_options() by providing a hook for when option values change
* This is a preliminary fix to the issue identified in PR#2065
* More softlist related refactoring:
- We now only parse the command line (with core_options::parse_command_line()) once
- Options that are set up during slot and image setup go through a 'value_specifier' function
- Eliminated the command line postprocessing
Diffstat (limited to 'src')
| -rw-r--r-- | src/emu/emuopts.cpp | 37 | ||||
| -rw-r--r-- | src/emu/emuopts.h | 7 | ||||
| -rw-r--r-- | src/frontend/mame/clifront.cpp | 59 | ||||
| -rw-r--r-- | src/frontend/mame/mameopts.cpp | 202 | ||||
| -rw-r--r-- | src/frontend/mame/mameopts.h | 11 | ||||
| -rw-r--r-- | src/lib/util/options.cpp | 40 | ||||
| -rw-r--r-- | src/lib/util/options.h | 4 |
7 files changed, 244 insertions, 116 deletions
diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp index d74d6278eb4..7551a682622 100644 --- a/src/emu/emuopts.cpp +++ b/src/emu/emuopts.cpp @@ -262,21 +262,34 @@ std::string emu_options::sub_value(const char *name, const char *subname) const //------------------------------------------------- -// update_cached_options - to prevent tagmap +// value_changed - to prevent tagmap // lookups keep copies of frequently requested // options in member variables. //------------------------------------------------- -void emu_options::update_cached_options() +void emu_options::value_changed(const std::string &name, const std::string &value) { - m_coin_impulse = int_value(OPTION_COIN_IMPULSE); - m_joystick_contradictory = bool_value(OPTION_JOYSTICK_CONTRADICTORY); - m_sleep = bool_value(OPTION_SLEEP); - m_refresh_speed = bool_value(OPTION_REFRESHSPEED); - - auto ui_option_string = value(OPTION_UI); - if (!strcmp(ui_option_string, "simple")) - m_ui = UI_SIMPLE; - else - m_ui = UI_CABINET; + if (name == OPTION_COIN_IMPULSE) + { + m_coin_impulse = int_value(OPTION_COIN_IMPULSE); + } + else if (name == OPTION_JOYSTICK_CONTRADICTORY) + { + m_joystick_contradictory = bool_value(OPTION_JOYSTICK_CONTRADICTORY); + } + else if (name == OPTION_SLEEP) + { + m_sleep = bool_value(OPTION_SLEEP); + } + else if (name == OPTION_REFRESHSPEED) + { + m_refresh_speed = bool_value(OPTION_REFRESHSPEED); + } + else if (name == OPTION_UI) + { + if (value == "simple") + m_ui = UI_SIMPLE; + else + m_ui = UI_CABINET; + } } diff --git a/src/emu/emuopts.h b/src/emu/emuopts.h index c1114748900..777894c878f 100644 --- a/src/emu/emuopts.h +++ b/src/emu/emuopts.h @@ -390,11 +390,12 @@ public: short http_port() const { return int_value(OPTION_HTTP_PORT); } const char *http_root() const { return value(OPTION_HTTP_ROOT); } - // cache frequently used options in members - void update_cached_options(); - std::string main_value(const char *option) const; std::string sub_value(const char *name, const char *subname) const; + +protected: + virtual void value_changed(const std::string &name, const std::string &value) override; + private: static const options_entry s_option_entries[]; diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp index c51e126cd3d..450a8384b0f 100644 --- a/src/frontend/mame/clifront.cpp +++ b/src/frontend/mame/clifront.cpp @@ -196,60 +196,6 @@ cli_frontend::~cli_frontend() void cli_frontend::start_execution(mame_machine_manager *manager,int argc, char **argv,std::string &option_errors) { - // load software specified at the command line (if any of course) - const std::string software_name = m_options.software_name(); - if (!software_name.empty()) - { - const game_driver *system = mame_options::system(m_options); - if (system == nullptr && *(m_options.system_name()) != 0) - throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "Unknown system '%s'", m_options.system_name()); - - // sanity check - lets fail quickly if this system doesn't have any softlists - machine_config config(*system, m_options); - software_list_device_iterator iter(config.root_device()); - if (iter.count() == 0) - throw emu_fatalerror(EMU_ERR_FATALERROR, "Error: unknown option: %s\n", software_name.c_str()); - - // 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) - { - 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) - { - device_image_interface *image = software_list_device::find_mountable_image(config, swpart); - if (image != nullptr) - { - std::string val = string_format("%s:%s:%s", swlistdev.list_name(), software_name, swpart.name()); - - // call this in order to set slot devices according to mounting - mame_options::parse_slot_devices(m_options, argc, argv, option_errors, image->instance_name(), val.c_str(), &swpart); - } - compatible = true; - } - } - found = true; - } - - 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(), m_options.system_name()); - } - } // parse the command line, adding any system-specific options if (!mame_options::parse_command_line(m_options, argc, argv, option_errors)) { @@ -306,11 +252,8 @@ int cli_frontend::execute(int argc, char **argv) try { - // first parse options to be able to get software from it std::string option_errors; - mame_options::parse_command_line(m_options,argc, argv, option_errors); - - mame_options::parse_standard_inis(m_options,option_errors); + mame_options::parse_standard_inis(m_options, option_errors); load_translation(m_options); diff --git a/src/frontend/mame/mameopts.cpp b/src/frontend/mame/mameopts.cpp index f31db021211..0f9a9584716 100644 --- a/src/frontend/mame/mameopts.cpp +++ b/src/frontend/mame/mameopts.cpp @@ -2,7 +2,7 @@ // copyright-holders:Aaron Giles /*************************************************************************** - mameopts.c + mameopts.cpp Options file and command line management. @@ -14,6 +14,7 @@ #include "softlist_dev.h" #include <ctype.h> +#include <stack> int mame_options::m_slot_options = 0; int mame_options::m_device_options = 0; @@ -23,7 +24,7 @@ int mame_options::m_device_options = 0; // options for the configured system //------------------------------------------------- -bool mame_options::add_slot_options(emu_options &options, const software_part *swpart) +bool mame_options::add_slot_options(emu_options &options, std::function<void(emu_options &options, const std::string &)> value_specifier) { // look up the system configured by name; if no match, do nothing const game_driver *cursystem = system(options); @@ -51,18 +52,11 @@ bool mame_options::add_slot_options(emu_options &options, const software_part *s // add the option options.add_entry(name, nullptr, OPTION_STRING | OPTION_FLAG_DEVICE, slot.default_option(), true); - } - // allow software lists to supply their own defaults - if (swpart != nullptr) - { - std::string featurename = std::string(name).append("_default"); - const char *value = swpart->feature(featurename); - if (value != nullptr && (*value == '\0' || slot.option(value) != nullptr)) + // allow opportunity to specify this value + if (value_specifier) { - // set priority above INIs but below actual command line - std::string error; - options.set_value(name, value, OPTION_PRIORITY_SUBCMD, error); + value_specifier(options, name); } } } @@ -108,7 +102,6 @@ void mame_options::update_slot_options(emu_options &options, const software_part options.set_flag(name, ~OPTION_FLAG_INTERNAL, (option != nullptr && !option->selectable()) ? OPTION_FLAG_INTERNAL : 0); } } - while (add_slot_options(options,swpart)) {} add_device_options(options); } @@ -118,7 +111,7 @@ void mame_options::update_slot_options(emu_options &options, const software_part // options for the configured system //------------------------------------------------- -void mame_options::add_device_options(emu_options &options) +void mame_options::add_device_options(emu_options &options, std::function<void(emu_options &options, const std::string &)> value_specifier) { // look up the system configured by name; if no match, do nothing const game_driver *cursystem = system(options); @@ -147,6 +140,10 @@ void mame_options::add_device_options(emu_options &options) // add the option options.add_entry(option_name.str().c_str(), nullptr, OPTION_STRING | OPTION_FLAG_DEVICE, nullptr, true); + + // allow opportunity to specify this value + if (value_specifier) + value_specifier(options, image.instance_name()); } } } @@ -184,33 +181,23 @@ void mame_options::remove_device_options(emu_options &options) // and update slot and image devices //------------------------------------------------- -bool mame_options::parse_slot_devices(emu_options &options, int argc, char *argv[], std::string &error_string, const char *name, const char *value, const software_part *swpart) +bool mame_options::parse_slot_devices(emu_options &options, std::function<void(emu_options &options, const std::string &)> value_specifier) { - // an initial parse to capture the initial set of values - bool result; - - options.parse_command_line(argc, argv, OPTION_PRIORITY_CMDLINE, error_string); - // keep adding slot options until we stop seeing new stuff - while (add_slot_options(options,swpart)) - options.parse_command_line(argc, argv, OPTION_PRIORITY_CMDLINE, error_string); + while (add_slot_options(options, value_specifier)) + { + } - // add device options and reparse - add_device_options(options); - if (name != nullptr && options.exists(name)) - options.set_value(name, value, OPTION_PRIORITY_SUBCMD, error_string); - options.parse_command_line(argc, argv, OPTION_PRIORITY_CMDLINE, error_string); + // add device options + add_device_options(options, value_specifier); int num; do { num = options.options_count(); - update_slot_options(options,swpart); - result = options.parse_command_line(argc, argv, OPTION_PRIORITY_CMDLINE, error_string); + update_slot_options(options); } while (num != options.options_count()); - options.update_cached_options(); - - return result; + return true; } @@ -221,11 +208,150 @@ bool mame_options::parse_slot_devices(emu_options &options, int argc, char *argv bool mame_options::parse_command_line(emu_options &options, int argc, char *argv[], std::string &error_string) { - // parse as normal + // parse the command line options.parse_command_line(argc, argv, OPTION_PRIORITY_CMDLINE, error_string); - bool result = parse_slot_devices(options,argc, argv, error_string); - options.update_cached_options(); - return result; + + // 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 = [&softlist_opts, argc, argv, &error_string](emu_options &options, const std::string &arg) + { + // first find within the command line + const char *arg_value = options.find_within_command_line(argc, argv, arg.c_str()); + + // next try to find within softlist-specified options + if (!arg_value) + { + auto iter = softlist_opts.find(arg); + if (iter != softlist_opts.end()) + arg_value = iter->second.c_str(); + } + + // did we find something? + if (arg_value) + options.set_value(arg.c_str(), arg_value, OPTION_PRIORITY_MAXIMUM, error_string); + }; + + return parse_slot_devices(options, value_specifier); +} + + +//------------------------------------------------- +// 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) + { + device_image_interface *image = software_list_device::find_mountable_image(config, swpart); + 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; } @@ -306,8 +432,6 @@ void mame_options::parse_standard_inis(emu_options &options, std::string &error_ // Re-evaluate slot options after loading ini files update_slot_options(options); - - options.update_cached_options(); } @@ -380,7 +504,7 @@ void mame_options::set_system_name(emu_options &options, const char *name) // then add the options if (new_system) { - while (add_slot_options(options,swpart)) {} + while (add_slot_options(options)) {} add_device_options(options); } diff --git a/src/frontend/mame/mameopts.h b/src/frontend/mame/mameopts.h index 0b47bfa3dad..1fbf14e78e6 100644 --- a/src/frontend/mame/mameopts.h +++ b/src/frontend/mame/mameopts.h @@ -56,24 +56,27 @@ public: // parsing wrappers static bool parse_command_line(emu_options &options, int argc, char *argv[], std::string &error_string); static void parse_standard_inis(emu_options &options, std::string &error_string, const game_driver *driver = nullptr); - static bool parse_slot_devices(emu_options &options, int argc, char *argv[], std::string &error_string, const char *name = nullptr, const char *value = nullptr, const software_part *swpart = nullptr); // FIXME: Couriersud: This should be in image_device_exit static void remove_device_options(emu_options &options); 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, const software_part *swpart = nullptr); + static bool add_slot_options(emu_options &options, std::function<void(emu_options &options, const std::string &)> value_specifier = nullptr); + private: // device-specific option handling - static void add_device_options(emu_options &options); + static void add_device_options(emu_options &options, std::function<void(emu_options &options, const std::string &)> value_specifier = nullptr); static void update_slot_options(emu_options &options, const software_part *swpart = nullptr); + static bool parse_slot_devices(emu_options &options, std::function<void(emu_options &options, const std::string &)> value_specifier); // 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); + static int m_slot_options; static int m_device_options; - }; #endif /* __MAMEOPTS_H__ */ diff --git a/src/lib/util/options.cpp b/src/lib/util/options.cpp index 7e40ab736de..b0b5439c129 100644 --- a/src/lib/util/options.cpp +++ b/src/lib/util/options.cpp @@ -277,6 +277,9 @@ void core_options::add_entry(const char *name, const char *description, uint32_t return; } } + + // need to call value_changed() with initial value + value_changed(newentry->name(), newentry->value()); } // add us to the list and maps @@ -462,6 +465,42 @@ bool core_options::parse_ini_file(util::core_file &inifile, int priority, int ig //------------------------------------------------- +// find_within_command_line - finds a specific +// value from within a command line +//------------------------------------------------- + +const char *core_options::find_within_command_line(int argc, char **argv, const char *optionname) +{ + // find this entry within the options (it is illegal to call this with a non-existant option + // so we assert if not present) + auto curentry = m_entrymap.find(optionname); + assert(curentry != m_entrymap.end()); + + // build a vector with potential targets + std::vector<std::string> targets; + const char *potential_target; + int index = 0; + while ((potential_target = curentry->second->name(index++)) != nullptr) + { + // not supporting unadorned options for now + targets.push_back(std::string("-") + potential_target); + } + + // find each of the targets in the argv array + for (int i = 1; i < argc - 1; i++) + { + auto const iter = std::find_if( + targets.begin(), + targets.end(), + [argv, i](const std::string &targ) { return targ == argv[i]; }); + if (iter != targets.end()) + return argv[i + 1]; + } + return nullptr; +} + + +//------------------------------------------------- // revert - revert options at or below a certain // priority back to their defaults //------------------------------------------------- @@ -835,6 +874,7 @@ bool core_options::validate_and_set_data(core_options::entry &curentry, const ch // set the data curentry.set_value(data.c_str(), priority); + value_changed(curentry.name(), data); return true; } diff --git a/src/lib/util/options.h b/src/lib/util/options.h index a05898f46fc..fc6ab9849eb 100644 --- a/src/lib/util/options.h +++ b/src/lib/util/options.h @@ -149,6 +149,7 @@ public: // parsing/input bool parse_command_line(int argc, char **argv, int priority, std::string &error_string); bool parse_ini_file(util::core_file &inifile, int priority, int ignore_priority, std::string &error_string); + const char *find_within_command_line(int argc, char **argv, const char *name); // reverting void revert(int priority_hi = OPTION_PRIORITY_MAXIMUM, int priority_lo = OPTION_PRIORITY_DEFAULT); @@ -179,6 +180,9 @@ public: static const char *unadorned(int x = 0) { return s_option_unadorned[std::min(x, MAX_UNADORNED_OPTIONS)]; } int options_count() const { return m_entrylist.count(); } +protected: + virtual void value_changed(const std::string &name, const std::string &value) {} + private: // internal helpers void reset(); |
