summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author npwoods <npwoods@alumni.carnegiemellon.edu>2017-02-22 07:16:23 -0500
committer Vas Crabb <cuavas@users.noreply.github.com>2017-02-22 23:16:23 +1100
commit709c330a1f2f2deb095967f865d2c638b63cc497 (patch)
treef502f6b638d1c538f16bac60026205810048ac2c /src
parentc2070315db52e43f66b91b385546f2b5885f4eea (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.cpp37
-rw-r--r--src/emu/emuopts.h7
-rw-r--r--src/frontend/mame/clifront.cpp59
-rw-r--r--src/frontend/mame/mameopts.cpp202
-rw-r--r--src/frontend/mame/mameopts.h11
-rw-r--r--src/lib/util/options.cpp40
-rw-r--r--src/lib/util/options.h4
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();