summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/devices/machine/ram.cpp4
-rw-r--r--src/emu/diimage.cpp11
-rw-r--r--src/emu/diimage.h6
-rw-r--r--src/emu/dislot.h1
-rw-r--r--src/emu/emuopts.cpp893
-rw-r--r--src/emu/emuopts.h139
-rw-r--r--src/emu/image.cpp31
-rw-r--r--src/emu/mconfig.cpp11
-rw-r--r--src/emu/natkeyboard.cpp4
-rw-r--r--src/emu/romload.cpp18
-rw-r--r--src/frontend/mame/clifront.cpp36
-rw-r--r--src/frontend/mame/info.cpp4
-rw-r--r--src/frontend/mame/luaengine.cpp22
-rw-r--r--src/frontend/mame/mame.cpp47
-rw-r--r--src/frontend/mame/mameopts.cpp612
-rw-r--r--src/frontend/mame/mameopts.h32
-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.cpp9
-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.cpp35
-rw-r--r--src/lib/util/options.cpp968
-rw-r--r--src/lib/util/options.h294
-rw-r--r--src/osd/modules/lib/osdobj_common.h2
-rw-r--r--src/osd/modules/render/drawbgfx.cpp1
-rw-r--r--src/osd/sdl/sdlmain.cpp10
-rw-r--r--src/osd/windows/winmain.cpp15
34 files changed, 1523 insertions, 1846 deletions
diff --git a/src/devices/machine/ram.cpp b/src/devices/machine/ram.cpp
index 1fb1be56043..49ff027ed0f 100644
--- a/src/devices/machine/ram.cpp
+++ b/src/devices/machine/ram.cpp
@@ -163,7 +163,9 @@ void ram_device::device_validity_check(validity_checker &valid) const
osd_printf_error("%s", output.str().c_str());
osd_printf_warning("Setting value to default %s\n",m_default_size);
- mconfig().options().set_value(OPTION_RAMSIZE, m_default_size, OPTION_PRIORITY_CMDLINE);
+ std::string error;
+ mconfig().options().set_value(OPTION_RAMSIZE, m_default_size, OPTION_PRIORITY_CMDLINE, error);
+ assert(error.empty());
}
}
diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp
index 009ea67e42b..1c256684821 100644
--- a/src/emu/diimage.cpp
+++ b/src/emu/diimage.cpp
@@ -1226,7 +1226,7 @@ void device_image_interface::reset_and_load(const std::string &path)
device().machine().schedule_hard_reset();
// and record the new load
- device().machine().options().image_option(instance_name()).specify(path);
+ device().machine().options().image_options()[instance_name()] = path;
}
@@ -1310,10 +1310,9 @@ void device_image_interface::update_names()
if (brief_name == nullptr)
brief_name = device_brieftypename(image_type());
- m_cannonical_instance_name = string_format("%s%d", inst_name, index + 1);
if (count > 1)
{
- m_instance_name = m_cannonical_instance_name;
+ m_instance_name = string_format("%s%d", inst_name, index + 1);
m_brief_instance_name = string_format("%s%d", brief_name, index + 1);
}
else
@@ -1464,11 +1463,11 @@ std::string device_image_interface::software_get_default_slot(const char *defaul
{
std::string result;
- const std::string &image_name(device().mconfig().options().image_option(instance_name()).value());
- if (!image_name.empty())
+ auto iter = device().mconfig().options().image_options().find(instance_name());
+ if (iter != device().mconfig().options().image_options().end() && !iter->second.empty())
{
result.assign(default_card_slot);
- const software_part *swpart = find_software_item(image_name, true);
+ const software_part *swpart = find_software_item(iter->second, true);
if (swpart != nullptr)
{
const char *slot = swpart->feature("slot");
diff --git a/src/emu/diimage.h b/src/emu/diimage.h
index e6fa3ea69e3..bf656b6a040 100644
--- a/src/emu/diimage.h
+++ b/src/emu/diimage.h
@@ -225,7 +225,6 @@ public:
const std::string &instance_name() const { return m_instance_name; }
const std::string &brief_instance_name() const { return m_brief_instance_name; }
- const std::string &cannonical_instance_name() const { return m_cannonical_instance_name; }
bool uses_file_extension(const char *file_extension) const;
const formatlist_type &formatlist() const { return m_formatlist; }
@@ -342,9 +341,8 @@ private:
util::hash_collection m_hash;
- std::string m_instance_name; // e.g. - "cartridge", "floppydisk2"
- std::string m_brief_instance_name; // e.g. - "cart", "flop2"
- std::string m_cannonical_instance_name; // e.g. - "cartridge1", "floppydisk2" - only used internally in emuopts.cpp
+ std::string m_brief_instance_name;
+ std::string m_instance_name;
// in the case of arcade cabinet with fixed carts inserted,
// we want to disable command line cart loading...
diff --git a/src/emu/dislot.h b/src/emu/dislot.h
index 8f36d70386c..a6722a50f70 100644
--- a/src/emu/dislot.h
+++ b/src/emu/dislot.h
@@ -145,7 +145,6 @@ public:
virtual std::string get_default_card_software(get_default_card_software_hook &hook) const { return std::string(); }
device_t *get_card_device() { return m_card_device; }
void set_card_device(device_t *dev) { m_card_device = dev; }
- const char *slot_name() const { return device().tag() + 1; }
private:
// internal state
diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp
index 823fb2e071f..2863ef35caf 100644
--- a/src/emu/emuopts.cpp
+++ b/src/emu/emuopts.cpp
@@ -10,11 +10,6 @@
#include "emu.h"
#include "emuopts.h"
-#include "drivenum.h"
-#include "softlist_dev.h"
-#include "hashfile.h"
-
-#include <stack>
//**************************************************************************
@@ -218,167 +213,6 @@ const options_entry emu_options::s_option_entries[] =
//**************************************************************************
-// CUSTOM OPTION ENTRIES AND SUPPORT CLASSES
-//**************************************************************************
-
-namespace
-{
- // custom option entry for the system name
- class system_name_option_entry : public core_options::entry
- {
- public:
- system_name_option_entry(emu_options &host)
- : entry(OPTION_SYSTEMNAME)
- , m_host(host)
- {
- }
-
- virtual const char *value() const override
- {
- return m_host.system() ? m_host.system()->name : "";
- }
-
- protected:
- virtual void internal_set_value(std::string &&newvalue) override
- {
- m_host.set_system_name(newvalue);
- }
-
- private:
- emu_options &m_host;
- };
-
- // custom option entry for the software name
- class software_name_option_entry : public core_options::entry
- {
- public:
- software_name_option_entry(emu_options &host)
- : entry(OPTION_SOFTWARENAME)
- , m_host(host)
- {
- }
-
- protected:
- virtual void internal_set_value(std::string &&newvalue) override
- {
- m_host.set_software(newvalue);
- }
-
- private:
- emu_options &m_host;
- };
-
- // custom option entry for slots
- class slot_option_entry : public core_options::entry
- {
- public:
- slot_option_entry(const char *name, slot_option &host)
- : entry(name)
- , m_host(host)
- {
- }
-
- virtual const char *value() const override
- {
- const char *result = nullptr;
- if (m_host.specified())
- {
- m_temp = m_host.specified_value();
- result = m_temp.c_str();
- }
- return result;
- }
-
- protected:
- virtual void internal_set_value(std::string &&newvalue) override
- {
- m_host.specify(std::move(newvalue));
- }
-
- private:
- slot_option & m_host;
- mutable std::string m_temp;
- };
-
- // custom option entry for images
- class image_option_entry : public core_options::entry
- {
- public:
- image_option_entry(std::vector<std::string> &&names, image_option &host)
- : entry(std::move(names))
- , m_host(host)
- {
- }
-
- virtual const char *value() const override
- {
- return m_host.value().c_str();
- }
-
- protected:
- virtual void internal_set_value(std::string &&newvalue) override
- {
- m_host.specify(std::move(newvalue));
- }
-
- private:
- image_option &m_host;
- };
-
- // existing option tracker class; used by slot/image calculus to identify existing
- // options for later purging
- template<typename T>
- class existing_option_tracker
- {
- public:
- existing_option_tracker(const std::unordered_map<std::string, T> &map)
- {
- m_vec.reserve(map.size());
- for (const auto &entry : map)
- m_vec.push_back(&entry.first);
- }
-
- template<typename TStr>
- void remove(TStr str)
- {
- auto iter = std::find_if(
- m_vec.begin(),
- m_vec.end(),
- [&str](const auto &x) { return *x == str; });
- if (iter != m_vec.end())
- m_vec.erase(iter);
- }
-
- std::vector<const std::string *>::iterator begin() { return m_vec.begin(); }
- std::vector<const std::string *>::iterator end() { return m_vec.end(); }
-
- private:
- std::vector<const std::string *> m_vec;
- };
-
-
- //-------------------------------------------------
- // get_full_option_names
- //-------------------------------------------------
-
- std::vector<std::string> get_full_option_names(const device_image_interface &image)
- {
- std::vector<std::string> result;
-
- result.push_back(image.instance_name());
- result.push_back(image.brief_instance_name());
-
- if (strcmp(image.device_typename(image.image_type()), image.instance_name().c_str()) == 0)
- {
- result.push_back(image.instance_name() + "1");
- result.push_back(image.brief_instance_name() + "1");
- }
- return result;
- }
-}
-
-
-//**************************************************************************
// EMU OPTIONS
//**************************************************************************
@@ -386,611 +220,125 @@ namespace
// emu_options - constructor
//-------------------------------------------------
-emu_options::emu_options(bool general_only)
- : m_system(nullptr)
- , m_coin_impulse(0)
- , m_joystick_contradictory(false)
- , m_sleep(true)
- , m_refresh_speed(false)
- , m_ui(UI_CABINET)
+emu_options::emu_options()
+: core_options()
+, m_coin_impulse(0)
+, m_joystick_contradictory(false)
+, m_sleep(true)
+, m_refresh_speed(false)
+, m_ui(UI_CABINET)
{
- // add entries
- if (!general_only)
- {
- add_entry(std::make_shared<system_name_option_entry>(*this));
- add_entry(std::make_shared<software_name_option_entry>(*this));
- }
add_entries(emu_options::s_option_entries);
-
- // adding handlers to keep copies of frequently requested options in member variables
- set_value_changed_handler(OPTION_COIN_IMPULSE, [this](const char *value) { m_coin_impulse = int_value(OPTION_COIN_IMPULSE); });
- set_value_changed_handler(OPTION_JOYSTICK_CONTRADICTORY, [this](const char *value) { m_joystick_contradictory = bool_value(OPTION_JOYSTICK_CONTRADICTORY); });
- set_value_changed_handler(OPTION_SLEEP, [this](const char *value) { m_sleep = bool_value(OPTION_SLEEP); });
- set_value_changed_handler(OPTION_REFRESHSPEED, [this](const char *value) { m_sleep = bool_value(OPTION_REFRESHSPEED); });
- set_value_changed_handler(OPTION_UI, [this](const std::string &value)
- {
- if (value == "simple")
- m_ui = UI_SIMPLE;
- else
- m_ui = UI_CABINET;
- });
-}
-
-
-//-------------------------------------------------
-// emu_options - destructor
-//-------------------------------------------------
-
-emu_options::~emu_options()
-{
}
//-------------------------------------------------
-// system_name
+// value_changed - to prevent tagmap
+// lookups keep copies of frequently requested
+// options in member variables.
//-------------------------------------------------
-const char *emu_options::system_name() const
+void emu_options::value_changed(const std::string &name, const std::string &value)
{
- return m_system ? m_system->name : "";
-}
-
-
-//-------------------------------------------------
-// set_system_name - called to set the system
-// name; will adjust slot/image options as appropriate
-//-------------------------------------------------
-
-void emu_options::set_system_name(const std::string &new_system_name)
-{
- const game_driver *new_system = nullptr;
-
- // was a system name specified?
- if (!new_system_name.empty())
+ if (name == OPTION_COIN_IMPULSE)
{
- // if so, first extract the base name (the reason for this is drag-and-drop on Windows; a side
- // effect is a command line like 'mame pacman.foo' will work correctly, but so be it)
- std::string new_system_base_name = core_filename_extract_base(new_system_name, true);
-
- // perform the lookup (and error if it cannot be found)
- int index = driver_list::find(new_system_base_name.c_str());
- if (index < 0)
- throw options_error_exception("Unknown system '%s'", new_system_name);
- new_system = &driver_list::driver(index);
+ m_coin_impulse = int_value(OPTION_COIN_IMPULSE);
}
-
- // did we change anything?
- if (new_system != m_system)
+ else if (name == OPTION_JOYSTICK_CONTRADICTORY)
{
- // if so, specify the new system and update
- m_system = new_system;
- update_slot_and_image_options();
+ m_joystick_contradictory = bool_value(OPTION_JOYSTICK_CONTRADICTORY);
}
-}
-
-
-//-------------------------------------------------
-// update_slot_and_image_options
-//-------------------------------------------------
-
-void emu_options::update_slot_and_image_options()
-{
- bool changed;
- do
+ else if (name == OPTION_SLEEP)
{
- changed = false;
-
- // first we add and remove slot options depending on what has been configured in the
- // device, bringing m_slot_options up to a state where it matches machine_config
- if (add_and_remove_slot_options())
- changed = true;
-
- // second, we perform an analgous operation with m_image_options
- if (add_and_remove_image_options())
- changed = true;
-
- // if we changed anything, we should reevaluate existing options
- if (changed)
- reevaluate_default_card_software();
- } while (changed);
-}
-
-
-//-------------------------------------------------
-// add_and_remove_slot_options - add any missing
-// and/or purge extraneous slot options
-//-------------------------------------------------
-
-bool emu_options::add_and_remove_slot_options()
-{
- bool changed = false;
-
- // first, create a list of existing slot options; this is so we can purge
- // any stray slot options that are no longer pertinent when we're done
- existing_option_tracker<::slot_option> existing(m_slot_options);
-
- // it is perfectly legal for this to be called without a system; we
- // need to check for that condition!
- if (m_system)
- {
- // create the configuration
- machine_config config(*m_system, *this);
-
- for (const device_slot_interface &slot : slot_interface_iterator(config.root_device()))
- {
- // come up with the cannonical name of the slot
- const char *slot_option_name = slot.slot_name();
-
- // erase this option from existing (so we don't purge it later)
- existing.remove(slot_option_name);
-
- // do we need to add this option?
- if (!has_slot_option(slot_option_name))
- {
- // we do - add it to m_slot_options
- auto pair = std::make_pair(slot_option_name, ::slot_option(*this, slot.default_option()));
- ::slot_option &new_option(m_slot_options.emplace(std::move(pair)).first->second);
- changed = true;
-
- // for non-fixed slots, this slot needs representation in the options collection
- if (!slot.fixed())
- {
- // first device? add the header as to be pretty
- const char *header = "SLOT DEVICES";
- if (!header_exists(header))
- add_header(header);
-
- // create a new entry in the options
- auto new_entry = new_option.setup_option_entry(slot_option_name);
-
- // and add it
- add_entry(std::move(new_entry), header);
- }
- }
-
- }
+ m_sleep = bool_value(OPTION_SLEEP);
}
-
- // at this point we need to purge stray slot options that may no longer be pertinent
- for (auto &opt_name : existing)
- {
- auto iter = m_slot_options.find(*opt_name);
- assert(iter != m_slot_options.end());
-
- // if this is represented in core_options, remove it
- if (iter->second.option_entry())
- remove_entry(*iter->second.option_entry());
-
- // remove this option
- m_slot_options.erase(iter);
- changed = true;
- }
-
- return changed;
-}
-
-
-//-------------------------------------------------
-// add_and_remove_slot_options - add any missing
-// and/or purge extraneous slot options
-//-------------------------------------------------
-
-bool emu_options::add_and_remove_image_options()
-{
- // The logic for image options is superficially similar to the logic for slot options, but
- // there is one larger piece of complexity. The image instance names (returned by the
- // image_instance() call and surfaced in the UI) may change simply because we've added more
- // devices. This is because the instance_name() for a singular cartridge device might be
- // "cartridge" starting out, but become "cartridge1" when another cartridge device is added.
- //
- // To get around this behavior, our internal data structures work in terms of what is
- // returned by cannonical_instance_name(), which will be something like "cartridge1" both
- // for a singular cartridge device and the first cartridge in a multi cartridge system.
- //
- // The need for this behavior was identified by Tafoid when the following command line
- // regressed:
- //
- // mame snes bsxsore -cart2 bszelda
- //
- // Before we were accounting for this behavior, 'bsxsore' got stored in "cartridge" and
- // the association got lost when the second cartridge was added.
-
- bool changed = false;
-
- // first, create a list of existing image options; this is so we can purge
- // any stray slot options that are no longer pertinent when we're done; we
- // have to do this for both "flavors" of name
- existing_option_tracker<::image_option> existing(m_image_options_cannonical);
-
- // wipe the non-cannonical image options; we're going to rebuild it
- m_image_options.clear();
-
- // it is perfectly legal for this to be called without a system; we
- // need to check for that condition!
- if (m_system)
+ else if (name == OPTION_REFRESHSPEED)
{
- // create the configuration
- machine_config config(*m_system, *this);
-
- // iterate through all image devices
- for (device_image_interface &image : image_interface_iterator(config.root_device()))
- {
- const std::string &cannonical_name(image.cannonical_instance_name());
-
- // erase this option from existing (so we don't purge it later)
- existing.remove(cannonical_name);
-
- // do we need to add this option?
- auto iter = m_image_options_cannonical.find(cannonical_name);
- ::image_option *this_option = iter != m_image_options_cannonical.end() ? &iter->second : nullptr;
- if (!this_option)
- {
- // we do - add it to both m_image_options_cannonical and m_image_options
- auto pair = std::make_pair(cannonical_name, ::image_option(*this, image.cannonical_instance_name()));
- this_option = &m_image_options_cannonical.emplace(std::move(pair)).first->second;
- changed = true;
-
- // if this image is user loadable, we have to surface it in the core_options
- if (image.user_loadable())
- {
- // first device? add the header as to be pretty
- const char *header = "IMAGE DEVICES";
- if (!header_exists(header))
- add_header(header);
-
- // name this options
- auto names = get_full_option_names(image);
-
- // create a new entry in the options
- auto new_entry = this_option->setup_option_entry(std::move(names));
-
- // and add it
- add_entry(std::move(new_entry), header);
- }
- }
-
- // whether we added it or we didn't, we have to add it to the m_image_option map
- m_image_options[image.instance_name()] = this_option;
- }
+ m_refresh_speed = bool_value(OPTION_REFRESHSPEED);
}
-
- // at this point we need to purge stray image options that may no longer be pertinent
- for (auto &opt_name : existing)
+ else if (name == OPTION_UI)
{
- auto iter = m_image_options_cannonical.find(*opt_name);
- assert(iter != m_image_options_cannonical.end());
-
- // if this is represented in core_options, remove it
- if (iter->second.option_entry())
- remove_entry(*iter->second.option_entry());
-
- // remove this option
- m_image_options_cannonical.erase(iter);
- changed = true;
+ if (value == "simple")
+ m_ui = UI_SIMPLE;
+ else
+ m_ui = UI_CABINET;
}
-
- return changed;
}
//-------------------------------------------------
-// reevaluate_default_card_software - based on recent
-// changes in what images are mounted, give drivers
-// a chance to specify new default slot options
+// override_get_value - when saving to an INI, we
+// need to hook into that process so we can write
+// out image/slot options
//-------------------------------------------------
-void emu_options::reevaluate_default_card_software()
+core_options::override_get_value_result emu_options::override_get_value(const char *name, std::string &value) const
{
- if (m_system)
+ if (name)
{
- bool found;
- do
+ auto slotiter = m_slot_options.find(name);
+ if (slotiter != m_slot_options.end())
{
- // set up the machine_config
- machine_config config(*m_system, *this);
- found = false;
-
- // iterate through all slot devices
- for (device_slot_interface &slot : slot_interface_iterator(config.root_device()))
- {
- // retrieve info about the device instance
- auto &slot_opt(slot_option(slot.slot_name()));
-
- // 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);
- if (slot_opt.default_card_software() != default_card_software)
- {
- slot_opt.set_default_card_software(std::move(default_card_software));
-
- // calling set_default_card_software() can cause a cascade of slot/image
- // evaluations; we need to bail out of this loop because the iterator
- // may be bad
- found = true;
- break;
- }
- }
- } while (found);
- }
-}
-
-
-//-------------------------------------------------
-// get_default_card_software
-//-------------------------------------------------
-
-std::string emu_options::get_default_card_software(device_slot_interface &slot)
-{
- 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)
- {
- image_path = image_option(image->instance_name()).value();
+ value = slotiter->second.specified_value();
+ return slotiter->second.specified()
+ ? override_get_value_result::OVERRIDE
+ : override_get_value_result::SKIP;
+ }
- get_hashfile_extrainfo = [image, this](util::core_file &file, std::string &extrainfo)
+ auto imageiter = m_image_options.find(name);
+ if (imageiter != m_image_options.end())
{
- util::hash_collection hashes = image->calculate_hash_on_file(file);
-
- return hashfile_extrainfo(
- hash_path(),
- image->device().mconfig().gamedrv(),
- hashes,
- extrainfo);
- };
+ value = imageiter->second;
+ return override_get_value_result::OVERRIDE;
+ }
}
- // 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);
+ return override_get_value_result::NONE;
}
//-------------------------------------------------
-// set_software - called to load "unqualified"
-// software out of a software list (e.g. - "mame nes 'zelda'")
+// override_set_value - when parsing an INI, we
+// need to hook into into it so we can do the same
+// crazy slot logic done in mameopt
//-------------------------------------------------
-void emu_options::set_software(const std::string &new_software)
+bool emu_options::override_set_value(const char *name, const std::string &value)
{
- // identify any options as a result of softlists
- software_options softlist_opts = evaluate_initial_softlist_options(new_software);
-
- while (!softlist_opts.slot.empty() || !softlist_opts.image.empty())
+ auto slotiter = m_slot_options.find(name);
+ if (slotiter != m_slot_options.end())
{
- // track how many options we have
- size_t before_size = softlist_opts.slot.size() + softlist_opts.image.size();
-
- // keep a list of deferred options, in case anything is applied
- // out of order
- software_options deferred_opts;
-
- // distribute slot options
- for (auto &slot_opt : softlist_opts.slot)
- {
- auto iter = m_slot_options.find(slot_opt.first);
- if (iter != m_slot_options.end())
- iter->second.specify(std::move(slot_opt.second));
- else
- deferred_opts.slot[slot_opt.first] = std::move(slot_opt.second);
- }
-
- // distribute image options
- for (auto &image_opt : softlist_opts.image)
- {
- auto iter = m_image_options.find(image_opt.first);
- if (iter != m_image_options.end())
- iter->second->specify(std::move(image_opt.second));
- else
- deferred_opts.image[image_opt.first] = std::move(image_opt.second);
- }
-
- // keep any deferred options for the next round
- softlist_opts = std::move(deferred_opts);
-
- // do we have any pending options after failing to distribute any?
- size_t after_size = softlist_opts.slot.size() + softlist_opts.image.size();
- if ((after_size > 0) && after_size >= before_size)
- throw options_error_exception("Could not assign software option");
+ slotiter->second.specify(std::string(value));
+ return true;
}
-}
-
-
-//-------------------------------------------------
-// evaluate_initial_softlist_options
-//-------------------------------------------------
-
-emu_options::software_options emu_options::evaluate_initial_softlist_options(const std::string &software_identifier)
-{
- software_options results;
- // load software specified at the command line (if any of course)
- if (!software_identifier.empty())
+ auto imageiter = m_image_options.find(name);
+ if (imageiter != m_image_options.end())
{
- // we have software; first identify the proper game_driver
- if (!m_system)
- throw options_error_exception("Cannot specify software without specifying system");
-
- // and set up a configuration
- machine_config config(*m_system, *this);
- software_list_device_iterator iter(config.root_device());
- if (iter.count() == 0)
- throw emu_fatalerror(EMU_ERR_FATALERROR, "Error: unknown option: %s\n", software_identifier.c_str());
-
- // 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
- std::string current_software_identifier = std::move(software_identifier_stack.top());
- software_identifier_stack.pop();
-
- // and parse it
- std::string list_name, software_name;
- auto colon_pos = current_software_identifier.find_first_of(':');
- if (colon_pos != std::string::npos)
- {
- list_name = current_software_identifier.substr(0, colon_pos);
- software_name = current_software_identifier.substr(colon_pos + 1);
- }
- else
- {
- software_name = current_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.image.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[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[slot_name] = fi.value();
- }
- }
- }
- }
- if (compatible)
- break;
- }
-
- if (!compatible)
- {
- software_list_device::display_matches(config, nullptr, software_name);
- if (!found)
- throw options_error_exception("");
- else
- throw options_error_exception("Software '%s' is incompatible with system '%s'\n", software_name, m_system->name);
- }
- }
+ // We've found a potential image slot for this value. However, we're only going to specify it
+ // if the current image option is empty. This is because if there is an image option already
+ // present, it is almost certain that this was because something was specified at the command
+ // line and we're parsing an INI. Because INIs have less priority than the command line, this
+ // should be ignored
+ //
+ // Obviously, this ignores that INIs themselves have their own prioritization, so this should be
+ // considered to be a hack. Instead of having image options being just a straight map of std::string
+ // it should really be a structure where the priority can be recorded
+ if (imageiter->second.empty())
+ imageiter->second = value;
+ return true;
}
- return results;
-}
-
-
-//-------------------------------------------------
-// slot_option
-//-------------------------------------------------
-
-const slot_option &emu_options::slot_option(const std::string &device_name) const
-{
- auto iter = m_slot_options.find(device_name);
- assert(iter != m_slot_options.end() && "Attempt to access non-existent slot option");
- return iter->second;
-}
-
-slot_option &emu_options::slot_option(const std::string &device_name)
-{
- auto iter = m_slot_options.find(device_name);
- assert(iter != m_slot_options.end() && "Attempt to access non-existent slot option");
- return iter->second;
-}
-
-
-//-------------------------------------------------
-// has_slot_option
-//-------------------------------------------------
-bool emu_options::has_slot_option(const std::string &device_name) const
-{
- return m_slot_options.find(device_name) != m_slot_options.end();
+ return false;
}
//-------------------------------------------------
-// image_option
-//-------------------------------------------------
-
-const image_option &emu_options::image_option(const std::string &device_name) const
-{
- auto iter = m_image_options.find(device_name);
- assert(iter != m_image_options.end() && "Attempt to access non-existent image option");
- return *iter->second;
-}
-
-image_option &emu_options::image_option(const std::string &device_name)
-{
- auto iter = m_image_options.find(device_name);
- assert(iter != m_image_options.end() && "Attempt to access non-existent image option");
- return *iter->second;
-}
-
-
-//**************************************************************************
-// SLOT OPTIONS
-//**************************************************************************
-
-//-------------------------------------------------
// slot_option ctor
//-------------------------------------------------
-slot_option::slot_option(emu_options &host, const char *default_value)
- : m_host(host)
- , m_specified(false)
+slot_option::slot_option(const char *default_value)
+ : m_specified(false)
, m_default_value(default_value ? default_value : "")
{
}
@@ -1048,12 +396,10 @@ std::string slot_option::specified_value() const
void slot_option::specify(std::string &&text)
{
- // record the old value; we may need to trigger an update
- const std::string old_value = value();
-
// we need to do some elementary parsing here
const char *bios_arg = ",bios=";
- const size_t pos = text.find(bios_arg);
+
+ size_t pos = text.find(bios_arg);
if (pos != std::string::npos)
{
m_specified = true;
@@ -1066,37 +412,6 @@ void slot_option::specify(std::string &&text)
m_specified_value = std::move(text);
m_specified_bios = "";
}
-
- // we may have changed
- possibly_changed(old_value);
-}
-
-
-//-------------------------------------------------
-// slot_option::set_default_card_software
-//-------------------------------------------------
-
-void slot_option::set_default_card_software(std::string &&s)
-{
- // record the old value; we may need to trigger an update
- const std::string old_value = value();
-
- // update the default card software
- m_default_card_software = std::move(s);
-
- // we may have changed
- possibly_changed(old_value);
-}
-
-
-//-------------------------------------------------
-// slot_option::possibly_changed
-//-------------------------------------------------
-
-void slot_option::possibly_changed(const std::string &old_value)
-{
- if (value() != old_value)
- m_host.update_slot_and_image_options();
}
@@ -1113,73 +428,3 @@ void slot_option::set_bios(std::string &&text)
}
m_specified_bios = std::move(text);
}
-
-
-//-------------------------------------------------
-// slot_option::setup_option_entry
-//-------------------------------------------------
-
-core_options::entry::shared_ptr slot_option::setup_option_entry(const char *name)
-{
- // this should only be called once
- assert(m_entry.expired());
-
- // create the entry and return it
- core_options::entry::shared_ptr entry = std::make_shared<slot_option_entry>(name, *this);
- m_entry = entry;
- return entry;
-}
-
-
-//**************************************************************************
-// IMAGE OPTIONS
-//**************************************************************************
-
-//-------------------------------------------------
-// image_option ctor
-//-------------------------------------------------
-
-image_option::image_option(emu_options &host, const std::string &cannonical_instance_name)
- : m_host(host)
- , m_cannonical_instance_name(cannonical_instance_name)
-{
-}
-
-
-//-------------------------------------------------
-// image_option::specify
-//-------------------------------------------------
-
-void image_option::specify(const std::string &value)
-{
- if (value != m_value)
- {
- m_value = value;
- m_host.reevaluate_default_card_software();
- }
-}
-
-void image_option::specify(std::string &&value)
-{
- if (value != m_value)
- {
- m_value = std::move(value);
- m_host.reevaluate_default_card_software();
- }
-}
-
-
-//-------------------------------------------------
-// image_option::setup_option_entry
-//-------------------------------------------------
-
-core_options::entry::shared_ptr image_option::setup_option_entry(std::vector<std::string> &&names)
-{
- // this should only be called once
- assert(m_entry.expired());
-
- // create the entry and return it
- core_options::entry::shared_ptr entry = std::make_shared<image_option_entry>(std::move(names), *this);
- m_entry = entry;
- return entry;
-}
diff --git a/src/emu/emuopts.h b/src/emu/emuopts.h
index 44c636182ec..e592d04d6e3 100644
--- a/src/emu/emuopts.h
+++ b/src/emu/emuopts.h
@@ -195,77 +195,56 @@
// TYPE DEFINITIONS
//**************************************************************************
-struct game_driver;
-class device_slot_interface;
-class emu_options;
-
class slot_option
{
public:
- slot_option(emu_options &host, const char *default_value);
- slot_option(const slot_option &that) = delete;
+ slot_option(const char *default_value = nullptr);
+ slot_option(const slot_option &that) = default;
slot_option(slot_option &&that) = default;
+ const slot_option &operator=(const slot_option &that)
+ {
+ m_specified = that.m_specified;
+ m_specified_value = that.m_specified_value;
+ m_specified_bios = that.m_specified_bios;
+ m_default_card_software = that.m_default_card_software;
+ m_default_value = that.m_default_value;
+ return *this;
+ }
+
+ const slot_option &operator=(slot_option &&that)
+ {
+ m_specified = that.m_specified;
+ m_specified_value = std::move(that.m_specified_value);
+ m_specified_bios = std::move(that.m_specified_bios);
+ m_default_card_software = std::move(that.m_default_card_software);
+ m_default_value = std::move(that.m_default_value);
+ return *this;
+ }
+
// accessors
const std::string &value() const;
std::string specified_value() const;
const std::string &bios() const { return m_specified_bios; }
const std::string &default_card_software() const { return m_default_card_software; }
bool specified() const { return m_specified; }
- core_options::entry::shared_ptr option_entry() const { return m_entry.lock(); }
// seters
void specify(std::string &&text);
void set_bios(std::string &&text);
- void set_default_card_software(std::string &&s);
-
- // instantiates an option entry (don't call outside of emuopts.cpp)
- core_options::entry::shared_ptr setup_option_entry(const char *name);
+ void set_default_card_software(std::string &&s) { m_default_card_software = std::move(s); }
private:
- void possibly_changed(const std::string &old_value);
-
- emu_options & m_host;
- bool m_specified;
- std::string m_specified_value;
- std::string m_specified_bios;
- std::string m_default_card_software;
- std::string m_default_value;
- core_options::entry::weak_ptr m_entry;
-};
-
-
-class image_option
-{
-public:
- image_option(emu_options &host, const std::string &cannonical_instance_name);
- image_option(const image_option &that) = delete;
- image_option(image_option &&that) = default;
-
- // accessors
- const std::string &cannonical_instance_name() const { return m_cannonical_instance_name; }
- const std::string &value() const { return m_value; }
- core_options::entry::shared_ptr option_entry() const { return m_entry.lock(); }
-
- // mutators
- void specify(const std::string &value);
- void specify(std::string &&value);
-
- // instantiates an option entry (don't call outside of emuopts.cpp)
- core_options::entry::shared_ptr setup_option_entry(std::vector<std::string> &&names);
-
-private:
- emu_options & m_host;
- std::string m_cannonical_instance_name;
- std::string m_value;
- core_options::entry::weak_ptr m_entry;
+ bool m_specified;
+ std::string m_specified_value;
+ std::string m_specified_bios;
+ std::string m_default_card_software;
+ std::string m_default_value;
};
class emu_options : public core_options
{
- friend class slot_option;
- friend class image_option;
public:
enum ui_option
{
@@ -274,16 +253,11 @@ public:
};
// construction/destruction
- emu_options(bool general_only = false);
- ~emu_options();
-
- // mutation
- void set_system_name(const std::string &new_system_name);
- void set_software(const std::string &new_software);
+ emu_options();
// core options
- const game_driver *system() const { return m_system; }
- const char *system_name() const;
+ const char *system_name() const { return value(OPTION_SYSTEMNAME); }
+ const char *software_name() const { return value(OPTION_SOFTWARENAME); }
// core configuration options
bool read_config() const { return bool_value(OPTION_READCONFIG); }
@@ -453,51 +427,36 @@ public:
const char *language() const { return value(OPTION_LANGUAGE); }
- // Web server specific options
+ // Web server specific optopns
bool http() const { return bool_value(OPTION_HTTP); }
short http_port() const { return int_value(OPTION_HTTP_PORT); }
const char *http_root() const { return value(OPTION_HTTP_ROOT); }
// slots and devices - the values for these are stored outside of the core_options
// structure
- const ::slot_option &slot_option(const std::string &device_name) const;
- ::slot_option &slot_option(const std::string &device_name);
- bool has_slot_option(const std::string &device_name) const;
- const ::image_option &image_option(const std::string &device_name) const;
- ::image_option &image_option(const std::string &device_name);
+ std::map<std::string, slot_option> &slot_options() { return m_slot_options; }
+ const std::map<std::string, slot_option> &slot_options() const { return m_slot_options; }
+ std::map<std::string, std::string> &image_options() { return m_image_options; }
+ const std::map<std::string, std::string> &image_options() const { return m_image_options; }
-private:
- struct software_options
- {
- std::unordered_map<std::string, std::string> slot;
- std::unordered_map<std::string, std::string> image;
- };
-
- // slot/image/softlist calculus
- software_options evaluate_initial_softlist_options(const std::string &software_identifier);
- void update_slot_and_image_options();
- bool add_and_remove_slot_options();
- bool add_and_remove_image_options();
- void reevaluate_default_card_software();
- std::string get_default_card_software(device_slot_interface &slot);
+protected:
+ virtual void value_changed(const std::string &name, const std::string &value) override;
+ virtual override_get_value_result override_get_value(const char *name, std::string &value) const override;
+ virtual bool override_set_value(const char *name, const std::string &value) override;
- // static list of options entries
- static const options_entry s_option_entries[];
-
- // the current driver
- const game_driver * m_system;
+private:
+ static const options_entry s_option_entries[];
// slots and devices
- std::unordered_map<std::string, ::slot_option> m_slot_options;
- std::unordered_map<std::string, ::image_option> m_image_options_cannonical;
- std::unordered_map<std::string, ::image_option *> m_image_options;
+ std::map<std::string, slot_option> m_slot_options;
+ std::map<std::string, std::string> m_image_options;
// cached options, for scenarios where parsing core_options is too slow
- int m_coin_impulse;
- bool m_joystick_contradictory;
- bool m_sleep;
- bool m_refresh_speed;
- ui_option m_ui;
+ int m_coin_impulse;
+ bool m_joystick_contradictory;
+ bool m_sleep;
+ bool m_refresh_speed;
+ ui_option m_ui;
};
#endif // MAME_EMU_EMUOPTS_H
diff --git a/src/emu/image.cpp b/src/emu/image.cpp
index 973c2b57db8..25167db54a2 100644
--- a/src/emu/image.cpp
+++ b/src/emu/image.cpp
@@ -38,12 +38,37 @@ image_manager::image_manager(running_machine &machine)
continue;
// find the image option in image_options()
- const std::string &startup_image(machine.options().image_option(image.instance_name()).value());
+ auto iter = machine.options().image_options().find(image.instance_name());
+
+ // GROSS HACK - if we began our journey with a single device configuration (e.g. - a single
+ // cartridge system) but later added a device of that type, image.instance_name() will become
+ // something different. We're going to try to accomodate that specific scenario here
+ //
+ // Specific example: 'mame snes -cart1 sufami -cart2 poipoi' - the instance_name() starts out
+ // as "cartridge" but at the end becomes "cartridge1"
+ if (iter == machine.options().image_options().end()
+ && (image.instance_name().rbegin() != image.instance_name().rend())
+ && (*image.instance_name().rbegin() == '1'))
+ {
+ std::string alternate_instance_name = image.instance_name().substr(0, image.instance_name().size() - 1);
+ iter = machine.options().image_options().find(alternate_instance_name);
+
+ // If we found something, we need to write it back (so later checks work). We also need to redo
+ // the find; the act of erasing the old value breaks the iterator
+ if (iter != machine.options().image_options().end())
+ {
+ std::string temp = std::move(iter->second);
+ machine.options().image_options()[image.instance_name()] = std::move(temp);
+ machine.options().image_options().erase(alternate_instance_name);
+ iter = machine.options().image_options().find(image.instance_name());
+ }
+ }
// is an image specified for this image?
- if (!startup_image.empty())
+ if (iter != machine.options().image_options().end() && !iter->second.empty())
{
// we do have a startup image specified - load it
+ const std::string &startup_image(iter->second);
image_init_result result = image_init_result::FAIL;
// try as a softlist
@@ -193,7 +218,7 @@ void image_manager::options_extract()
}
// and set the option
- machine().options().image_option(image.instance_name()).specify(std::move(image_opt));
+ machine().options().image_options()[image.instance_name()] = std::move(image_opt);
}
}
diff --git a/src/emu/mconfig.cpp b/src/emu/mconfig.cpp
index ba52b986fa5..84fc5c70b67 100644
--- a/src/emu/mconfig.cpp
+++ b/src/emu/mconfig.cpp
@@ -39,20 +39,21 @@ machine_config::machine_config(const game_driver &gamedrv, emu_options &options)
const char *slot_option_name = owner.tag() + 1;
// figure out which device goes into this slot
- bool has_option = options.has_slot_option(slot_option_name);
+ bool has_option = options.slot_options().count(slot_option_name);
const char *selval;
bool is_default;
if (!has_option)
{
- // The only time we should be getting here is when emuopts.cpp is invoking
- // us to evaluate slot/image options, and the internal state of emuopts.cpp has
- // not caught up yet
+ // Theoretically we should never get here; in the long run the expectation is that
+ // options.slot_options() should be fully qualified and all options should be
+ // present. However, we're getting late in the MAME 0.185 development cycle and
+ // I don't want to rip this out (yet)
selval = slot.default_option();
is_default = true;
}
else
{
- const slot_option &opt = options.slot_option(slot_option_name);
+ const slot_option &opt = options.slot_options()[slot_option_name];
selval = opt.value().c_str();
is_default = !opt.specified();
}
diff --git a/src/emu/natkeyboard.cpp b/src/emu/natkeyboard.cpp
index 1aa8a78ed75..e1921b7a21d 100644
--- a/src/emu/natkeyboard.cpp
+++ b/src/emu/natkeyboard.cpp
@@ -365,7 +365,9 @@ void natural_keyboard::set_in_use(bool usage)
{
// update active usage
m_in_use = usage;
- machine().options().set_value(OPTION_NATURAL_KEYBOARD, usage, OPTION_PRIORITY_CMDLINE);
+ std::string error;
+ machine().options().set_value(OPTION_NATURAL_KEYBOARD, usage, OPTION_PRIORITY_CMDLINE, error);
+ assert(error.empty());
// lock out (or unlock) all keyboard inputs
for (auto &port : machine().ioport().ports())
diff --git a/src/emu/romload.cpp b/src/emu/romload.cpp
index ab2feae3886..118c7fcc0fe 100644
--- a/src/emu/romload.cpp
+++ b/src/emu/romload.cpp
@@ -1091,9 +1091,10 @@ int open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_
// will only find CHDs for the default configuration. I believe that this in practice will
// be acceptable.
emu_options driver_specific_options;
- driver_specific_options.set_value(OPTION_SYSTEMNAME, options.system_name(), OPTION_PRIORITY_DEFAULT);
- driver_specific_options.set_value(OPTION_MEDIAPATH, options.media_path(), OPTION_PRIORITY_DEFAULT);
- driver_specific_options.set_value(OPTION_DIFF_DIRECTORY, options.diff_directory(), OPTION_PRIORITY_DEFAULT);
+ std::string error_string;
+ driver_specific_options.set_value(OPTION_SYSTEMNAME, options.system_name(), OPTION_PRIORITY_DEFAULT, error_string);
+ driver_specific_options.set_value(OPTION_MEDIAPATH, options.media_path(), OPTION_PRIORITY_DEFAULT, error_string);
+ driver_specific_options.set_value(OPTION_DIFF_DIRECTORY, options.diff_directory(), OPTION_PRIORITY_DEFAULT, error_string);
// Now that we have an emu_options structure properly set up, we can create a machine_config
machine_config config(current_driver, driver_specific_options);
@@ -1495,13 +1496,12 @@ rom_load_manager::rom_load_manager(running_machine &machine)
specbios.assign(machine.options().bios());
else
{
- const device_slot_interface *slot = dynamic_cast<const device_slot_interface *>(&device);
- const slot_option *slot_opt = slot
- ? &machine.options().slot_option(slot->slot_name())
+ const char *slot_option_name = device.owner()->tag() + 1;
+ const slot_option *opt = machine.options().slot_options().count(slot_option_name)
+ ? &machine.options().slot_options()[slot_option_name]
: nullptr;
-
- specbios = slot_opt && !slot_opt->bios().empty()
- ? slot_opt->bios().c_str()
+ specbios = opt && !opt->bios().empty()
+ ? opt->bios().c_str()
: device.default_bios_tag();
}
determine_bios_rom(device, specbios.c_str());
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp
index 8aa5e0c31c2..c7a01674f47 100644
--- a/src/frontend/mame/clifront.cpp
+++ b/src/frontend/mame/clifront.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles
/***************************************************************************
- clifront.cpp
+ clifront.c
Command-line interface frontend for MAME.
@@ -190,26 +190,26 @@ 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)
{
- std::ostringstream option_errors;
+ std::string option_errors;
// parse the command line, adding any system-specific options
- try
- {
- m_options.parse_command_line(args, OPTION_PRIORITY_CMDLINE);
- }
- catch (options_exception &ex)
+ if (!mame_options::parse_command_line(m_options, args, option_errors))
{
// 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());
// otherwise, error on the options
- throw emu_fatalerror(EMU_ERR_INVALID_CONFIG, "%s", ex.message().c_str());
+ throw emu_fatalerror(EMU_ERR_INVALID_CONFIG, "%s", strtrimspace(option_errors).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,11 +232,8 @@ void cli_frontend::start_execution(mame_machine_manager *manager, std::vector<st
manager->start_luaengine();
- 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 (!option_errors.empty())
+ osd_printf_error("Error in command line:\n%s\n", strtrimspace(option_errors).c_str());
// if we can't find it, give an appropriate error
const game_driver *system = mame_options::system(m_options);
@@ -782,13 +779,8 @@ void cli_frontend::listmedia(const char *gamename)
//-------------------------------------------------
void cli_frontend::verifyroms(const char *gamename)
{
- // create our own copy of options for the purposes of ROM validation
- // so we are not "polluted" with driver-specific slot/image options
- emu_options options(true);
- options.copy_from(m_options);
-
// determine which drivers to output;
- driver_enumerator drivlist(options, gamename);
+ driver_enumerator drivlist(m_options, gamename);
unsigned correct = 0;
unsigned incorrect = 0;
@@ -1364,10 +1356,10 @@ void cli_frontend::execute_commands(const char *exename)
}
// other commands need the INIs parsed
- std::ostringstream option_errors;
+ std::string option_errors;
mame_options::parse_standard_inis(m_options,option_errors);
- if (option_errors.tellp() > 0)
- osd_printf_error("%s\n", option_errors.str().c_str());
+ if (!option_errors.empty())
+ osd_printf_error("%s\n", option_errors.c_str());
// createconfig?
if (m_options.command() == CLICOMMAND_CREATECONFIG)
diff --git a/src/frontend/mame/info.cpp b/src/frontend/mame/info.cpp
index b580bc76a7e..fa742dfe2f4 100644
--- a/src/frontend/mame/info.cpp
+++ b/src/frontend/mame/info.cpp
@@ -193,9 +193,9 @@ info_xml_creator::info_xml_creator(driver_enumerator &drivlist, bool filter_devi
: m_output(nullptr)
, m_drivlist(drivlist)
, m_filter_devices(filter_devices)
- , m_lookup_options(true)
+ , m_lookup_options(m_drivlist.options())
{
- m_lookup_options.copy_from(m_drivlist.options());
+ mame_options::remove_device_options(m_lookup_options);
}
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index add15da55f9..7e7d5d78572 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -721,6 +721,7 @@ void lua_engine::initialize()
emu["app_version"] = &emulator_info::get_bare_build_version;
emu["gamename"] = [this](){ return machine().system().description; };
emu["romname"] = [this](){ return machine().basename(); };
+ 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) {
@@ -921,11 +922,9 @@ void lua_engine::initialize()
"entries", sol::property([this](core_options &options) {
sol::table table = sol().create_table();
int unadorned_index = 0;
- for (auto &curentry : options.entries())
+ for(core_options::entry &curentry : options)
{
- const char *name = curentry->names().size() > 0
- ? curentry->name().c_str()
- : nullptr;
+ const char *name = curentry.name();
bool is_unadorned = false;
// check if it's unadorned
if (name && strlen(name) && !strcmp(name, options.unadorned(unadorned_index)))
@@ -933,8 +932,8 @@ void lua_engine::initialize()
unadorned_index++;
is_unadorned = true;
}
- if (curentry->type() != core_options::option_type::HEADER && curentry->type() != core_options::option_type::COMMAND && !is_unadorned)
- table[name] = &*curentry;
+ if (!curentry.is_header() && !curentry.is_command() && !curentry.is_internal() && !is_unadorned)
+ table[name] = &curentry;
}
return table;
}));
@@ -975,19 +974,18 @@ void lua_engine::initialize()
e.set_value(val, OPTION_PRIORITY_CMDLINE);
},
[this](core_options::entry &e) -> sol::object {
- if (e.type() == core_options::option_type::INVALID)
+ if(!e.type())
return sol::make_object(sol(), sol::nil);
switch(e.type())
{
- case core_options::option_type::BOOLEAN:
+ case OPTION_BOOLEAN:
return sol::make_object(sol(), atoi(e.value()) != 0);
- case core_options::option_type::INTEGER:
+ case OPTION_INTEGER:
return sol::make_object(sol(), atoi(e.value()));
- case core_options::option_type::FLOAT:
+ case OPTION_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 0046d4c421e..0a954906c35 100644
--- a/src/frontend/mame/mame.cpp
+++ b/src/frontend/mame/mame.cpp
@@ -124,38 +124,36 @@ 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)
{
- try
- {
- m_plugins->parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, false);
- }
- catch (options_exception &)
- {
- osd_printf_error("**Error loading plugin.ini**\n");
- }
+ bool result = m_plugins->parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_DRIVER_INI, error);
+ if (!result)
+ osd_printf_error("**Error loading plugin.ini**");
}
}
- for (auto &curentry : m_plugins->entries())
+ for (auto &curentry : *m_plugins)
{
- if (curentry->type() != core_options::option_type::HEADER)
+ if (!curentry.is_header())
{
- if (std::find(include.begin(), include.end(), curentry->name()) != include.end())
+ if (std::find(include.begin(), include.end(), curentry.name()) != include.end())
{
- m_plugins->set_value(curentry->name(), "1", OPTION_PRIORITY_CMDLINE);
+ std::string error_string;
+ m_plugins->set_value(curentry.name(), "1", OPTION_PRIORITY_CMDLINE, error_string);
}
- if (std::find(exclude.begin(), exclude.end(), curentry->name()) != exclude.end())
+ if (std::find(exclude.begin(), exclude.end(), curentry.name()) != exclude.end())
{
- m_plugins->set_value(curentry->name(), "0", OPTION_PRIORITY_CMDLINE);
+ std::string error_string;
+ m_plugins->set_value(curentry.name(), "0", OPTION_PRIORITY_CMDLINE, error_string);
}
}
}
}
- if (options().console())
- {
- m_plugins->set_value("console", "1", OPTION_PRIORITY_CMDLINE);
+ if (options().console()) {
+ std::string error_string;
+ m_plugins->set_value("console", "1", OPTION_PRIORITY_CMDLINE, error_string);
}
m_lua->initialize();
@@ -204,8 +202,9 @@ int mame_machine_manager::execute()
// parse any INI files as the first thing
if (m_options.read_config())
{
- std::ostringstream errors;
- mame_options::parse_standard_inis(m_options, errors);
+ m_options.revert(OPTION_PRIORITY_INI);
+ std::string errors;
+ mame_options::parse_standard_inis(m_options,errors);
}
// otherwise, perform validity checks before anything else
@@ -217,6 +216,11 @@ 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);
@@ -233,13 +237,12 @@ int mame_machine_manager::execute()
if (m_new_driver_pending)
{
// set up new system name and adjust device options accordingly
- m_options.set_system_name(m_new_driver_pending->name);
+ mame_options::set_system_name(m_options,m_new_driver_pending->name);
m_firstrun = true;
}
else
{
- if (machine.exit_pending())
- m_options.set_system_name("");
+ if (machine.exit_pending()) mame_options::set_system_name(m_options,"");
}
if (machine.exit_pending() && (!started_empty || is_empty))
diff --git a/src/frontend/mame/mameopts.cpp b/src/frontend/mame/mameopts.cpp
index 04025630a58..8cb8cff09fa 100644
--- a/src/frontend/mame/mameopts.cpp
+++ b/src/frontend/mame/mameopts.cpp
@@ -21,21 +21,491 @@
#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;
+
+ // 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();
+ };
+
+ // 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::ostream &error_stream, const game_driver *driver)
+void mame_options::parse_standard_inis(emu_options &options, std::string &error_string, 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_stream);
+ 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);
// debug mode: parse "debug.ini" as well
if (options.debug())
- parse_one_ini(options, "debug", OPTION_PRIORITY_DEBUG_INI, &error_stream);
+ parse_one_ini(options,"debug", OPTION_PRIORITY_DEBUG_INI, &error_string);
// if we have a valid system driver, parse system-specific INI files
const game_driver *cursystem = (driver == nullptr) ? system(options) : driver;
@@ -44,18 +514,18 @@ void mame_options::parse_standard_inis(emu_options &options, std::ostream &error
// parse "vertical.ini" or "horizont.ini"
if (cursystem->flags & ORIENTATION_SWAP_XY)
- parse_one_ini(options, "vertical", OPTION_PRIORITY_ORIENTATION_INI, &error_stream);
+ parse_one_ini(options,"vertical", OPTION_PRIORITY_ORIENTATION_INI, &error_string);
else
- parse_one_ini(options, "horizont", OPTION_PRIORITY_ORIENTATION_INI, &error_stream);
+ parse_one_ini(options,"horizont", OPTION_PRIORITY_ORIENTATION_INI, &error_string);
if (cursystem->flags & MACHINE_TYPE_ARCADE)
- parse_one_ini(options, "arcade", OPTION_PRIORITY_SYSTYPE_INI, &error_stream);
+ parse_one_ini(options,"arcade", OPTION_PRIORITY_SYSTYPE_INI, &error_string);
else if (cursystem->flags & MACHINE_TYPE_CONSOLE)
- parse_one_ini(options ,"console", OPTION_PRIORITY_SYSTYPE_INI, &error_stream);
+ parse_one_ini(options,"console", OPTION_PRIORITY_SYSTYPE_INI, &error_string);
else if (cursystem->flags & MACHINE_TYPE_COMPUTER)
- parse_one_ini(options, "computer", OPTION_PRIORITY_SYSTYPE_INI, &error_stream);
+ parse_one_ini(options,"computer", OPTION_PRIORITY_SYSTYPE_INI, &error_string);
else if (cursystem->flags & MACHINE_TYPE_OTHER)
- parse_one_ini(options, "othersys", OPTION_PRIORITY_SYSTYPE_INI, &error_stream);
+ parse_one_ini(options,"othersys", OPTION_PRIORITY_SYSTYPE_INI, &error_string);
machine_config config(*cursystem, options);
for (const screen_device &device : screen_device_iterator(config.root_device()))
@@ -63,35 +533,35 @@ void mame_options::parse_standard_inis(emu_options &options, std::ostream &error
// parse "raster.ini" for raster games
if (device.screen_type() == SCREEN_TYPE_RASTER)
{
- parse_one_ini(options, "raster", OPTION_PRIORITY_SCREEN_INI, &error_stream);
+ parse_one_ini(options,"raster", OPTION_PRIORITY_SCREEN_INI, &error_string);
break;
}
// parse "vector.ini" for vector games
if (device.screen_type() == SCREEN_TYPE_VECTOR)
{
- parse_one_ini(options, "vector", OPTION_PRIORITY_SCREEN_INI, &error_stream);
+ parse_one_ini(options,"vector", OPTION_PRIORITY_SCREEN_INI, &error_string);
break;
}
// parse "lcd.ini" for lcd games
if (device.screen_type() == SCREEN_TYPE_LCD)
{
- parse_one_ini(options, "lcd", OPTION_PRIORITY_SCREEN_INI, &error_stream);
+ parse_one_ini(options,"lcd", OPTION_PRIORITY_SCREEN_INI, &error_string);
break;
}
}
// next parse "source/<sourcefile>.ini"
std::string sourcename = core_filename_extract_base(cursystem->source_file, true).insert(0, "source" PATH_SEPARATOR);
- parse_one_ini(options, sourcename.c_str(), OPTION_PRIORITY_SOURCE_INI, &error_stream);
+ parse_one_ini(options,sourcename.c_str(), OPTION_PRIORITY_SOURCE_INI, &error_string);
// 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_stream);
+ parse_one_ini(options,driver_list::driver(gparent).name, OPTION_PRIORITY_GPARENT_INI, &error_string);
if (parent != -1)
- 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);
+ 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);
}
@@ -108,33 +578,115 @@ 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
//-------------------------------------------------
-void mame_options::parse_one_ini(emu_options &options, const char *basename, int priority, std::ostream *error_stream)
+bool mame_options::parse_one_ini(emu_options &options, const char *basename, int priority, std::string *error_string)
{
// don't parse if it has been disabled
if (!options.read_config())
- return;
+ return false;
// 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;
+ return false;
// parse the file
osd_printf_verbose("Parsing %s.ini\n", basename);
- try
- {
- options.parse_ini_file((util::core_file&)file, priority, 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;
- }
+ std::string error;
+ bool result = options.parse_ini_file((util::core_file&)file, 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));
+ return result;
}
+
diff --git a/src/frontend/mame/mameopts.h b/src/frontend/mame/mameopts.h
index 68c0d683d0d..3c543e65c66 100644
--- a/src/frontend/mame/mameopts.h
+++ b/src/frontend/mame/mameopts.h
@@ -50,14 +50,42 @@ 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 void parse_standard_inis(emu_options &options, std::ostream &error_stream, const game_driver *driver = nullptr);
+ 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 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);
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 void parse_one_ini(emu_options &options, const char *basename, int priority, std::ostream *error_stream = nullptr);
+ 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);
+
+ // 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;
};
#endif /* __MAMEOPTS_H__ */
diff --git a/src/frontend/mame/pluginopts.cpp b/src/frontend/mame/pluginopts.cpp
index b9a9e8d3c3b..779ac6ff709 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({ std::move(plugin_name) }, core_strdup(description.c_str()), option_type::BOOLEAN, start ? "1" : "0");
+ add_entry(core_strdup(plugin_name.c_str()),core_strdup(description.c_str()), OPTION_BOOLEAN, start ? "1" : "0");
}
}
diff --git a/src/frontend/mame/ui/custui.cpp b/src/frontend/mame/ui/custui.cpp
index 438840f0fc0..17a5c22539b 100644
--- a/src/frontend/mame/ui/custui.cpp
+++ b/src/frontend/mame/ui/custui.cpp
@@ -64,10 +64,12 @@ menu_custom_ui::menu_custom_ui(mame_ui_manager &mui, render_container &container
menu_custom_ui::~menu_custom_ui()
{
- ui().options().set_value(OPTION_HIDE_PANELS, ui_globals::panels_status, OPTION_PRIORITY_CMDLINE);
+ std::string error_string;
+ ui().options().set_value(OPTION_HIDE_PANELS, ui_globals::panels_status, OPTION_PRIORITY_CMDLINE, error_string);
if (!m_lang.empty())
{
- machine().options().set_value(OPTION_LANGUAGE, m_lang[m_currlang].c_str(), OPTION_PRIORITY_CMDLINE);
+ machine().options().set_value(OPTION_LANGUAGE, m_lang[m_currlang].c_str(), OPTION_PRIORITY_CMDLINE, error_string);
+ machine().options().mark_changed(OPTION_LANGUAGE);
load_translation(machine().options());
}
ui_globals::reset = true;
@@ -213,10 +215,22 @@ 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();
- 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());
+
+ 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());
+ }
+ }
+
}
//-------------------------------------------------
@@ -250,9 +264,11 @@ menu_font_ui::~menu_font_ui()
name.insert(0, "[B]");
}
#endif
- 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);
+ 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);
}
//-------------------------------------------------
@@ -447,11 +463,11 @@ menu_colors_ui::menu_colors_ui(mame_ui_manager &mui, render_container &container
menu_colors_ui::~menu_colors_ui()
{
- std::string dec_color;
+ std::string error_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);
+ ui().options().set_value(m_color_table[index].option, dec_color.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
}
}
diff --git a/src/frontend/mame/ui/dirmenu.cpp b/src/frontend/mame/ui/dirmenu.cpp
index 2d0200ef099..1ef39925bfd 100644
--- a/src/frontend/mame/ui/dirmenu.cpp
+++ b/src/frontend/mame/ui/dirmenu.cpp
@@ -352,10 +352,11 @@ 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);
+ ui().options().set_value(s_folders[m_ref].option, m_current_path.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
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);
+ 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);
}
}
else
@@ -370,10 +371,11 @@ 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);
+ ui().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
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);
+ 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);
}
}
@@ -590,10 +592,11 @@ 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);
+ ui().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
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);
+ 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);
}
reset_parent(reset_options::REMEMBER_REF);
diff --git a/src/frontend/mame/ui/info.cpp b/src/frontend/mame/ui/info.cpp
index ab0e6d85cd3..8101faad3c6 100644
--- a/src/frontend/mame/ui/info.cpp
+++ b/src/frontend/mame/ui/info.cpp
@@ -326,7 +326,8 @@ std::string machine_info::mandatory_images()
{
if (image.must_be_loaded())
{
- if (m_machine.options().image_option(image.instance_name()).value().empty())
+ auto iter = m_machine.options().image_options().find(image.instance_name());
+ if (iter == m_machine.options().image_options().end() || iter->second.empty())
{
if (is_first)
is_first = false;
diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp
index 66201951a91..3ec2bf78cd3 100644
--- a/src/frontend/mame/ui/miscmenu.cpp
+++ b/src/frontend/mame/ui/miscmenu.cpp
@@ -127,10 +127,12 @@ void menu_bios_selection::handle()
if (val>cnt) val=1;
dev->set_system_bios(val);
if (strcmp(dev->tag(),":")==0) {
- machine().options().set_value("bios", val-1, OPTION_PRIORITY_CMDLINE);
+ std::string error;
+ machine().options().set_value("bios", val-1, OPTION_PRIORITY_CMDLINE, error);
+ assert(error.empty());
} else {
const char *slot_option_name = dev->owner()->tag() + 1;
- machine().options().slot_option(slot_option_name).set_bios(string_format("%d", val - 1));
+ machine().options().slot_options()[slot_option_name].set_bios(string_format("%d", val - 1));
}
reset(reset_options::REMEMBER_REF);
}
@@ -673,14 +675,15 @@ 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::ostringstream error;
- mame_options::parse_standard_inis(m_opts, error, m_drv);
+ std::string error;
+ mame_options::parse_standard_inis(m_opts,error, m_drv);
setup_bios();
}
@@ -751,7 +754,9 @@ 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;
- m_opts.set_value(OPTION_BIOS, m_bios[m_curbios].second, OPTION_PRIORITY_CMDLINE);
+ std::string error;
+ m_opts.set_value(OPTION_BIOS, m_bios[m_curbios].second, OPTION_PRIORITY_CMDLINE, error);
+ m_opts.mark_changed(OPTION_BIOS);
reset(reset_options::REMEMBER_POSITION);
}
}
@@ -913,7 +918,8 @@ 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);
- plugins.set_value((const char*)menu_event->itemref, oldval == 1 ? 0 : 1, OPTION_PRIORITY_CMDLINE);
+ std::string error_string;
+ plugins.set_value((const char*)menu_event->itemref, oldval == 1 ? 0 : 1, OPTION_PRIORITY_CMDLINE, error_string);
changed = true;
}
}
@@ -929,13 +935,13 @@ void menu_plugins_configure::populate(float &customtop, float &custombottom)
{
plugin_options& plugins = mame_machine_manager::instance()->plugins();
- for (auto &curentry : plugins.entries())
+ for (auto &curentry : plugins)
{
- if (curentry->type() != OPTION_HEADER)
+ if (!curentry.is_header())
{
- 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());
+ 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());
}
}
item_append(menu_item_type::SEPARATOR);
diff --git a/src/frontend/mame/ui/selgame.cpp b/src/frontend/mame/ui/selgame.cpp
index 04d1c2b2350..e2628f63a9b 100644
--- a/src/frontend/mame/ui/selgame.cpp
+++ b/src/frontend/mame/ui/selgame.cpp
@@ -116,7 +116,8 @@ 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);
+ 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);
ui_globals::curimage_view = FIRST_VIEW;
ui_globals::curdats_view = 0;
@@ -154,9 +155,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);
- 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);
+ 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);
ui().save_ui_options();
}
@@ -929,10 +930,11 @@ void menu_select_game::inkey_select_favorite(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);
- mopt.set_value(OPTION_SOFTWARENAME, string_list.c_str(), OPTION_PRIORITY_CMDLINE);
+ mopt.set_value(OPTION_SOFTWARENAME, string_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
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);
+ mopt.set_value(OPTION_SNAPNAME, snap_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
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 23107e4d992..b5eeb36b204 100644
--- a/src/frontend/mame/ui/selsoft.cpp
+++ b/src/frontend/mame/ui/selsoft.cpp
@@ -144,6 +144,9 @@ 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);
}
//-------------------------------------------------
@@ -715,10 +718,11 @@ void menu_select_software::inkey_select(const event *menu_event)
return;
}
- machine().options().set_system_name(m_driver->name);
- machine().options().set_value(OPTION_SOFTWARENAME, ui_swinfo->shortname, OPTION_PRIORITY_CMDLINE);
+ 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);
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);
+ machine().options().set_value(OPTION_SNAPNAME, snap_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
reselect_last::driver = drivlist.driver().name;
reselect_last::software = ui_swinfo->shortname;
reselect_last::swlist = ui_swinfo->listname;
@@ -1284,8 +1288,9 @@ 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);
+ machine().options().set_value(OPTION_SOFTWARENAME, string_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
reselect_last::driver = m_uiinfo->driver->name;
reselect_last::software = m_uiinfo->shortname;
@@ -1293,7 +1298,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);
+ machine().options().set_value(OPTION_SNAPNAME, snap_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
mame_machine_manager::instance()->schedule_new_driver(*m_uiinfo->driver);
machine().schedule_hard_reset();
@@ -1395,7 +1400,8 @@ void bios_selection::handle()
reselect_last::set(true);
}
- moptions.set_value(OPTION_BIOS, elem.second, OPTION_PRIORITY_CMDLINE);
+ std::string error;
+ moptions.set_value(OPTION_BIOS, elem.second, OPTION_PRIORITY_CMDLINE, error);
mame_machine_manager::instance()->schedule_new_driver(*s_driver);
machine().schedule_hard_reset();
stack_reset();
@@ -1403,7 +1409,8 @@ void bios_selection::handle()
else
{
ui_software_info *ui_swinfo = (ui_software_info *)m_driver;
- machine().options().set_value(OPTION_BIOS, elem.second, OPTION_PRIORITY_CMDLINE);
+ std::string error;
+ machine().options().set_value(OPTION_BIOS, elem.second, OPTION_PRIORITY_CMDLINE, error);
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());
@@ -1424,10 +1431,11 @@ 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);
+ moptions.set_value(OPTION_SOFTWARENAME, string_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
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);
+ moptions.set_value(OPTION_SNAPNAME, snap_list.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
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 8434a667899..42ec9e1a896 100644
--- a/src/frontend/mame/ui/slotopt.cpp
+++ b/src/frontend/mame/ui/slotopt.cpp
@@ -27,9 +27,9 @@ device_slot_option *menu_slot_devices::slot_get_current_option(device_slot_inter
std::string current;
const char *slot_option_name = slot.device().tag() + 1;
- if (!slot.fixed())
+ if (!slot.fixed() && machine().options().slot_options().count(slot_option_name) > 0)
{
- current = machine().options().slot_option(slot_option_name).value();
+ current = machine().options().slot_options()[slot_option_name].value();
}
else
{
@@ -140,7 +140,9 @@ const char *menu_slot_devices::slot_get_option(device_slot_interface &slot, int
void menu_slot_devices::set_slot_device(device_slot_interface &slot, const char *val)
{
- machine().options().set_value(slot.device().tag()+1, val, OPTION_PRIORITY_CMDLINE);
+ std::string error;
+ machine().options().set_value(slot.device().tag()+1, val, OPTION_PRIORITY_CMDLINE, error);
+ assert(error.empty());
}
/*-------------------------------------------------
@@ -198,6 +200,7 @@ void menu_slot_devices::handle()
{
if ((uintptr_t)menu_event->itemref == 1 && 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)
diff --git a/src/frontend/mame/ui/sndmenu.cpp b/src/frontend/mame/ui/sndmenu.cpp
index f2304b529ea..0a0d1c019ed 100644
--- a/src/frontend/mame/ui/sndmenu.cpp
+++ b/src/frontend/mame/ui/sndmenu.cpp
@@ -45,19 +45,23 @@ 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);
+ moptions.set_value(OSDOPTION_SOUND, m_sound ? OSDOPTVAL_AUTO : OSDOPTVAL_NONE, OPTION_PRIORITY_CMDLINE, error_string);
+ machine().options().mark_changed(OSDOPTION_SOUND);
}
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);
+ moptions.set_value(OPTION_SAMPLERATE, m_sound_rate[m_cur_rates], OPTION_PRIORITY_CMDLINE, error_string);
+ machine().options().mark_changed(OPTION_SAMPLERATE);
}
if (moptions.bool_value(OPTION_SAMPLES)!=m_samples)
{
- moptions.set_value(OPTION_SAMPLES, m_samples, OPTION_PRIORITY_CMDLINE);
+ moptions.set_value(OPTION_SAMPLES, m_samples, OPTION_PRIORITY_CMDLINE, error_string);
+ machine().options().mark_changed(OPTION_SAMPLES);
}
}
diff --git a/src/frontend/mame/ui/submenu.cpp b/src/frontend/mame/ui/submenu.cpp
index ab18a5a5a95..5a8cb83cd8b 100644
--- a/src/frontend/mame/ui/submenu.cpp
+++ b/src/frontend/mame/ui/submenu.cpp
@@ -240,7 +240,8 @@ 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);
+ 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();
break;
case OPTION_INTEGER:
if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
@@ -248,7 +249,8 @@ 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);
+ sm_option.options->set_value(sm_option.name, i_cur, OPTION_PRIORITY_CMDLINE, error_string);
+ sm_option.entry->mark_changed();
}
break;
case OPTION_FLOAT:
@@ -258,19 +260,17 @@ void submenu::handle()
f_cur = atof(sm_option.entry->value());
if (sm_option.entry->has_range())
{
- const char *minimum = sm_option.entry->minimum();
- const char *maximum = sm_option.entry->maximum();
- f_step = atof(minimum);
+ f_step = atof(sm_option.entry->minimum());
if (f_step <= 0.0f) {
- int pmin = getprecisionchr(minimum);
- int pmax = getprecisionchr(maximum);
+ int pmin = getprecisionchr(sm_option.entry->minimum());
+ int pmax = getprecisionchr(sm_option.entry->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().c_str());
+ int precision = getprecisionchr(sm_option.entry->default_value());
tmptxt = '1' + std::string(precision, '0');
f_step = 1 / atof(tmptxt.c_str());
}
@@ -279,7 +279,8 @@ 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);
+ sm_option.options->set_value(sm_option.name, tmptxt.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
+ sm_option.entry->mark_changed();
}
break;
case OPTION_STRING:
@@ -292,11 +293,10 @@ 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);
+ sm_option.options->set_value(sm_option.name, v_cur.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
+ sm_option.entry->mark_changed();
}
break;
- default:
- break;
}
break;
default:
@@ -391,7 +391,7 @@ void submenu::populate(float &customtop, float &custombottom)
break;
case OPTION_STRING:
{
- std::string v_cur(sm_option->entry->value());
+ std::string const 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 f17b6fe53ff..acaf28d90e4 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::shared_ptr entry;
+ core_options::entry *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 fc080835893..cf4ea2c9cc5 100644
--- a/src/frontend/mame/ui/ui.cpp
+++ b/src/frontend/mame/ui/ui.cpp
@@ -2228,18 +2228,14 @@ 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)
{
- try
- {
- options().parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, true);
- }
- catch (options_exception &)
- {
+ bool result = options().parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_DRIVER_INI, error);
+ if (!result)
osd_printf_error("**Error loading ui.ini**");
- }
}
}
@@ -2270,37 +2266,28 @@ void mame_ui_manager::save_main_option()
{
// parse the file
std::string error;
- emu_options options(true); // This way we make sure that all OSD parts are in
-
- options.copy_from(machine().options());
+ emu_options options(machine().options()); // This way we make sure that all OSD parts are in
+ std::string error_string;
// 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)
{
- try
- {
- options.parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, true);
- }
- catch(options_error_exception &ex)
+ bool result = options.parse_ini_file((util::core_file&)file, OPTION_PRIORITY_MAME_INI, OPTION_PRIORITY_DRIVER_INI, error);
+ if (!result)
{
- osd_printf_error("**Error loading %s.ini**: %s\n", emulator_info::get_configname(), ex.message().c_str());
+ osd_printf_error("**Error loading %s.ini**", emulator_info::get_configname());
return;
}
- catch (options_exception &)
- {
- // ignore other exceptions
- }
}
}
- for (const auto &f_entry : machine().options().entries())
+ for (emu_options::entry &f_entry : machine().options())
{
- const char *value = f_entry->value();
- if (value && strcmp(value, options.value(f_entry->name().c_str())))
+ if (f_entry.is_changed())
{
- options.set_value(f_entry->name(), *f_entry->value(), OPTION_PRIORITY_CMDLINE);
+ options.set_value(f_entry.name(), f_entry.value(), OPTION_PRIORITY_CMDLINE, error_string);
}
}
diff --git a/src/lib/util/options.cpp b/src/lib/util/options.cpp
index 8889107eba1..8500eda327d 100644
--- a/src/lib/util/options.cpp
+++ b/src/lib/util/options.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles
/***************************************************************************
- options.cpp
+ options.c
Core options code code
@@ -44,335 +44,155 @@ const char *const core_options::s_option_unadorned[MAX_UNADORNED_OPTIONS] =
};
-//**************************************************************************
-// OPTIONS EXCEPTION CLASS
-//**************************************************************************
-
-//-------------------------------------------------
-// options_exception - constructor
-//-------------------------------------------------
-
-options_exception::options_exception(std::string &&message)
- : m_message(std::move(message))
-{
-}
-
-
-//-------------------------------------------------
-// options_warning_exception - constructor
-//-------------------------------------------------
-
-options_warning_exception::options_warning_exception(std::string &&message)
- : options_exception(std::move(message))
-{
-}
-
-
-//-------------------------------------------------
-// options_error_exception - constructor
-//-------------------------------------------------
-
-options_error_exception::options_error_exception(std::string &&message)
- : options_exception(std::move(message))
-{
-}
-
//**************************************************************************
-// CORE OPTIONS ENTRY BASE CLASS
+// CORE OPTIONS ENTRY
//**************************************************************************
//-------------------------------------------------
// entry - constructor
//-------------------------------------------------
-core_options::entry::entry(std::vector<std::string> &&names, core_options::option_type type, const char *description)
- : m_names(std::move(names))
- , m_priority(OPTION_PRIORITY_DEFAULT)
- , m_type(type)
- , m_description(description)
-{
- if (type == option_type::HEADER)
- assert(m_names.size() == 0);
- else
- assert(m_names.size() > 0);
-}
-
-core_options::entry::entry(std::string &&name, core_options::option_type type, const char *description)
- : entry(std::vector<std::string>({ std::move(name) }), type, description)
-{
-}
-
-
-//-------------------------------------------------
-// entry - destructor
-//-------------------------------------------------
-
-core_options::entry::~entry()
+core_options::entry::entry(const char *name, const char *description, uint32_t flags, const char *defvalue)
+ : m_next(nullptr),
+ m_flags(flags),
+ m_error_reported(false),
+ m_priority(OPTION_PRIORITY_DEFAULT),
+ m_description(description),
+ m_changed(false)
{
-}
-
-
-//-------------------------------------------------
-// entry::value
-//-------------------------------------------------
-
-const char *core_options::entry::value() const
-{
- // returning 'nullptr' from here signifies a value entry that is essentially "write only"
- // and cannot be meaningfully persisted (e.g. - a command or the software name)
- return nullptr;
-}
-
-
-//-------------------------------------------------
-// entry::set_value
-//-------------------------------------------------
-
-void core_options::entry::set_value(std::string &&newvalue, int priority_value, bool always_override)
-{
- // it is invalid to set the value on a header
- assert(type() != option_type::HEADER);
-
- // only set the value if we have priority
- if (always_override || priority_value >= priority())
- {
- internal_set_value(std::move(newvalue));
- m_priority = priority_value;
-
- // invoke the value changed handler, if appropriate
- if (m_value_changed_handler)
- m_value_changed_handler(value());
- }
-}
-
-
-//-------------------------------------------------
-// entry::set_default_value
-//-------------------------------------------------
-
-void core_options::entry::set_default_value(std::string &&newvalue)
-{
- // set_default_value() is not necessarily supported for all entry types
- throw false;
-}
-
-
-//-------------------------------------------------
-// entry::validate
-//-------------------------------------------------
-
-void core_options::entry::validate(const std::string &data)
-{
- float fval;
- int ival;
- int minimum_integer, maximum_integer;
- float minimum_float, maximum_float;
-
- switch (type())
+ // copy in the name(s) as appropriate
+ if (name != nullptr)
{
- case option_type::BOOLEAN:
- // booleans must be 0 or 1
- if (sscanf(data.c_str(), "%d", &ival) != 1 || ival < 0 || ival > 1)
- throw options_warning_exception("Illegal boolean value for %s: \"%s\"; reverting to %s\n", name(), data, value());
- break;
-
- case option_type::INTEGER:
- // integers must be integral
- if (sscanf(data.c_str(), "%d", &ival) != 1)
- throw options_warning_exception("Illegal integer value for %s: \"%s\"; reverting to %s\n", name(), data, value());
-
- // range checking
- if (has_range())
+ // first extract any range
+ std::string namestr(name);
+ int lparen = namestr.find_first_of('(',0);
+ int dash = namestr.find_first_of('-',lparen + 1);
+ int rparen = namestr.find_first_of(')',dash + 1);
+ if (lparen != -1 && dash != -1 && rparen != -1)
{
- minimum_integer = atoi(minimum());
- maximum_integer = atoi(maximum());
- if (ival < minimum_integer || ival > maximum_integer)
- throw options_warning_exception("Out-of-range integer value for %s: \"%s\" (must be between %d and %d); reverting to %s\n", name(), data, minimum_integer, maximum_integer, value());
+ strtrimspace(m_minimum.assign(namestr.substr(lparen + 1, dash - (lparen + 1))));
+ strtrimspace(m_maximum.assign(namestr.substr(dash + 1, rparen - (dash + 1))));
+ namestr.erase(lparen, rparen + 1 - lparen);
}
- break;
-
- case option_type::FLOAT:
- if (sscanf(data.c_str(), "%f", &fval) != 1)
- throw options_warning_exception("Illegal float value for %s: \"%s\"; reverting to %s\n", name(), data, value());
- // range checking
- if (has_range())
+ // then chop up any semicolon-separated names
+ int semi;
+ int nameindex = 0;
+ while ((semi = namestr.find_first_of(';')) != -1 && nameindex < ARRAY_LENGTH(m_name))
{
- minimum_float = atof(minimum());
- maximum_float = atof(maximum());
- if (fval < minimum_float || fval > maximum_float)
- throw options_warning_exception("Out-of-range float value for %s: \"%s\" (must be between %f and %f); reverting to %s\n", name(), data, minimum_float, maximum_float, value());
+ m_name[nameindex++].assign(namestr.substr(0, semi));
+ namestr.erase(0, semi + 1);
}
- break;
- case OPTION_STRING:
- // strings can be anything
- break;
-
- case OPTION_INVALID:
- case OPTION_HEADER:
- default:
- // anything else is invalid
- throw options_error_exception("Attempted to set invalid option %s\n", name());
+ // finally add the last item
+ if (nameindex < ARRAY_LENGTH(m_name))
+ m_name[nameindex++] = namestr;
}
-}
-
-//-------------------------------------------------
-// entry::minimum
-//-------------------------------------------------
-
-const char *core_options::entry::minimum() const
-{
- return nullptr;
+ // set the default value
+ if (defvalue != nullptr)
+ m_defdata = defvalue;
+ m_data = m_defdata;
}
//-------------------------------------------------
-// entry::maximum
+// set_value - update our data value
//-------------------------------------------------
-const char *core_options::entry::maximum() const
+void core_options::entry::set_value(const char *newdata, int priority)
{
- return nullptr;
-}
-
-
-//-------------------------------------------------
-// entry::has_range
-//-------------------------------------------------
+ // ignore if we don't have priority
+ if (priority < m_priority)
+ return;
-bool core_options::entry::has_range() const
-{
- return minimum() && maximum();
+ // set the data and priority, then bump the sequence
+ m_data = newdata;
+ m_priority = priority;
}
//-------------------------------------------------
-// entry::default_value
+// set_default_value - set the default value of
+// an option, and reset the current value to it
//-------------------------------------------------
-const std::string &core_options::entry::default_value() const
+void core_options::entry::set_default_value(const char *defvalue)
{
- // I don't really want this generally available, but MewUI seems to need it. Please
- // do not use
- throw false;
+ m_data = defvalue;
+ m_defdata = defvalue;
+ m_priority = OPTION_PRIORITY_DEFAULT;
}
-//**************************************************************************
-// CORE OPTIONS SIMPLE ENTRYCLASS
-//**************************************************************************
-
//-------------------------------------------------
-// simple_entry - constructor
+// set_description - set the description of
+// an option
//-------------------------------------------------
-core_options::simple_entry::simple_entry(std::vector<std::string> &&names, const char *description, core_options::option_type type, std::string &&defdata, std::string &&minimum, std::string &&maximum)
- : entry(std::move(names), type, description)
- , m_defdata(std::move(defdata))
- , m_minimum(std::move(minimum))
- , m_maximum(std::move(maximum))
+void core_options::entry::set_description(const char *description)
{
- m_data = m_defdata;
+ m_description = description;
}
-//-------------------------------------------------
-// simple_entry - destructor
-//-------------------------------------------------
-
-core_options::simple_entry::~simple_entry()
+void core_options::entry::set_flag(uint32_t mask, uint32_t flag)
{
+ m_flags = ( m_flags & mask ) | flag;
}
//-------------------------------------------------
-// simple_entry::value
+// revert - revert back to our default if we are
+// within the given priority range
//-------------------------------------------------
-const char *core_options::simple_entry::value() const
+void core_options::entry::revert(int priority_hi, int priority_lo)
{
- const char *result;
- switch (type())
+ // if our priority is within the range, revert to the default
+ if (m_priority <= priority_hi && m_priority >= priority_lo)
{
- case core_options::option_type::BOOLEAN:
- case core_options::option_type::INTEGER:
- case core_options::option_type::FLOAT:
- case core_options::option_type::STRING:
- result = m_data.c_str();
- break;
-
- default:
- result = nullptr;
- break;
+ m_data = m_defdata;
+ m_priority = OPTION_PRIORITY_DEFAULT;
}
- return result;
}
-//-------------------------------------------------
-// simple_entry::default_value
-//-------------------------------------------------
-
-const std::string &core_options::simple_entry::default_value() const
-{
- // only MewUI seems to need this; please don't use
- return m_defdata;
-}
+//**************************************************************************
+// CORE OPTIONS
+//**************************************************************************
//-------------------------------------------------
-// internal_set_value
+// core_options - constructor
//-------------------------------------------------
-void core_options::simple_entry::internal_set_value(std::string &&newvalue)
+core_options::core_options()
{
- m_data = std::move(newvalue);
}
-
-//-------------------------------------------------
-// set_default_value
-//-------------------------------------------------
-
-void core_options::simple_entry::set_default_value(std::string &&newvalue)
+core_options::core_options(const options_entry *entrylist)
{
- m_defdata = std::move(newvalue);
+ add_entries(entrylist);
}
-
-//-------------------------------------------------
-// minimum
-//-------------------------------------------------
-
-const char *core_options::simple_entry::minimum() const
+core_options::core_options(const options_entry *entrylist1, const options_entry *entrylist2)
{
- return m_minimum.c_str();
+ add_entries(entrylist1);
+ add_entries(entrylist2);
}
-
-//-------------------------------------------------
-// maximum
-//-------------------------------------------------
-
-const char *core_options::simple_entry::maximum() const
+core_options::core_options(const options_entry *entrylist1, const options_entry *entrylist2, const options_entry *entrylist3)
{
- return m_maximum.c_str();
+ add_entries(entrylist1);
+ add_entries(entrylist2);
+ add_entries(entrylist3);
}
-
-//**************************************************************************
-// CORE OPTIONS
-//**************************************************************************
-
-//-------------------------------------------------
-// core_options - constructor
-//-------------------------------------------------
-
-core_options::core_options()
+core_options::core_options(const core_options &src)
{
+ copyfrom(src);
}
@@ -386,140 +206,82 @@ core_options::~core_options()
//-------------------------------------------------
-// add_entry - adds an entry
+// operator= - assignment operator
//-------------------------------------------------
-void core_options::add_entry(entry::shared_ptr &&entry, const char *after_header)
+core_options &core_options::operator=(const core_options &rhs)
{
- // update the entry map
- for (const std::string &name : entry->names())
- {
- // append the entry
- add_to_entry_map(std::string(name), entry);
-
- // for booleans, add the "-noXYZ" option as well
- if (entry->type() == option_type::BOOLEAN)
- add_to_entry_map(std::string("no") + name, entry);
- }
-
- // and add the entry to the vector
- m_entries.emplace_back(std::move(entry));
+ // ignore self-assignment
+ if (this != &rhs)
+ copyfrom(rhs);
+ return *this;
}
//-------------------------------------------------
-// add_to_entry_map - adds an entry to the entry
-// map
+// operator== - compare two sets of options
//-------------------------------------------------
-void core_options::add_to_entry_map(std::string &&name, entry::shared_ptr &entry)
+bool core_options::operator==(const core_options &rhs)
{
- // it is illegal to call this method for something that already ex0ists
- assert(m_entrymap.find(name) == m_entrymap.end());
+ // iterate over options in the first list
+ for (entry &curentry : m_entrylist)
+ if (!curentry.is_header())
+ {
+ // if the values differ, return false
+ if (strcmp(curentry.value(), rhs.value(curentry.name())) != 0)
+ return false;
+ }
- // append the entry
- m_entrymap.emplace(std::make_pair(name, entry::weak_ptr(entry)));
+ return true;
}
//-------------------------------------------------
-// add_entry - adds an entry based on an
-// options_entry
+// operator!= - compare two sets of options
//-------------------------------------------------
-void core_options::add_entry(const options_entry &opt, bool override_existing)
+bool core_options::operator!=(const core_options &rhs)
{
- std::vector<std::string> names;
- std::string minimum, maximum;
-
- // copy in the name(s) as appropriate
- if (opt.name)
- {
- // first extract any range
- std::string namestr(opt.name);
- int lparen = namestr.find_first_of('(', 0);
- int dash = namestr.find_first_of('-', lparen + 1);
- int rparen = namestr.find_first_of(')', dash + 1);
- if (lparen != -1 && dash != -1 && rparen != -1)
- {
- strtrimspace(minimum.assign(namestr.substr(lparen + 1, dash - (lparen + 1))));
- strtrimspace(maximum.assign(namestr.substr(dash + 1, rparen - (dash + 1))));
- namestr.erase(lparen, rparen + 1 - lparen);
- }
+ return !operator==(rhs);
+}
- // then chop up any semicolon-separated names
- size_t semi;
- while ((semi = namestr.find_first_of(';')) != std::string::npos)
- {
- names.push_back(namestr.substr(0, semi));
- namestr.erase(0, semi + 1);
- }
- // finally add the last item
- names.push_back(std::move(namestr));
- }
+//-------------------------------------------------
+// add_entry - add an entry to the current
+// options set
+//-------------------------------------------------
- // we might be called with an existing entry
- entry::shared_ptr existing_entry;
- do
+void core_options::add_entry(const char *name, const char *description, uint32_t flags, const char *defvalue, bool override_existing)
+{
+ // allocate a new entry
+ auto newentry = global_alloc(entry(name, description, flags, defvalue));
+ if (newentry->name() != nullptr)
{
- for (const std::string &name : names)
- {
- existing_entry = get_entry(name.c_str());
- if (existing_entry)
- break;
- }
-
- if (existing_entry)
+ // see if we match an existing entry
+ auto checkentry = m_entrymap.find(newentry->name());
+ if (checkentry != m_entrymap.end())
{
+ entry *existing = checkentry->second;
+ // if we're overriding existing entries, then remove the old one
if (override_existing)
- remove_entry(*existing_entry);
+ m_entrylist.remove(*existing);
+
+ // otherwise, just override the default and current values and throw out the new entry
else
+ {
+ existing->set_default_value(newentry->value());
+ global_free(newentry);
return;
+ }
}
- } while (existing_entry);
-
- // set the default value
- std::string defdata = opt.defvalue ? opt.defvalue : "";
-
- // create and add the entry
- add_entry(
- std::move(names),
- opt.description,
- opt.type,
- std::move(defdata),
- std::move(minimum),
- std::move(maximum));
-}
-
-
-//-------------------------------------------------
-// add_entry
-//-------------------------------------------------
-
-void core_options::add_entry(std::vector<std::string> &&names, const char *description, option_type type, std::string &&default_value, std::string &&minimum, std::string &&maximum)
-{
- // create the entry
- entry::shared_ptr new_entry = std::make_shared<simple_entry>(
- std::move(names),
- description,
- type,
- std::move(default_value),
- std::move(minimum),
- std::move(maximum));
-
- // and add it
- add_entry(std::move(new_entry));
-}
+ // need to call value_changed() with initial value
+ value_changed(newentry->name(), newentry->value());
+ }
-//-------------------------------------------------
-// add_header
-//-------------------------------------------------
-
-void core_options::add_header(const char *description)
-{
- add_entry(std::vector<std::string>(), description, option_type::HEADER);
+ // add us to the list and maps
+ append_entry(*newentry);
}
@@ -531,8 +293,8 @@ void core_options::add_header(const char *description)
void core_options::add_entries(const options_entry *entrylist, bool override_existing)
{
// loop over entries until we hit a nullptr name
- for (int i = 0; entrylist[i].name || entrylist[i].type == option_type::HEADER; i++)
- add_entry(entrylist[i], override_existing);
+ for ( ; entrylist->name != nullptr || (entrylist->flags & OPTION_HEADER) != 0; entrylist++)
+ add_entry(*entrylist, override_existing);
}
@@ -543,8 +305,13 @@ void core_options::add_entries(const options_entry *entrylist, bool override_exi
void core_options::set_default_value(const char *name, const char *defvalue)
{
+ // find the entry and bail if we can't
+ auto curentry = m_entrymap.find(name);
+ if (curentry == m_entrymap.end())
+ return;
+
// update the data and default data
- get_entry(name)->set_default_value(defvalue);
+ curentry->second->set_default_value(defvalue);
}
@@ -555,8 +322,13 @@ void core_options::set_default_value(const char *name, const char *defvalue)
void core_options::set_description(const char *name, const char *description)
{
+ // find the entry and bail if we can't
+ auto curentry = m_entrymap.find(name);
+ if (curentry == m_entrymap.end())
+ return;
+
// update the data and default data
- get_entry(name)->set_description(description);
+ curentry->second->set_description(description);
}
@@ -565,12 +337,10 @@ void core_options::set_description(const char *name, const char *description)
// command line arguments
//-------------------------------------------------
-void core_options::parse_command_line(std::vector<std::string> &args, int priority)
+bool core_options::parse_command_line(std::vector<std::string> &args, int priority, std::string &error_string)
{
- std::ostringstream error_stream;
- condition_type condition = condition_type::NONE;
-
// reset the errors and the command
+ error_string.clear();
m_command.clear();
// iterate through arguments
@@ -584,8 +354,8 @@ void core_options::parse_command_line(std::vector<std::string> &args, int priori
const char *optionname = is_unadorned ? core_options::unadorned(unadorned_index++) : &curarg[1];
// find our entry; if not found, continue
- auto curentry = get_entry(optionname);
- if (!curentry)
+ auto curentry = m_entrymap.find(optionname);
+ if (curentry == m_entrymap.end())
{
// we need to relocate this option
if (new_argc != arg)
@@ -606,19 +376,21 @@ void core_options::parse_command_line(std::vector<std::string> &args, int priori
}
// process commands first
- if (curentry->type() == option_type::COMMAND)
+ if (curentry->second->type() == OPTION_COMMAND)
{
// can only have one command
if (!m_command.empty())
- throw options_error_exception("Error: multiple commands specified -%s and %s\n", m_command, curarg);
-
- m_command = curentry->name();
+ {
+ error_string.append(string_format("Error: multiple commands specified -%s and %s\n", m_command, curarg));
+ return false;
+ }
+ m_command = curentry->second->name();
continue;
}
// get the data for this argument, special casing booleans
std::string newdata;
- if (curentry->type() == option_type::BOOLEAN)
+ if (curentry->second->type() == OPTION_BOOLEAN)
{
newdata = (strncmp(&curarg[1], "no", 2) == 0) ? "0" : "1";
}
@@ -633,18 +405,17 @@ void core_options::parse_command_line(std::vector<std::string> &args, int priori
}
else
{
- throw options_error_exception("Error: option %s expected a parameter\n", curarg);
+ error_string.append(string_format("Error: option %s expected a parameter\n", curarg));
+ return false;
}
args[arg].clear();
// set the new data
- prettify_and_set_value(*curentry, std::move(newdata), priority, error_stream, condition);
+ validate_and_set_data(*curentry->second, std::move(newdata), priority, error_string);
}
args.resize(new_argc);
-
- // did we have any errors that may need to be aggregated?
- throw_options_exception_if_appropriate(condition, error_stream);
+ return true;
}
@@ -653,11 +424,8 @@ void core_options::parse_command_line(std::vector<std::string> &args, int priori
// an INI file
//-------------------------------------------------
-void core_options::parse_ini_file(util::core_file &inifile, int priority, bool always_override)
+bool core_options::parse_ini_file(util::core_file &inifile, int priority, int ignore_priority, std::string &error_string)
{
- std::ostringstream error_stream;
- condition_type condition = condition_type::NONE;
-
// loop over lines in the file
char buffer[4096];
while (inifile.gets(buffer, ARRAY_LENGTH(buffer)) != nullptr)
@@ -681,8 +449,7 @@ void core_options::parse_ini_file(util::core_file &inifile, int priority, bool a
// if we hit the end early, print a warning and continue
if (*temp == 0)
{
- condition = std::max(condition, condition_type::WARN);
- util::stream_format(error_stream, "Warning: invalid line in INI: %s", buffer);
+ error_string.append(string_format("Warning: invalid line in INI: %s", buffer));
continue;
}
@@ -702,68 +469,77 @@ void core_options::parse_ini_file(util::core_file &inifile, int priority, bool a
*temp = 0;
// find our entry
- entry::shared_ptr curentry = get_entry(optionname);
- if (!curentry)
+ auto curentry = m_entrymap.find(optionname);
+ if (curentry == m_entrymap.end())
{
- condition = std::max(condition, condition_type::WARN);
- util::stream_format(error_stream, "Warning: unknown option in INI: %s\n", optionname);
+ if (priority >= ignore_priority)
+ error_string.append(string_format("Warning: unknown option in INI: %s\n", optionname));
continue;
}
// set the new data
- prettify_and_set_value(*curentry, optiondata, priority, error_stream, condition);
+ validate_and_set_data(*curentry->second, optiondata, priority, error_string);
}
-
- // did we have any errors that may need to be aggregated?
- throw_options_exception_if_appropriate(condition, error_stream);
+ return true;
}
//-------------------------------------------------
-// throw_options_exception_if_appropriate
+// pluck_from_command_line - finds a specific
+// value from within a command line
//-------------------------------------------------
-void core_options::throw_options_exception_if_appropriate(core_options::condition_type condition, std::ostringstream &error_stream)
+bool core_options::pluck_from_command_line(std::vector<std::string> &args, const std::string &optionname, std::string &result)
{
- switch(condition)
- {
- case condition_type::NONE:
- // do nothing
- break;
+ // 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());
- case condition_type::WARN:
- throw options_warning_exception(error_stream.str());
+ // 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);
+ }
- case condition_type::ERR:
- throw options_warning_exception(error_stream.str());
+ // find each of the targets in the argv array
+ for (int i = 1; i < args.size() - 1; i++)
+ {
+ auto const iter = std::find_if(
+ targets.begin(),
+ targets.end(),
+ [&args, i](const std::string &targ) { return targ == args[i]; });
+ if (iter != targets.end())
+ {
+ // get the result
+ result = std::move(args[i + 1]);
- default:
- // should not get here
- throw false;
+ // remove this arguments from the list
+ auto const pos = std::next(args.begin(), i);
+ args.erase(pos, std::next(pos, 2));
+ return true;
+ }
}
+
+ result.clear();
+ return false;
}
//-------------------------------------------------
-// copy_from
+// revert - revert options at or below a certain
+// priority back to their defaults
//-------------------------------------------------
-void core_options::copy_from(const core_options &that)
+void core_options::revert(int priority_hi, int priority_lo)
{
- for (auto &dest_entry : m_entries)
- {
- if (dest_entry->names().size() > 0)
- {
- // identify the source entry
- const entry::shared_ptr source_entry = that.get_entry(dest_entry->name());
- if (source_entry)
- {
- const char *value = source_entry->value();
- if (value)
- dest_entry->set_value(value, source_entry->priority(), true);
- }
- }
- }
+ // iterate over options and revert to defaults if below the given priority
+ for (entry &curentry : m_entrylist)
+ curentry.revert(priority_hi, priority_lo);
}
@@ -784,34 +560,47 @@ std::string core_options::output_ini(const core_options *diff) const
std::string overridden_value;
// loop over all items
- for (auto &curentry : m_entries)
+ for (entry &curentry : m_entrylist)
{
- if (curentry->type() == option_type::HEADER)
+ const char *name = curentry.name();
+ const char *value;
+ switch (override_get_value(name, overridden_value))
{
- // header: record description
- last_header = curentry->description();
+ case override_get_value_result::NONE:
+ default:
+ value = curentry.value();
+ break;
+
+ case override_get_value_result::SKIP:
+ continue;
+
+ case override_get_value_result::OVERRIDE:
+ value = overridden_value.c_str();
+ break;
}
- else
+ bool is_unadorned = false;
+
+ // check if it's unadorned
+ if (name && strlen(name) && !strcmp(name, core_options::unadorned(unadorned_index)))
{
- const std::string &name(curentry->name());
- const char *value(curentry->value());
+ unadorned_index++;
+ is_unadorned = true;
+ }
- // check if it's unadorned
- bool is_unadorned = false;
- if (name == core_options::unadorned(unadorned_index))
- {
- unadorned_index++;
- is_unadorned = true;
- }
+ // header: record description
+ if (curentry.is_header())
+ last_header = curentry.description();
- // output entries for all non-command items (items with value)
- if (value)
+ // otherwise, output entries for all non-command items
+ else if (!curentry.is_command())
+ {
+ if (!curentry.is_internal())
{
// look up counterpart in diff, if diff is specified
- if (!diff || strcmp(value, diff->value(name.c_str())))
+ if (diff == nullptr || strcmp(value, diff->value(name)) != 0)
{
// output header, if we have one
- if (last_header)
+ if (last_header != nullptr)
{
if (num_valid_headers++)
buffer << '\n';
@@ -822,7 +611,7 @@ std::string core_options::output_ini(const core_options *diff) const
// and finally output the data, skip if unadorned
if (!is_unadorned)
{
- if (strchr(value, ' '))
+ if (strchr(value, ' ') != nullptr)
util::stream_format(buffer, "%-25s \"%s\"\n", name, value);
else
util::stream_format(buffer, "%-25s %s\n", name, value);
@@ -845,15 +634,15 @@ std::string core_options::output_help() const
std::ostringstream buffer;
// loop over all items
- for (auto &curentry : m_entries)
+ for (entry &curentry : m_entrylist)
{
// header: just print
- if (curentry->type() == option_type::HEADER)
- util::stream_format(buffer, "\n#\n# %s\n#\n", curentry->description());
+ if (curentry.is_header())
+ util::stream_format(buffer, "\n#\n# %s\n#\n", curentry.description());
// otherwise, output entries for all non-deprecated items
- else if (curentry->description() != nullptr)
- util::stream_format(buffer, "-%-20s%s\n", curentry->name(), curentry->description());
+ else if (curentry.description() != nullptr)
+ util::stream_format(buffer, "-%-20s%s\n", curentry.name(), curentry.description());
}
return buffer.str();
}
@@ -863,9 +652,10 @@ std::string core_options::output_help() const
// value - return the raw option value
//-------------------------------------------------
-const char *core_options::value(const char *option) const
+const char *core_options::value(const char *name) const
{
- return get_entry(option)->value();
+ auto curentry = m_entrymap.find(name);
+ return (curentry != m_entrymap.end()) ? curentry->second->value() : "";
}
@@ -873,143 +663,251 @@ const char *core_options::value(const char *option) const
// description - return description of option
//-------------------------------------------------
-const char *core_options::description(const char *option) const
+const char *core_options::description(const char *name) const
{
- return get_entry(option)->description();
+ auto curentry = m_entrymap.find(name);
+ return (curentry != m_entrymap.end()) ? curentry->second->description() : "";
}
-//**************************************************************************
-// LEGACY
-//**************************************************************************
-
//-------------------------------------------------
-// set_value - set the raw option value
+// priority - return the priority of option
//-------------------------------------------------
-void core_options::set_value(const std::string &name, const std::string &value, int priority)
+int core_options::priority(const char *name) const
{
- set_value(name, std::string(value), priority);
+ auto curentry = m_entrymap.find(name);
+ return (curentry != m_entrymap.end()) ? curentry->second->priority() : 0;
}
-void core_options::set_value(const std::string &name, std::string &&value, int priority)
-{
- get_entry(name)->set_value(std::move(value), priority);
-}
-void core_options::set_value(const std::string &name, int value, int priority)
-{
- set_value(name, string_format("%d", value), priority);
-}
+//-------------------------------------------------
+// exists - return if option exists in list
+//-------------------------------------------------
-void core_options::set_value(const std::string &name, float value, int priority)
+bool core_options::exists(const char *name) const
{
- set_value(name, string_format("%f", value), priority);
+ return (m_entrymap.find(name) != m_entrymap.end());
}
//-------------------------------------------------
-// remove_entry - remove an entry from our list
-// and map
+// set_value - set the raw option value
//-------------------------------------------------
-void core_options::remove_entry(core_options::entry &delentry)
+bool core_options::set_value(const char *name, const char *value, int priority, std::string &error_string)
{
- // find this in m_entries
- auto iter = std::find_if(
- m_entries.begin(),
- m_entries.end(),
- [&delentry](const auto &x) { return &*x == &delentry; });
- assert(iter != m_entries.end());
+ // find the entry first
+ auto curentry = m_entrymap.find(name);
+ if (curentry == m_entrymap.end())
+ {
+ error_string.append(string_format("Attempted to set unknown option %s\n", name));
+ return false;
+ }
- // erase each of the items out of the entry map
- for (const std::string &name : delentry.names())
- m_entrymap.erase(name);
+ // validate and set the item normally
+ return validate_and_set_data(*curentry->second, value, priority, error_string);
+}
- // finally erase it
- m_entries.erase(iter);
+bool core_options::set_value(const char *name, int value, int priority, std::string &error_string)
+{
+ return set_value(name, string_format("%d", value).c_str(), priority, error_string);
}
+bool core_options::set_value(const char *name, float value, int priority, std::string &error_string)
+{
+ return set_value(name, string_format("%f", value).c_str(), priority, error_string);
+}
-//-------------------------------------------------
-// prettify_and_set_value
-//-------------------------------------------------
-void core_options::prettify_and_set_value(entry &curentry, std::string &&data, int priority, std::ostream &error_stream, condition_type &condition)
+void core_options::set_flag(const char *name, uint32_t mask, uint32_t flag)
{
- // trim any whitespace
- strtrimspace(data);
-
- // trim quotes
- if (data.find_first_of('"') == 0 && data.find_last_of('"') == data.length() - 1)
+ // find the entry first
+ auto curentry = m_entrymap.find(name);
+ if ( curentry == m_entrymap.end())
{
- data.erase(0, 1);
- data.erase(data.length() - 1, 1);
+ return;
}
+ curentry->second->set_flag(mask, flag);
+}
- // this is called when parsing a command line or an INI - we want to catch the option_exception and write
- // any exception messages to the error stream
- try
- {
- curentry.set_value(std::move(data), priority);
- }
- catch (options_warning_exception &ex)
- {
- // we want to aggregate option exceptions
- error_stream << ex.message();
- condition = std::max(condition, condition_type::WARN);
- }
- catch (options_error_exception &ex)
+void core_options::mark_changed(const char* name)
+{
+ // find the entry first
+ auto curentry = m_entrymap.find(name);
+ if (curentry == m_entrymap.end())
{
- // we want to aggregate option exceptions
- error_stream << ex.message();
- condition = std::max(condition, condition_type::ERR);
+ return;
}
+ curentry->second->mark_changed();
}
-
//-------------------------------------------------
-// get_entry
+// reset - reset the options state, removing
+// everything
//-------------------------------------------------
-const core_options::entry::shared_ptr core_options::get_entry(const std::string &name) const
+void core_options::reset()
{
- auto curentry = m_entrymap.find(name);
- return (curentry != m_entrymap.end()) ? curentry->second.lock() : nullptr;
+ m_entrylist.reset();
+ m_entrymap.clear();
}
-core_options::entry::shared_ptr core_options::get_entry(const std::string &name)
+
+//-------------------------------------------------
+// append_entry - append an entry to our list
+// and index it in the map
+//-------------------------------------------------
+
+void core_options::append_entry(core_options::entry &newentry)
{
- auto curentry = m_entrymap.find(name);
- return (curentry != m_entrymap.end()) ? curentry->second.lock() : nullptr;
+ m_entrylist.append(newentry);
+
+ // if we have names, add them to the map
+ for (int name = 0; name < ARRAY_LENGTH(newentry.m_name); name++)
+ if (newentry.name(name) != nullptr)
+ {
+ m_entrymap.insert(std::make_pair(newentry.name(name), &newentry));
+ // for boolean options add a "no" variant as well
+ if (newentry.type() == OPTION_BOOLEAN)
+ m_entrymap.insert(std::make_pair(std::string("no").append(newentry.name(name)), &newentry));
+ }
}
//-------------------------------------------------
-// set_value_changed_handler
+// remove_entry - remove an entry from our list
+// and map
//-------------------------------------------------
-void core_options::set_value_changed_handler(const std::string &name, std::function<void(const char *)> &&handler)
+void core_options::remove_entry(core_options::entry &delentry)
{
- get_entry(name)->set_value_changed_handler(std::move(handler));
+ // remove all names from the map
+ for (int name = 0; name < ARRAY_LENGTH(delentry.m_name); name++)
+ if (!delentry.m_name[name].empty())
+ {
+ auto entry = m_entrymap.find(delentry.m_name[name]);
+ if (entry!= m_entrymap.end()) m_entrymap.erase(entry);
+ }
+
+ // remove the entry from the list
+ m_entrylist.remove(delentry);
}
+/**
+ * @fn void core_options::copyfrom(const core_options &src)
+ *
+ * @brief -------------------------------------------------
+ * copyfrom - copy options from another set
+ * -------------------------------------------------.
+ *
+ * @param src Source for the.
+ */
-//-------------------------------------------------
-// header_exists
-//-------------------------------------------------
+void core_options::copyfrom(const core_options &src)
+{
+ // reset ourselves first
+ reset();
+
+ // iterate through the src options and make our own
+ for (entry &curentry : src.m_entrylist)
+ append_entry(*global_alloc(entry(curentry.name(), curentry.description(), curentry.flags(), curentry.default_value())));
+}
-bool core_options::header_exists(const char *description) const
+/**
+ * @fn bool core_options::validate_and_set_data(core_options::entry &curentry, const char *newdata, int priority, std::string &error_string)
+ *
+ * @brief -------------------------------------------------
+ * validate_and_set_data - make sure the data is of the appropriate type and within
+ * range, then set it
+ * -------------------------------------------------.
+ *
+ * @param [in,out] curentry The curentry.
+ * @param newdata The newdata.
+ * @param priority The priority.
+ * @param [in,out] error_string The error string.
+ *
+ * @return true if it succeeds, false if it fails.
+ */
+
+bool core_options::validate_and_set_data(core_options::entry &curentry, std::string &&data, int priority, std::string &error_string)
{
- auto iter = std::find_if(
- m_entries.begin(),
- m_entries.end(),
- [description](const auto &entry)
+ // trim any whitespace
+ strtrimspace(data);
+
+ // trim quotes
+ if (data.find_first_of('"') == 0 && data.find_last_of('"') == data.length() - 1)
+ {
+ data.erase(0, 1);
+ data.erase(data.length() - 1, 1);
+ }
+
+ // let derived classes override how we set this data
+ if (override_set_value(curentry.name(), data))
+ return true;
+
+ // validate the type of data and optionally the range
+ float fval;
+ int ival;
+ switch (curentry.type())
+ {
+ // booleans must be 0 or 1
+ case OPTION_BOOLEAN:
+ if (sscanf(data.c_str(), "%d", &ival) != 1 || ival < 0 || ival > 1)
+ {
+ error_string.append(string_format("Illegal boolean value for %s: \"%s\"; reverting to %s\n", curentry.name(), data.c_str(), curentry.value()));
+ return false;
+ }
+ break;
+
+ // integers must be integral
+ case OPTION_INTEGER:
+ if (sscanf(data.c_str(), "%d", &ival) != 1)
+ {
+ error_string.append(string_format("Illegal integer value for %s: \"%s\"; reverting to %s\n", curentry.name(), data.c_str(), curentry.value()));
+ return false;
+ }
+ if (curentry.has_range() && (ival < atoi(curentry.minimum()) || ival > atoi(curentry.maximum())))
{
- return entry->type() == option_type::HEADER
- && entry->description()
- && !strcmp(entry->description(), description);
- });
+ error_string.append(string_format("Out-of-range integer value for %s: \"%s\" (must be between %s and %s); reverting to %s\n", curentry.name(), data.c_str(), curentry.minimum(), curentry.maximum(), curentry.value()));
+ return false;
+ }
+ break;
- return iter != m_entries.end();
+ // floating-point values must be numeric
+ case OPTION_FLOAT:
+ if (sscanf(data.c_str(), "%f", &fval) != 1)
+ {
+ error_string.append(string_format("Illegal float value for %s: \"%s\"; reverting to %s\n", curentry.name(), data.c_str(), curentry.value()));
+ return false;
+ }
+ if (curentry.has_range() && ((double) fval < atof(curentry.minimum()) || (double) fval > atof(curentry.maximum())))
+ {
+ error_string.append(string_format("Out-of-range float value for %s: \"%s\" (must be between %s and %s); reverting to %s\n", curentry.name(), data.c_str(), curentry.minimum(), curentry.maximum(), curentry.value()));
+ return false;
+ }
+ break;
+
+ // strings can be anything
+ case OPTION_STRING:
+ break;
+
+ // anything else is invalid
+ case OPTION_INVALID:
+ case OPTION_HEADER:
+ default:
+ error_string.append(string_format("Attempted to set invalid option %s\n", curentry.name()));
+ return false;
+ }
+
+ // set the data
+ curentry.set_value(data.c_str(), priority);
+ value_changed(curentry.name(), data);
+ return true;
+}
+
+core_options::entry *core_options::get_entry(const char *name) const
+{
+ auto curentry = m_entrymap.find(name);
+ return (curentry != m_entrymap.end()) ? curentry->second : nullptr;
}
diff --git a/src/lib/util/options.h b/src/lib/util/options.h
index a36ff95cab6..edf7f8600c8 100644
--- a/src/lib/util/options.h
+++ b/src/lib/util/options.h
@@ -13,13 +13,26 @@
#include "corefile.h"
#include <unordered_map>
-#include <sstream>
+
//**************************************************************************
// CONSTANTS
//**************************************************************************
+// option types
+const uint32_t OPTION_TYPE_MASK = 0x0007; // up to 8 different types
+enum
+{
+ OPTION_INVALID, // invalid
+ OPTION_HEADER, // a header item
+ OPTION_COMMAND, // a command
+ OPTION_BOOLEAN, // boolean option
+ OPTION_INTEGER, // integer option
+ OPTION_FLOAT, // floating-point option
+ OPTION_STRING // string option
+};
+
// option priorities
const int OPTION_PRIORITY_DEFAULT = 0; // defaults are at 0 priority
const int OPTION_PRIORITY_LOW = 50; // low priority
@@ -27,55 +40,20 @@ const int OPTION_PRIORITY_NORMAL = 100; // normal priority
const int OPTION_PRIORITY_HIGH = 150; // high priority
const int OPTION_PRIORITY_MAXIMUM = 255; // maximum priority
+const uint32_t OPTION_FLAG_INTERNAL = 0x40000000;
+
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
-struct options_entry;
-
-// exception thrown by core_options when an illegal request is made
-class options_exception : public std::exception
-{
-public:
- const std::string &message() const { return m_message; }
- virtual const char *what() const noexcept override { return message().c_str(); }
-
-protected:
- options_exception(std::string &&message);
-
-private:
- std::string m_message;
-};
-
-class options_warning_exception : public options_exception
-{
-public:
- template <typename... Params> options_warning_exception(const char *fmt, Params &&...args)
- : options_warning_exception(util::string_format(fmt, std::forward<Params>(args)...))
- {
- }
-
- options_warning_exception(std::string &&message);
- options_warning_exception(const options_warning_exception &) = default;
- options_warning_exception(options_warning_exception &&) = default;
- options_warning_exception& operator=(const options_warning_exception &) = default;
- options_warning_exception& operator=(options_warning_exception &&) = default;
-};
-
-class options_error_exception : public options_exception
+// static structure describing a single option with its description and default value
+struct options_entry
{
-public:
- template <typename... Params> options_error_exception(const char *fmt, Params &&...args)
- : options_error_exception(util::string_format(fmt, std::forward<Params>(args)...))
- {
- }
-
- options_error_exception(std::string &&message);
- options_error_exception(const options_error_exception &) = default;
- options_error_exception(options_error_exception &&) = default;
- options_error_exception& operator=(const options_error_exception &) = default;
- options_error_exception& operator=(options_error_exception &&) = default;
+ const char * name; // name on the command line
+ const char * defvalue; // default value of this argument
+ uint32_t flags; // flags to describe the option
+ const char * description; // description for -showusage
};
@@ -85,95 +63,94 @@ class core_options
static const int MAX_UNADORNED_OPTIONS = 16;
public:
- enum class option_type
- {
- INVALID, // invalid
- HEADER, // a header item
- COMMAND, // a command
- BOOLEAN, // boolean option
- INTEGER, // integer option
- FLOAT, // floating-point option
- STRING // string option
- };
-
// information about a single entry in the options
class entry
{
- public:
- typedef std::shared_ptr<entry> shared_ptr;
- typedef std::weak_ptr<entry> weak_ptr;
-
- // constructor/destructor
- entry(std::vector<std::string> &&names, option_type type = option_type::STRING, const char *description = nullptr);
- entry(std::string &&name, option_type type = option_type::STRING, const char *description = nullptr);
- entry(const entry &) = delete;
- entry(entry &&) = delete;
- entry& operator=(const entry &) = delete;
- entry& operator=(entry &&) = delete;
- virtual ~entry();
-
- // accessors
- const std::vector<std::string> &names() const { return m_names; }
- const std::string &name() const { return m_names[0]; }
- virtual const char *value() const;
- int priority() const { return m_priority; }
- option_type type() const { return m_type; }
- const char *description() const { return m_description; }
- virtual const std::string &default_value() const;
- virtual const char *minimum() const;
- virtual const char *maximum() const;
- bool has_range() const;
+ friend class core_options;
+ friend class simple_list<entry>;
- // mutators
- void set_value(std::string &&newvalue, int priority, bool always_override = false);
- virtual void set_default_value(std::string &&newvalue);
- void set_description(const char *description) { m_description = description; }
- void set_value_changed_handler(std::function<void(const char *)> &&handler) { m_value_changed_handler = std::move(handler); }
+ // construction/destruction
+ entry(const char *name, const char *description, uint32_t flags = 0, const char *defvalue = nullptr);
- protected:
- virtual void internal_set_value(std::string &&newvalue) = 0;
+ public:
+ // getters
+ entry *next() const { return m_next; }
+ const char *name(int index = 0) const { return (index < ARRAY_LENGTH(m_name) && !m_name[index].empty()) ? m_name[index].c_str() : nullptr; }
+ const char *description() const { return m_description; }
+ const char *value() const { return m_data.c_str(); }
+ const char *default_value() const { return m_defdata.c_str(); }
+ const char *minimum() const { return m_minimum.c_str(); }
+ const char *maximum() const { return m_maximum.c_str(); }
+ int type() const { return (m_flags & OPTION_TYPE_MASK); }
+ uint32_t flags() const { return m_flags; }
+ bool is_header() const { return type() == OPTION_HEADER; }
+ bool is_command() const { return type() == OPTION_COMMAND; }
+ bool is_internal() const { return m_flags & OPTION_FLAG_INTERNAL; }
+ bool has_range() const { return (!m_minimum.empty() && !m_maximum.empty()); }
+ int priority() const { return m_priority; }
+ bool is_changed() const { return m_changed; }
+
+ // setters
+ void set_value(const char *newvalue, int priority);
+ void set_default_value(const char *defvalue);
+ void set_description(const char *description);
+ void set_flag(uint32_t mask, uint32_t flag);
+ void mark_changed() { m_changed = true; }
+ void revert(int priority_hi, int priority_lo);
private:
- void validate(const std::string &value);
-
- std::vector<std::string> m_names;
- int m_priority;
- core_options::option_type m_type;
- const char * m_description;
- std::function<void(const char *)> m_value_changed_handler;
+ // internal state
+ entry * m_next; // link to the next data
+ uint32_t m_flags; // flags from the entry
+ bool m_error_reported; // have we reported an error on this option yet?
+ int m_priority; // priority of the data set
+ const char * m_description; // description for this item
+ std::string m_name[4]; // up to 4 names for the item
+ std::string m_data; // data for this item
+ std::string m_defdata; // default data for this item
+ std::string m_minimum; // minimum value
+ std::string m_maximum; // maximum value
+ bool m_changed; // changed flag
};
// construction/destruction
core_options();
- core_options(const core_options &) = delete;
- core_options(core_options &&) = delete;
- core_options& operator=(const core_options &) = delete;
- core_options& operator=(core_options &&) = delete;
+ core_options(const options_entry *entrylist);
+ core_options(const options_entry *entrylist1, const options_entry *entrylist2);
+ core_options(const options_entry *entrylist1, const options_entry *entrylist2, const options_entry *entrylist3);
+ core_options(const core_options &src);
virtual ~core_options();
+ // operators
+ core_options &operator=(const core_options &rhs);
+ bool operator==(const core_options &rhs);
+ bool operator!=(const core_options &rhs);
+
// getters
+ entry *first() const { return m_entrylist.first(); }
const std::string &command() const { return m_command; }
- const entry::shared_ptr get_entry(const std::string &name) const;
- entry::shared_ptr get_entry(const std::string &name);
- const std::vector<entry::shared_ptr> &entries() const { return m_entries; }
- bool exists(const std::string &name) const { return get_entry(name) != nullptr; }
- bool header_exists(const char *description) const;
+ entry *get_entry(const char *name) const;
+
+ // range iterators
+ using auto_iterator = simple_list<entry>::auto_iterator;
+ auto_iterator begin() const { return m_entrylist.begin(); }
+ auto_iterator end() const { return m_entrylist.end(); }
// configuration
- void add_entry(entry::shared_ptr &&entry, const char *after_header = nullptr);
- void add_entry(const options_entry &entry, bool override_existing = false);
- void add_entry(std::vector<std::string> &&names, const char *description, option_type type, std::string &&default_value = "", std::string &&minimum = "", std::string &&maximum = "");
- void add_header(const char *description);
+ void add_entry(const char *name, const char *description, uint32_t flags = 0, const char *defvalue = nullptr, bool override_existing = false);
+ void add_entry(const options_entry &data, bool override_existing = false) { add_entry(data.name, data.description, data.flags, data.defvalue, override_existing); }
void add_entries(const options_entry *entrylist, bool override_existing = false);
void set_default_value(const char *name, const char *defvalue);
void set_description(const char *name, const char *description);
void remove_entry(entry &delentry);
- void set_value_changed_handler(const std::string &name, std::function<void(const char *)> &&handler);
// parsing/input
- void parse_command_line(std::vector<std::string> &args, int priority);
- void parse_ini_file(util::core_file &inifile, int priority, bool always_override);
- void copy_from(const core_options &that);
+ bool parse_command_line(std::vector<std::string> &args, int priority, std::string &error_string);
+ bool parse_ini_file(util::core_file &inifile, int priority, int ignore_priority, std::string &error_string);
+ bool pluck_from_command_line(std::vector<std::string> &args, const std::string &name, std::string &result);
+
+ // reverting
+ void revert(int priority_hi = OPTION_PRIORITY_MAXIMUM, int priority_lo = OPTION_PRIORITY_DEFAULT);
// output
std::string output_ini(const core_options *diff = nullptr) const;
@@ -182,88 +159,51 @@ public:
// reading
const char *value(const char *option) const;
const char *description(const char *option) const;
- bool bool_value(const char *option) const { return int_value(option) != 0; }
- int int_value(const char *option) const { return atoi(value(option)); }
- float float_value(const char *option) const { return atof(value(option)); }
+ int priority(const char *option) const;
+ bool bool_value(const char *name) const { return (atoi(value(name)) != 0); }
+ int int_value(const char *name) const { return atoi(value(name)); }
+ float float_value(const char *name) const { return atof(value(name)); }
+ bool exists(const char *name) const;
// setting
- void set_value(const std::string &name, const std::string &value, int priority);
- void set_value(const std::string &name, std::string &&value, int priority);
- void set_value(const std::string &name, int value, int priority);
- void set_value(const std::string &name, float value, int priority);
+ bool set_value(const char *name, const char *value, int priority, std::string &error_string);
+ bool set_value(const char *name, int value, int priority, std::string &error_string);
+ bool set_value(const char *name, float value, int priority, std::string &error_string);
+ void set_flag(const char *name, uint32_t mask, uint32_t flags);
+ void mark_changed(const char *name);
// misc
static const char *unadorned(int x = 0) { return s_option_unadorned[std::min(x, MAX_UNADORNED_OPTIONS - 1)]; }
+ int options_count() const { return m_entrylist.count(); }
-private:
- class simple_entry : public entry
- {
- public:
- // construction/destruction
- simple_entry(std::vector<std::string> &&names, const char *description, core_options::option_type type, std::string &&defdata, std::string &&minimum, std::string &&maximum);
- simple_entry(const simple_entry &) = delete;
- simple_entry(simple_entry &&) = delete;
- simple_entry& operator=(const simple_entry &) = delete;
- simple_entry& operator=(simple_entry &&) = delete;
- ~simple_entry();
-
- // getters
- virtual const char *value() const override;
- virtual const char *minimum() const override;
- virtual const char *maximum() const override;
- virtual const std::string &default_value() const override;
-
- virtual void set_default_value(std::string &&newvalue) override;
-
- protected:
- virtual void internal_set_value(std::string &&newvalue) override;
-
- private:
- // internal state
- std::string m_data; // data for this item
- std::string m_defdata; // default data for this item
- std::string m_minimum; // minimum value
- std::string m_maximum; // maximum value
- };
-
- // used internally in core_options
- enum class condition_type
+protected:
+ // This is a hook to allow option value retrieval to be overridden for various reasons; this is a crude
+ // extensibility mechanism that should really be replaced by something better
+ enum class override_get_value_result
{
NONE,
- WARN,
- ERR
+ OVERRIDE,
+ SKIP
};
+ virtual void value_changed(const std::string &name, const std::string &value) {}
+ virtual override_get_value_result override_get_value(const char *name, std::string &value) const { return override_get_value_result::NONE; }
+ virtual bool override_set_value(const char *name, const std::string &value) { return false; }
+
+private:
// internal helpers
- void add_to_entry_map(std::string &&name, entry::shared_ptr &entry);
- void prettify_and_set_value(entry &curentry, std::string &&data, int priority, std::ostream &error_stream, condition_type &condition);
- void throw_options_exception_if_appropriate(condition_type condition, std::ostringstream &error_stream);
+ void reset();
+ void append_entry(entry &newentry);
+ void copyfrom(const core_options &src);
+ bool validate_and_set_data(entry &curentry, std::string &&newdata, int priority, std::string &error_string);
// internal state
- std::vector<entry::shared_ptr> m_entries; // cannonical list of entries
- std::unordered_map<std::string, entry::weak_ptr> m_entrymap; // map for fast lookup
- std::string m_command; // command found
- static const char *const s_option_unadorned[]; // array of unadorned option "names"
-};
-
-
-// static structure describing a single option with its description and default value
-struct options_entry
-{
- const char * name; // name on the command line
- const char * defvalue; // default value of this argument
- core_options::option_type type; // type of option
- const char * description; // description for -showusage
+ simple_list<entry> m_entrylist; // head of list of entries
+ std::unordered_map<std::string,entry *> m_entrymap; // map for fast lookup
+ std::string m_command; // command found
+ static const char *const s_option_unadorned[]; // array of unadorned option "names"
};
-// legacy option types
-const core_options::option_type OPTION_INVALID = core_options::option_type::INVALID;
-const core_options::option_type OPTION_HEADER = core_options::option_type::HEADER;
-const core_options::option_type OPTION_COMMAND = core_options::option_type::COMMAND;
-const core_options::option_type OPTION_BOOLEAN = core_options::option_type::BOOLEAN;
-const core_options::option_type OPTION_INTEGER = core_options::option_type::INTEGER;
-const core_options::option_type OPTION_FLOAT = core_options::option_type::FLOAT;
-const core_options::option_type OPTION_STRING = core_options::option_type::STRING;
#endif // MAME_LIB_UTIL_OPTIONS_H
diff --git a/src/osd/modules/lib/osdobj_common.h b/src/osd/modules/lib/osdobj_common.h
index 2c2f750fdbe..df8096840cf 100644
--- a/src/osd/modules/lib/osdobj_common.h
+++ b/src/osd/modules/lib/osdobj_common.h
@@ -270,7 +270,7 @@ private:
// FIXME: should be elsewhere
osd_module *select_module_options(const core_options &opts, const std::string &opt_name)
{
- std::string opt_val = opts.exists(opt_name) ? opts.value(opt_name.c_str()) : "";
+ std::string opt_val = opts.value(opt_name.c_str());
if (opt_val.compare("auto")==0)
opt_val = "";
else if (!m_mod_man.type_has_name(opt_name.c_str(), opt_val.c_str()))
diff --git a/src/osd/modules/render/drawbgfx.cpp b/src/osd/modules/render/drawbgfx.cpp
index 31ddc58c145..2fb0d0b3a1e 100644
--- a/src/osd/modules/render/drawbgfx.cpp
+++ b/src/osd/modules/render/drawbgfx.cpp
@@ -85,6 +85,7 @@ renderer_bgfx::renderer_bgfx(std::shared_ptr<osd_window> w)
, m_avi_writer(nullptr)
, m_avi_target(nullptr)
{
+ m_options = downcast<osd_options &>(assert_window()->machine().options());
}
//============================================================
diff --git a/src/osd/sdl/sdlmain.cpp b/src/osd/sdl/sdlmain.cpp
index 10e57ec5766..31f65e2ba66 100644
--- a/src/osd/sdl/sdlmain.cpp
+++ b/src/osd/sdl/sdlmain.cpp
@@ -408,12 +408,14 @@ void sdl_osd_interface::init(running_machine &machine)
// determine if we are benchmarking, and adjust options appropriately
int bench = options().bench();
+ std::string error_string;
if (bench > 0)
{
- options().set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM);
- options().set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM);
- options().set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM);
- options().set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM);
+ options().set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string);
+ options().set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM, error_string);
+ options().set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM, error_string);
+ options().set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM, error_string);
+ assert(error_string.c_str()[0] == 0);
}
// Some driver options - must be before audio init!
diff --git a/src/osd/windows/winmain.cpp b/src/osd/windows/winmain.cpp
index 805a769d1b8..efec6700849 100644
--- a/src/osd/windows/winmain.cpp
+++ b/src/osd/windows/winmain.cpp
@@ -515,20 +515,23 @@ void windows_osd_interface::init(running_machine &machine)
// determine if we are benchmarking, and adjust options appropriately
int bench = options.bench();
+ std::string error_string;
if (bench > 0)
{
- options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM);
- options.set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM);
- options.set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM);
- options.set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM);
+ options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string);
+ options.set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM, error_string);
+ options.set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM, error_string);
+ options.set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM, error_string);
+ assert(error_string.empty());
}
// determine if we are profiling, and adjust options appropriately
int profile = options.profile();
if (profile > 0)
{
- options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM);
- options.set_value(OSDOPTION_NUMPROCESSORS, 1, OPTION_PRIORITY_MAXIMUM);
+ options.set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM, error_string);
+ options.set_value(OSDOPTION_NUMPROCESSORS, 1, OPTION_PRIORITY_MAXIMUM, error_string);
+ assert(error_string.empty());
}
// thread priority