mame/src/emu/config.cpp
Vas Crabb 42fbb9c396 Make osd_file a polymorphic class that's held with smart pointers
Make avi_file a class that's held with smart pointers, encapsulate various AVI I/O structures
Make zip_file and _7z_file classes rather than having free functions everywhere
Hide zip/7z class implementation behind an interface, no longer need to call close() to send back to the cache
Don't dump as much crap in global namespace
Add solaris PTY implementation
Improve variable expansion for SDL OSD - supports ~/$FOO/${BAR} syntax
Rearrange stuff so the same things are in file module for all OSDs
Move file stuff into its own module

7z/zip open and destruct are still not thread-safe due to lack of interlocks around cache access
Directory functions still need to be moved to file module
SDL OSD may not initialise WinSock on Windows
2016-03-14 18:55:00 +11:00

280 lines
7.6 KiB
C++

// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria, Aaron Giles
/***************************************************************************
config.c
Configuration file I/O.
***************************************************************************/
#include "emu.h"
#include "emuopts.h"
#include "drivenum.h"
#include "config.h"
#include "xmlfile.h"
#define DEBUG_CONFIG 0
//**************************************************************************
// CONFIGURATION MANAGER
//**************************************************************************
//-------------------------------------------------
// configuration_manager - constructor
//-------------------------------------------------
configuration_manager::configuration_manager(running_machine &machine)
: m_machine(machine)
{
}
/*************************************
*
* Register to be involved in config
* save/load
*
*************************************/
void configuration_manager::config_register(const char* nodename, config_saveload_delegate load, config_saveload_delegate save)
{
config_element element;
element.name = nodename;
element.load = load;
element.save = save;
m_typelist.push_back(element);
}
/*************************************
*
* Settings save/load frontend
*
*************************************/
int 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::CONFIG_TYPE_INIT, nullptr);
/* now load the controller file */
if (controller[0] != 0)
{
/* open the config file */
emu_file file(machine().options().ctrlr_path(), OPEN_FLAG_READ);
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::CONFIG_TYPE_CONTROLLER))
throw emu_fatalerror("Could not load controller file %s.cfg", controller);
}
/* next load the defaults file */
emu_file file(machine().options().cfg_directory(), OPEN_FLAG_READ);
osd_file::error filerr = file.open("default.cfg");
if (filerr == osd_file::error::NONE)
load_xml(file, config_type::CONFIG_TYPE_DEFAULT);
/* finally, load the game-specific file */
filerr = file.open(machine().basename(), ".cfg");
if (filerr == osd_file::error::NONE)
loaded = load_xml(file, config_type::CONFIG_TYPE_GAME);
/* loop over all registrants and call their final function */
for (auto type : m_typelist)
type.load(config_type::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 diplay the disclaimer. */
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::CONFIG_TYPE_INIT, nullptr);
/* 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)
save_xml(file, config_type::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::CONFIG_TYPE_GAME);
/* loop over all registrants and call their final function */
for (auto type : m_typelist)
type.save(config_type::CONFIG_TYPE_FINAL, nullptr);
}
/*************************************
*
* XML file load
*
*************************************/
int configuration_manager::load_xml(emu_file &file, config_type which_type)
{
xml_data_node *root, *confignode, *systemnode;
const char *srcfile;
int version, count;
/* read the file */
root = xml_file_read(file, nullptr);
if (!root)
goto error;
/* find the config node */
confignode = xml_get_sibling(root->child, "mameconfig");
if (!confignode)
goto error;
/* validate the config data version */
version = xml_get_attribute_int(confignode, "version", 0);
if (version != CONFIG_VERSION)
goto error;
/* strip off all the path crap from the source filename */
srcfile = strrchr(machine().system().source_file, '/');
if (!srcfile)
srcfile = strrchr(machine().system().source_file, '\\');
if (!srcfile)
srcfile = strrchr(machine().system().source_file, ':');
if (!srcfile)
srcfile = machine().system().source_file;
else
srcfile++;
/* loop over all system nodes in the file */
count = 0;
for (systemnode = xml_get_sibling(confignode->child, "system"); systemnode; systemnode = xml_get_sibling(systemnode->next, "system"))
{
/* look up the name of the system here; skip if none */
const char *name = xml_get_attribute_string(systemnode, "name", "");
/* based on the file type, determine whether we have a match */
switch (which_type)
{
case config_type::CONFIG_TYPE_GAME:
/* only match on the specific game name */
if (strcmp(name, machine().system().name) != 0)
continue;
break;
case config_type::CONFIG_TYPE_DEFAULT:
/* only match on default */
if (strcmp(name, "default") != 0)
continue;
break;
case config_type::CONFIG_TYPE_CONTROLLER:
{
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))
continue;
break;
}
default:
break;
}
/* 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, xml_get_sibling(systemnode->child, type.name.c_str()));
count++;
}
/* error if this isn't a valid game match */
if (count == 0)
goto error;
/* free the parser */
xml_file_free(root);
return 1;
error:
if (root)
xml_file_free(root);
return 0;
}
/*************************************
*
* XML file save
*
*************************************/
int configuration_manager::save_xml(emu_file &file, config_type which_type)
{
xml_data_node *root = xml_file_create();
xml_data_node *confignode, *systemnode;
/* if we don't have a root, bail */
if (!root)
return 0;
/* create a config node */
confignode = xml_add_child(root, "mameconfig", nullptr);
if (!confignode)
goto error;
xml_set_attribute_int(confignode, "version", CONFIG_VERSION);
/* create a system node */
systemnode = xml_add_child(confignode, "system", nullptr);
if (!systemnode)
goto error;
xml_set_attribute(systemnode, "name", (which_type == config_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)
{
xml_data_node *curnode = xml_add_child(systemnode, type.name.c_str(), nullptr);
if (!curnode)
goto error;
type.save(which_type, curnode);
/* if nothing was added, just nuke the node */
if (!curnode->value && !curnode->child)
xml_delete_node(curnode);
}
/* flush the file */
xml_file_write(root, file);
/* free and get out of here */
xml_file_free(root);
return 1;
error:
xml_file_free(root);
return 0;
}