summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend
diff options
context:
space:
mode:
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
commitb193e05cd7c8456a2648d43854645da84f56ddbd (patch)
tree406d4dca91e403acdcea26379bcf65e567ca4834 /src/frontend
parent1b28df0b39225c3017e7bc843c14b58f548162ac (diff)
Overhaul to how MAME handles options, take two (#2341)
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/mame/clifront.cpp96
-rw-r--r--src/frontend/mame/clifront.h6
-rw-r--r--src/frontend/mame/info.cpp2
-rw-r--r--src/frontend/mame/luaengine.cpp23
-rw-r--r--src/frontend/mame/mame.cpp45
-rw-r--r--src/frontend/mame/mameopts.cpp685
-rw-r--r--src/frontend/mame/mameopts.h36
-rw-r--r--src/frontend/mame/pluginopts.cpp2
-rw-r--r--src/frontend/mame/ui/custui.cpp38
-rw-r--r--src/frontend/mame/ui/dirmenu.cpp15
-rw-r--r--src/frontend/mame/ui/info.cpp3
-rw-r--r--src/frontend/mame/ui/miscmenu.cpp28
-rw-r--r--src/frontend/mame/ui/selgame.cpp14
-rw-r--r--src/frontend/mame/ui/selsoft.cpp26
-rw-r--r--src/frontend/mame/ui/slotopt.cpp93
-rw-r--r--src/frontend/mame/ui/slotopt.h7
-rw-r--r--src/frontend/mame/ui/sndmenu.cpp10
-rw-r--r--src/frontend/mame/ui/submenu.cpp26
-rw-r--r--src/frontend/mame/ui/submenu.h2
-rw-r--r--src/frontend/mame/ui/ui.cpp33
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);
}
}