summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/config.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/config.cpp')
-rw-r--r--src/emu/config.cpp345
1 files changed, 225 insertions, 120 deletions
diff --git a/src/emu/config.cpp b/src/emu/config.cpp
index 3574eb2d12e..8e9423415ee 100644
--- a/src/emu/config.cpp
+++ b/src/emu/config.cpp
@@ -2,33 +2,50 @@
// copyright-holders:Nicola Salmoria, Aaron Giles
/***************************************************************************
- config.c
+ config.cpp
Configuration file I/O.
+
***************************************************************************/
#include "emu.h"
-#include "emuopts.h"
-#include "drivenum.h"
#include "config.h"
+
+#include "drivenum.h"
+#include "emuopts.h"
+#include "fileio.h"
+
#include "xmlfile.h"
+#include <system_error>
+#include <utility>
+
#define DEBUG_CONFIG 0
+
//**************************************************************************
// CONFIGURATION MANAGER
//**************************************************************************
-//-------------------------------------------------
-// configuration_manager - constructor
-//-------------------------------------------------
+/*************************************
+ *
+ * Construction/destruction
+ *
+ *************************************/
+
+configuration_manager::configuration_manager(running_machine &machine) :
+ m_machine(machine),
+ m_typelist()
+{
+}
-configuration_manager::configuration_manager(running_machine &machine)
- : m_machine(machine)
+configuration_manager::~configuration_manager()
{
}
+
+
/*************************************
*
* Register to be involved in config
@@ -36,14 +53,9 @@ configuration_manager::configuration_manager(running_machine &machine)
*
*************************************/
-void configuration_manager::config_register(const char* nodename, config_load_delegate load, config_save_delegate save)
+void configuration_manager::config_register(std::string_view name, load_delegate &&load, save_delegate &&save)
{
- config_element element;
- element.name = nodename;
- element.load = load;
- element.save = save;
-
- m_typelist.push_back(element);
+ m_typelist.emplace(name, config_handler{ std::move(load), std::move(save) });
}
@@ -54,74 +66,58 @@ void configuration_manager::config_register(const char* nodename, config_load_de
*
*************************************/
-int configuration_manager::load_settings()
+bool configuration_manager::load_settings()
{
- const char *controller = machine().options().ctrlr();
- int loaded = 0;
-
- /* loop over all registrants and call their init function */
- for (auto type : m_typelist)
- type.load(config_type::INIT, nullptr);
+ // loop over all registrants and call their init function
+ for (auto const &type : m_typelist)
+ type.second.load(config_type::INIT, config_level::DEFAULT, nullptr);
- /* now load the controller file */
- if (controller[0] != 0)
+ // now load the controller file
+ char const *const controller = machine().options().ctrlr();
+ if (controller && *controller)
{
- /* open the config file */
emu_file file(machine().options().ctrlr_path(), OPEN_FLAG_READ);
- osd_printf_verbose("Attempting to parse: %s.cfg\n",controller);
- osd_file::error filerr = file.open(controller, ".cfg");
-
- if (filerr != osd_file::error::NONE)
- throw emu_fatalerror("Could not load controller file %s.cfg", controller);
-
- /* load the XML */
- if (!load_xml(file, config_type::CONTROLLER))
- throw emu_fatalerror("Could not load controller file %s.cfg", controller);
+ if (!attempt_load(machine().system(), file, std::string(controller) + ".cfg", config_type::CONTROLLER))
+ throw emu_fatalerror("Could not load controller configuration file %s.cfg", controller);
}
- /* next load the defaults file */
+ // next load the defaults file
emu_file file(machine().options().cfg_directory(), OPEN_FLAG_READ);
- osd_file::error filerr = file.open("default.cfg");
- osd_printf_verbose("Attempting to parse: default.cfg\n");
- if (filerr == osd_file::error::NONE)
- load_xml(file, config_type::DEFAULT);
-
- /* finally, load the game-specific file */
- filerr = file.open(machine().basename(), ".cfg");
- osd_printf_verbose("Attempting to parse: %s.cfg\n",machine().basename());
- if (filerr == osd_file::error::NONE)
- loaded = load_xml(file, config_type::GAME);
-
- /* loop over all registrants and call their final function */
- for (auto type : m_typelist)
- type.load(config_type::FINAL, nullptr);
-
- /* if we didn't find a saved config, return 0 so the main core knows that it */
- /* is the first time the game is run and it should display the disclaimer. */
+ attempt_load(machine().system(), file, "default.cfg", config_type::DEFAULT);
+
+ // load the system-specific file
+ bool const loaded = attempt_load(machine().system(), file, machine().basename() + ".cfg", config_type::SYSTEM);
+
+ // loop over all registrants and call their final function
+ for (auto const &type : m_typelist)
+ type.second.load(config_type::FINAL, config_level::DEFAULT, nullptr);
+
+ // if we didn't find a saved config, return false so the main core knows that it
+ // is the first time the system has been run
return loaded;
}
void configuration_manager::save_settings()
{
- /* loop over all registrants and call their init function */
- for (auto type : m_typelist)
- type.save(config_type::INIT, nullptr);
+ // loop over all registrants and call their init function
+ for (auto const &type : m_typelist)
+ type.second.save(config_type::INIT, nullptr);
- /* save the defaults file */
+ // save the defaults file
emu_file file(machine().options().cfg_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- osd_file::error filerr = file.open("default.cfg");
- if (filerr == osd_file::error::NONE)
+ std::error_condition filerr = file.open("default.cfg");
+ if (!filerr)
save_xml(file, config_type::DEFAULT);
- /* finally, save the game-specific file */
- filerr = file.open(machine().basename(), ".cfg");
- if (filerr == osd_file::error::NONE)
- save_xml(file, config_type::GAME);
+ // finally, save the system-specific file
+ filerr = file.open(machine().basename() + ".cfg");
+ if (!filerr)
+ save_xml(file, config_type::SYSTEM);
- /* loop over all registrants and call their final function */
- for (auto type : m_typelist)
- type.save(config_type::FINAL, nullptr);
+ // loop over all registrants and call their final function
+ for (auto const &type : m_typelist)
+ type.second.save(config_type::FINAL, nullptr);
}
@@ -132,66 +128,130 @@ void configuration_manager::save_settings()
*
*************************************/
-int configuration_manager::load_xml(emu_file &file, config_type which_type)
+bool configuration_manager::attempt_load(game_driver const &system, emu_file &file, std::string_view name, config_type which_type)
+{
+ std::error_condition const filerr = file.open(std::string(name));
+ if (std::errc::no_such_file_or_directory == filerr)
+ {
+ osd_printf_verbose("Configuration file %s not found\n", name);
+ return false;
+ }
+ else if (filerr)
+ {
+ osd_printf_warning(
+ "Error opening configuration file %s (%s:%d %s)\n",
+ name,
+ filerr.category().name(),
+ filerr.value(),
+ filerr.message());
+ return false;
+ }
+ else
+ {
+ osd_printf_verbose("Attempting to parse: %s\n", name);
+ return load_xml(system, file, which_type);
+ }
+}
+
+
+bool configuration_manager::load_xml(game_driver const &system, emu_file &file, config_type which_type)
{
- /* read the file */
+ // read the file
util::xml::file::ptr const root(util::xml::file::read(file, nullptr));
if (!root)
- return 0;
+ {
+ osd_printf_warning("Error parsing XML configuration file %s\n", file.filename());
+ return false;
+ }
- /* find the config node */
+ // find the config node
util::xml::data_node const *const confignode = root->get_child("mameconfig");
if (!confignode)
- return 0;
+ {
+ osd_printf_warning("Could not find root mameconfig element in configuration file %s\n", file.filename());
+ return false;
+ }
- /* validate the config data version */
+ // validate the config data version
int const version = confignode->get_attribute_int("version", 0);
if (version != CONFIG_VERSION)
- return 0;
+ {
+ osd_printf_warning("Configuration file %s has unsupported version %d\n", file.filename(), version);
+ return false;
+ }
- /* strip off all the path crap from the source filename */
- const char *srcfile = strrchr(machine().system().type.source(), '/');
+ // strip off all the path crap from the source filename
+ char const *srcfile = strrchr(system.type.source(), '/');
if (!srcfile)
- srcfile = strrchr(machine().system().type.source(), '\\');
+ srcfile = strrchr(system.type.source(), '\\');
if (!srcfile)
- srcfile = strrchr(machine().system().type.source(), ':');
+ srcfile = strrchr(system.type.source(), ':');
if (!srcfile)
- srcfile = machine().system().type.source();
+ srcfile = system.type.source();
else
srcfile++;
- /* loop over all system nodes in the file */
+ // loop over all system nodes in the file
int count = 0;
for (util::xml::data_node const *systemnode = confignode->get_child("system"); systemnode; systemnode = systemnode->get_next_sibling("system"))
{
- /* look up the name of the system here; skip if none */
- const char *name = systemnode->get_attribute_string("name", "");
+ // look up the name of the system here; skip if none
+ char const *name = systemnode->get_attribute_string("name", "");
- /* based on the file type, determine whether we have a match */
+ // based on the file type, determine whether we have a match
+ config_level level = config_level::DEFAULT;
switch (which_type)
{
- case config_type::GAME:
- /* only match on the specific game name */
- if (strcmp(name, machine().system().name) != 0)
+ case config_type::SYSTEM:
+ // only match on the specific system name
+ if (strcmp(name, system.name))
+ {
+ osd_printf_verbose("Ignoring configuration for system %s in system configuration file %s\n", name, file.filename());
continue;
+ }
+ level = config_level::SYSTEM;
break;
case config_type::DEFAULT:
- /* only match on default */
- if (strcmp(name, "default") != 0)
+ // only match on default
+ if (strcmp(name, "default"))
+ {
+ osd_printf_verbose("Ignoring configuration for system %s in default configuration file %s\n", name, file.filename());
continue;
+ }
+ level = config_level::DEFAULT;
break;
case config_type::CONTROLLER:
{
+ // match on: default, system name, source file name, parent name, grandparent name
int clone_of;
- /* match on: default, game name, source file name, parent name, grandparent name */
- if (strcmp(name, "default") != 0 &&
- strcmp(name, machine().system().name) != 0 &&
- strcmp(name, srcfile) != 0 &&
- ((clone_of = driver_list::clone(machine().system())) == -1 || strcmp(name, driver_list::driver(clone_of).name) != 0) &&
- (clone_of == -1 || ((clone_of = driver_list::clone(clone_of)) == -1) || strcmp(name, driver_list::driver(clone_of).name) != 0))
+ if (!strcmp(name, "default"))
+ {
+ osd_printf_verbose("Applying default configuration from controller configuration file %s\n", file.filename());
+ level = config_level::DEFAULT;
+ }
+ else if (!strcmp(name, system.name))
+ {
+ osd_printf_verbose("Applying configuration for system %s from controller configuration file %s\n", name, file.filename());
+ level = config_level::SYSTEM;
+ }
+ else if (!strcmp(name, srcfile))
+ {
+ osd_printf_verbose("Applying configuration for source file %s from controller configuration file %s\n", name, file.filename());
+ level = config_level::SOURCE;
+ }
+ else if (
+ ((clone_of = driver_list::clone(system)) != -1 && !strcmp(name, driver_list::driver(clone_of).name)) ||
+ (clone_of != -1 && ((clone_of = driver_list::clone(clone_of)) != -1) && !strcmp(name, driver_list::driver(clone_of).name)))
+ {
+ osd_printf_verbose("Applying configuration for parent/BIOS %s from controller configuration file %s\n", name, file.filename());
+ level = (driver_list::driver(clone_of).flags & MACHINE_IS_BIOS_ROOT) ? config_level::BIOS : config_level::PARENT;
+ }
+ else
+ {
continue;
+ }
break;
}
@@ -199,21 +259,24 @@ int configuration_manager::load_xml(emu_file &file, config_type which_type)
break;
}
- /* log that we are processing this entry */
+ // log that we are processing this entry
if (DEBUG_CONFIG)
osd_printf_debug("Entry: %s -- processing\n", name);
- /* loop over all registrants and call their load function */
- for (auto type : m_typelist)
- type.load(which_type, systemnode->get_child(type.name.c_str()));
+ // loop over all registrants and call their load function
+ for (auto const &type : m_typelist)
+ type.second.load(which_type, level, systemnode->get_child(type.first.c_str()));
count++;
- }
- /* error if this isn't a valid game match */
- if (count == 0)
- return 0;
+ // save unhandled settings for default and system types
+ if (config_type::DEFAULT == which_type)
+ save_unhandled(m_unhandled_default, *systemnode);
+ else if (config_type::SYSTEM == which_type)
+ save_unhandled(m_unhandled_system, *systemnode);
+ }
- return 1;
+ // error if this isn't a valid match
+ return count != 0;
}
@@ -224,43 +287,85 @@ int configuration_manager::load_xml(emu_file &file, config_type which_type)
*
*************************************/
-int configuration_manager::save_xml(emu_file &file, config_type which_type)
+bool configuration_manager::save_xml(emu_file &file, config_type which_type)
{
+ // if we cant't create a root node, bail
util::xml::file::ptr root(util::xml::file::create());
-
- /* if we don't have a root, bail */
if (!root)
- return 0;
+ return false;
- /* create a config node */
+ // create a config node
util::xml::data_node *const confignode = root->add_child("mameconfig", nullptr);
if (!confignode)
- return 0;
+ return false;
confignode->set_attribute_int("version", CONFIG_VERSION);
- /* create a system node */
+ // create a system node
util::xml::data_node *const systemnode = confignode->add_child("system", nullptr);
if (!systemnode)
- return 0;
+ return false;
systemnode->set_attribute("name", (which_type == config_type::DEFAULT) ? "default" : machine().system().name);
- /* create the input node and write it out */
- /* loop over all registrants and call their save function */
- for (auto type : m_typelist)
+ // loop over all registrants and call their save function
+ util::xml::data_node *curnode = nullptr;
+ for (auto const &type : m_typelist)
{
- util::xml::data_node *const curnode = systemnode->add_child(type.name.c_str(), nullptr);
+ if (!curnode || (type.first != curnode->get_name()))
+ curnode = systemnode->add_child(type.first.c_str(), nullptr);
if (!curnode)
- return 0;
- type.save(which_type, curnode);
+ return false;
+ type.second.save(which_type, curnode);
- /* if nothing was added, just nuke the node */
- if (!curnode->get_value() && !curnode->get_first_child())
+ // if nothing was added, just nuke the node
+ if (!curnode->get_value() && !curnode->get_first_child() && !curnode->count_attributes())
+ {
curnode->delete_node();
+ curnode = nullptr;
+ }
}
- /* flush the file */
+ // restore unhandled settings
+ if ((config_type::DEFAULT == which_type) && m_unhandled_default)
+ restore_unhandled(*m_unhandled_default, *systemnode);
+ else if ((config_type::SYSTEM == which_type) && m_unhandled_system)
+ restore_unhandled(*m_unhandled_system, *systemnode);
+
+ // write out the file
root->write(file);
- /* free and get out of here */
- return 1;
+ // free and get out of here
+ return true;
+}
+
+
+
+/*************************************
+ *
+ * Preserving unhandled settings
+ *
+ *************************************/
+
+void configuration_manager::save_unhandled(
+ std::unique_ptr<util::xml::file> &unhandled,
+ util::xml::data_node const &systemnode)
+{
+ for (util::xml::data_node const *curnode = systemnode.get_first_child(); curnode; curnode = curnode->get_next_sibling())
+ {
+ auto const handler = m_typelist.lower_bound(curnode->get_name());
+ if ((m_typelist.end() == handler) || (handler->first != curnode->get_name()))
+ {
+ if (!unhandled)
+ unhandled = util::xml::file::create();
+ curnode->copy_into(*unhandled);
+ }
+ }
+}
+
+
+void configuration_manager::restore_unhandled(
+ util::xml::file const &unhandled,
+ util::xml::data_node &systemnode)
+{
+ for (util::xml::data_node const *curnode = unhandled.get_first_child(); curnode; curnode = curnode->get_next_sibling())
+ curnode->copy_into(systemnode);
}