summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--plugins/autofire/autofire_save.lua2
-rw-r--r--plugins/boot.lua2
-rw-r--r--plugins/cheat/init.lua4
-rw-r--r--plugins/cheatfind/init.lua2
-rw-r--r--plugins/console/init.lua2
-rw-r--r--plugins/data/data_hiscore.lua6
-rw-r--r--plugins/data/database.lua4
-rw-r--r--plugins/hiscore/init.lua2
-rw-r--r--plugins/inputmacro/inputmacro_persist.lua2
-rw-r--r--plugins/portname/init.lua2
-rw-r--r--plugins/timecode/init.lua2
-rw-r--r--plugins/timer/timer_persist.lua2
-rw-r--r--src/emu/emuopts.cpp62
-rw-r--r--src/frontend/mame/clifront.cpp2
-rw-r--r--src/frontend/mame/luaengine.cpp2
-rw-r--r--src/frontend/mame/mame.cpp7
-rw-r--r--src/frontend/mame/ui/dirmenu.cpp142
-rw-r--r--src/frontend/mame/ui/moptions.cpp44
-rw-r--r--src/frontend/mame/ui/submenu.cpp6
-rw-r--r--src/lib/util/options.cpp201
-rw-r--r--src/lib/util/options.h23
-rw-r--r--src/osd/modules/file/posixdir.cpp2
-rw-r--r--src/osd/modules/file/posixfile.cpp2
-rw-r--r--src/osd/modules/file/winfile.cpp6
-rw-r--r--src/osd/modules/file/winrtfile.cpp6
-rw-r--r--src/osd/modules/lib/osdobj_common.cpp4
-rw-r--r--src/osd/modules/render/bgfx/chainmanager.cpp4
-rw-r--r--src/osd/modules/render/bgfx/effectmanager.cpp2
-rw-r--r--src/osd/modules/render/bgfx/shadermanager.cpp2
-rw-r--r--src/osd/sdl/sdlmain.cpp4
-rw-r--r--src/osd/windows/winmain.cpp8
31 files changed, 368 insertions, 193 deletions
diff --git a/plugins/autofire/autofire_save.lua b/plugins/autofire/autofire_save.lua
index 5ca4cd217b6..52586c461ad 100644
--- a/plugins/autofire/autofire_save.lua
+++ b/plugins/autofire/autofire_save.lua
@@ -1,7 +1,7 @@
local lib = {}
local function get_settings_path()
- return emu.subst_env(manager.machine.options.entries.homepath:value():match('([^;]+)')) .. '/autofire'
+ return manager.machine.options.entries.homepath:value():match('([^;]+)') .. '/autofire'
end
local function get_settings_filename()
diff --git a/plugins/boot.lua b/plugins/boot.lua
index 712fe0db7c6..390ce652ff6 100644
--- a/plugins/boot.lua
+++ b/plugins/boot.lua
@@ -8,7 +8,7 @@ _G.N_ = function (message) return message end
_G.N_p = function (context, message) return message end
_G.emu.plugin = {} -- table to contain plugin interfaces
-- substitute environment variables in the plugins path from options
-local dirs = emu.subst_env(manager.options.entries.pluginspath:value())
+local dirs = manager.options.entries.pluginspath:value()
-- and split the paths apart and make them suitable for package.path
package.path = ""
diff --git a/plugins/cheat/init.lua b/plugins/cheat/init.lua
index 896fc1e101b..47d7db26cc2 100644
--- a/plugins/cheat/init.lua
+++ b/plugins/cheat/init.lua
@@ -130,7 +130,7 @@ function cheat.startplugin()
local function load_hotkeys()
local json = require("json")
- local file = io.open(emu.subst_env(manager.machine.options.entries.cheatpath:value():match("([^;]+)")) .. "/" .. cheatname .. "_hotkeys.json", "r")
+ local file = io.open(manager.machine.options.entries.cheatpath:value():match("([^;]+)") .. "/" .. cheatname .. "_hotkeys.json", "r")
if not file then
return
end
@@ -154,7 +154,7 @@ function cheat.startplugin()
end
end
end
- local path = emu.subst_env(manager.machine.options.entries.cheatpath:value():match("([^;]+)"))
+ local path = manager.machine.options.entries.cheatpath:value():match("([^;]+)")
local filepath = path .. "/" .. cheatname .. "_hotkeys.json"
if #hotkeys > 0 then
local json = require("json")
diff --git a/plugins/cheatfind/init.lua b/plugins/cheatfind/init.lua
index 96617e12fb6..7c3cea73e8b 100644
--- a/plugins/cheatfind/init.lua
+++ b/plugins/cheatfind/init.lua
@@ -965,7 +965,7 @@ function cheatfind.startplugin()
end
end
end
- cheat_save.path = emu.subst_env(manager.machine.options.entries.cheatpath:value()):match("([^;]+)")
+ cheat_save.path = manager.machine.options.entries.cheatpath:value():match("([^;]+)")
cheat_save.filename = string.format("%s/%s", cheat_save.path, setname)
cheat_save.name = cheat.desc
local json = require("json")
diff --git a/plugins/console/init.lua b/plugins/console/init.lua
index 6b8643fe168..1b40ac50bee 100644
--- a/plugins/console/init.lua
+++ b/plugins/console/init.lua
@@ -243,7 +243,7 @@ function console.startplugin()
end
if (not started) then
-- options are not available in startplugin, so we load the history here
- local homepath = emu.subst_env(manager.options.entries.homepath:value():match("([^;]+)"))
+ local homepath = manager.options.entries.homepath:value():match("([^;]+)")
history_fullpath = homepath .. '/' .. history_file
ln.loadhistory(history_fullpath)
started = true
diff --git a/plugins/data/data_hiscore.lua b/plugins/data/data_hiscore.lua
index c0794b20195..f05e4ddd173 100644
--- a/plugins/data/data_hiscore.lua
+++ b/plugins/data/data_hiscore.lua
@@ -5,7 +5,7 @@ local dat = {}
local env = {}
local output
local curset
-local path = emu.subst_env(mame_manager.ui.options.entries.historypath:value():gsub("([^;]+)", "%1/hi2txt"))
+local path = mame_manager.ui.options.entries.historypath:value():gsub("([^;]+)", "%1/hi2txt")
local htmlentites = {
["amp"] = "&",
["quot"] = utf8.char(34),
@@ -355,7 +355,7 @@ local htmlentites = {
function env.open(file, size, swap)
if file == ".hi" then
local path = "hi"
- local ini = emu.file(emu.subst_env(manager.options.entries.inipath:value()), 1)
+ local ini = emu.file(manager.options.entries.inipath:value(), 1)
local ret = ini:open("hiscore.ini")
if not ret then
local inifile = ini:read(ini:size())
@@ -369,7 +369,7 @@ function env.open(file, size, swap)
end
file = path .. "/" .. curset .. ".hi"
else
- file = emu.subst_env(manager.options.entries.nvram_directory:value()) .. "/" .. curset .. "/" .. file
+ file = manager.options.entries.nvram_directory:value() .. "/" .. curset .. "/" .. file
end
local f = io.open(file, "rb")
local content = f:read("*all")
diff --git a/plugins/data/database.lua b/plugins/data/database.lua
index e0249182409..4fb4eaa2ddf 100644
--- a/plugins/data/database.lua
+++ b/plugins/data/database.lua
@@ -10,7 +10,7 @@ local function check_db_result(msg)
end
local function settings_path()
- return emu.subst_env(manager.machine.options.entries.homepath:value():match('([^;]+)')) .. '/data'
+ return manager.machine.options.entries.homepath:value():match('([^;]+)') .. '/data'
end
local function check_version_table()
@@ -147,7 +147,7 @@ end
function dbtable.open_data_file(file)
local fh, filepath
for path in mame_manager.ui.options.entries.historypath:value():gmatch('([^;]+)') do
- filepath = emu.subst_env(path) .. '/' .. file
+ filepath = path .. '/' .. file
fh = io.open(filepath, 'r')
if fh then
break
diff --git a/plugins/hiscore/init.lua b/plugins/hiscore/init.lua
index 652061c92cf..5f93b91bd1a 100644
--- a/plugins/hiscore/init.lua
+++ b/plugins/hiscore/init.lua
@@ -23,7 +23,7 @@ end
function hiscore.startplugin()
local function get_data_path()
- return emu.subst_env(manager.machine.options.entries.homepath:value():match('([^;]+)')) .. '/hiscore'
+ return manager.machine.options.entries.homepath:value():match('([^;]+)') .. '/hiscore'
end
-- configuration
diff --git a/plugins/inputmacro/inputmacro_persist.lua b/plugins/inputmacro/inputmacro_persist.lua
index 6c2aa6fd188..6519f3a048a 100644
--- a/plugins/inputmacro/inputmacro_persist.lua
+++ b/plugins/inputmacro/inputmacro_persist.lua
@@ -5,7 +5,7 @@
-- Helpers
local function settings_path()
- return emu.subst_env(manager.machine.options.entries.homepath:value():match('([^;]+)')) .. '/inputmacro'
+ return manager.machine.options.entries.homepath:value():match('([^;]+)') .. '/inputmacro'
end
local function settings_filename()
diff --git a/plugins/portname/init.lua b/plugins/portname/init.lua
index 1f2c8d80874..b855f27cc6e 100644
--- a/plugins/portname/init.lua
+++ b/plugins/portname/init.lua
@@ -28,7 +28,7 @@ local portname = exports
function portname.startplugin()
local json = require("json")
- local ctrlrpath = emu.subst_env(manager.options.entries.ctrlrpath:value():match("([^;]+)"))
+ local ctrlrpath = manager.options.entries.ctrlrpath:value():match("([^;]+)")
local function get_filename(nosoft)
local filename
if emu.softname() ~= "" and not nosoft then
diff --git a/plugins/timecode/init.lua b/plugins/timecode/init.lua
index 09e49229cae..93435ef2870 100644
--- a/plugins/timecode/init.lua
+++ b/plugins/timecode/init.lua
@@ -34,7 +34,7 @@ function timecode.startplugin()
local function get_settings_path()
- return emu.subst_env(manager.machine.options.entries.homepath:value():match('([^;]+)')) .. '/timecode'
+ return manager.machine.options.entries.homepath:value():match('([^;]+)') .. '/timecode'
end
diff --git a/plugins/timer/timer_persist.lua b/plugins/timer/timer_persist.lua
index 4781c263ba8..cb24b485dcb 100644
--- a/plugins/timer/timer_persist.lua
+++ b/plugins/timer/timer_persist.lua
@@ -130,7 +130,7 @@ end
local function open_database()
-- make sure settings directory exists
- local dir = emu.subst_env(manager.machine.options.entries.homepath:value():match('([^;]+)')) .. '/timer'
+ local dir = manager.machine.options.entries.homepath:value():match('([^;]+)') .. '/timer'
local attr = lfs.attributes(dir)
if not attr then
lfs.mkdir(dir)
diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp
index a3972edcb0e..41b33874e08 100644
--- a/src/emu/emuopts.cpp
+++ b/src/emu/emuopts.cpp
@@ -37,30 +37,30 @@ const options_entry emu_options::s_option_entries[] =
// search path options
{ nullptr, nullptr, core_options::option_type::HEADER, "CORE SEARCH PATH OPTIONS" },
- { OPTION_PLUGINDATAPATH, ".", core_options::option_type::STRING, "path to base folder for plugin data (read/write)" },
- { OPTION_MEDIAPATH ";rp;biospath;bp", "roms", core_options::option_type::STRING, "path to ROM sets and hard disk images" },
- { OPTION_HASHPATH ";hash_directory;hash", "hash", core_options::option_type::STRING, "path to software definition files" },
- { OPTION_SAMPLEPATH ";sp", "samples", core_options::option_type::STRING, "path to audio sample sets" },
- { OPTION_ARTPATH, "artwork", core_options::option_type::STRING, "path to artwork files" },
- { OPTION_CTRLRPATH, "ctrlr", core_options::option_type::STRING, "path to controller definitions" },
- { OPTION_INIPATH, ".;ini;ini/presets", core_options::option_type::STRING, "path to ini files" },
- { OPTION_FONTPATH, ".", core_options::option_type::STRING, "path to font files" },
- { OPTION_CHEATPATH, "cheat", core_options::option_type::STRING, "path to cheat files" },
- { OPTION_CROSSHAIRPATH, "crosshair", core_options::option_type::STRING, "path to crosshair files" },
- { OPTION_PLUGINSPATH, "plugins", core_options::option_type::STRING, "path to plugin files" },
- { OPTION_LANGUAGEPATH, "language", core_options::option_type::STRING, "path to UI translation files" },
- { OPTION_SWPATH, "software", core_options::option_type::STRING, "path to loose software" },
+ { OPTION_PLUGINDATAPATH, ".", core_options::option_type::PATH, "path to base folder for plugin data (read/write)" },
+ { OPTION_MEDIAPATH ";rp;biospath;bp", "roms", core_options::option_type::MULTIPATH, "path to ROM sets and hard disk images" },
+ { OPTION_HASHPATH ";hash_directory;hash", "hash", core_options::option_type::MULTIPATH, "path to software definition files" },
+ { OPTION_SAMPLEPATH ";sp", "samples", core_options::option_type::MULTIPATH, "path to audio sample sets" },
+ { OPTION_ARTPATH, "artwork", core_options::option_type::MULTIPATH, "path to artwork files" },
+ { OPTION_CTRLRPATH, "ctrlr", core_options::option_type::MULTIPATH, "path to controller definitions" },
+ { OPTION_INIPATH, ".;ini;ini/presets", core_options::option_type::MULTIPATH, "path to ini files" },
+ { OPTION_FONTPATH, ".", core_options::option_type::MULTIPATH, "path to font files" },
+ { OPTION_CHEATPATH, "cheat", core_options::option_type::MULTIPATH, "path to cheat files" },
+ { OPTION_CROSSHAIRPATH, "crosshair", core_options::option_type::MULTIPATH, "path to crosshair files" },
+ { OPTION_PLUGINSPATH, "plugins", core_options::option_type::MULTIPATH, "path to plugin files" },
+ { OPTION_LANGUAGEPATH, "language", core_options::option_type::MULTIPATH, "path to UI translation files" },
+ { OPTION_SWPATH, "software", core_options::option_type::MULTIPATH, "path to loose software" },
// output directory options
{ nullptr, nullptr, core_options::option_type::HEADER, "CORE OUTPUT DIRECTORY OPTIONS" },
- { OPTION_CFG_DIRECTORY, "cfg", core_options::option_type::STRING, "directory to save configurations" },
- { OPTION_NVRAM_DIRECTORY, "nvram", core_options::option_type::STRING, "directory to save NVRAM contents" },
- { OPTION_INPUT_DIRECTORY, "inp", core_options::option_type::STRING, "directory to save input device logs" },
- { OPTION_STATE_DIRECTORY, "sta", core_options::option_type::STRING, "directory to save states" },
- { OPTION_SNAPSHOT_DIRECTORY, "snap", core_options::option_type::STRING, "directory to save/load screenshots" },
- { OPTION_DIFF_DIRECTORY, "diff", core_options::option_type::STRING, "directory to save hard drive image difference files" },
- { OPTION_COMMENT_DIRECTORY, "comments", core_options::option_type::STRING, "directory to save debugger comments" },
- { OPTION_SHARE_DIRECTORY, "share", core_options::option_type::STRING, "directory to share with emulated machines" },
+ { OPTION_CFG_DIRECTORY, "cfg", core_options::option_type::PATH, "directory to save configurations" },
+ { OPTION_NVRAM_DIRECTORY, "nvram", core_options::option_type::PATH, "directory to save NVRAM contents" },
+ { OPTION_INPUT_DIRECTORY, "inp", core_options::option_type::PATH, "directory to save input device logs" },
+ { OPTION_STATE_DIRECTORY, "sta", core_options::option_type::PATH, "directory to save states" },
+ { OPTION_SNAPSHOT_DIRECTORY, "snap", core_options::option_type::PATH, "directory to save/load screenshots" },
+ { OPTION_DIFF_DIRECTORY, "diff", core_options::option_type::PATH, "directory to save hard drive image difference files" },
+ { OPTION_COMMENT_DIRECTORY, "comments", core_options::option_type::PATH, "directory to save debugger comments" },
+ { OPTION_SHARE_DIRECTORY, "share", core_options::option_type::PATH, "directory to share with emulated machines" },
// state/playback options
{ nullptr, nullptr, core_options::option_type::HEADER, "CORE STATE/PLAYBACK OPTIONS" },
@@ -72,9 +72,9 @@ const options_entry emu_options::s_option_entries[] =
{ OPTION_RECORD ";rec", nullptr, core_options::option_type::STRING, "record an input file" },
{ OPTION_EXIT_AFTER_PLAYBACK, "0", core_options::option_type::BOOLEAN, "close the program at the end of playback" },
- { OPTION_MNGWRITE, nullptr, core_options::option_type::STRING, "optional filename to write a MNG movie of the current session" },
- { OPTION_AVIWRITE, nullptr, core_options::option_type::STRING, "optional filename to write an AVI movie of the current session" },
- { OPTION_WAVWRITE, nullptr, core_options::option_type::STRING, "optional filename to write a WAV file of the current session" },
+ { OPTION_MNGWRITE, nullptr, core_options::option_type::PATH, "optional filename to write a MNG movie of the current session" },
+ { OPTION_AVIWRITE, nullptr, core_options::option_type::PATH, "optional filename to write an AVI movie of the current session" },
+ { OPTION_WAVWRITE, nullptr, core_options::option_type::PATH, "optional filename to write a WAV file of the current session" },
{ OPTION_SNAPNAME, "%g/%i", core_options::option_type::STRING, "override of the default snapshot/movie naming; %g == gamename, %i == index" },
{ OPTION_SNAPSIZE, "auto", core_options::option_type::STRING, "specify snapshot/movie resolution (<width>x<height>) or 'auto' to use minimal size " },
{ OPTION_SNAPVIEW, "auto", core_options::option_type::STRING, "snapshot/movie view - 'auto' for default, or 'native' for per-screen pixel-aspect views" },
@@ -181,7 +181,7 @@ const options_entry emu_options::s_option_entries[] =
{ OPTION_OSLOG, "0", core_options::option_type::BOOLEAN, "output error.log data to system diagnostic output (debugger or standard error)" },
{ OPTION_DEBUG ";d", "0", core_options::option_type::BOOLEAN, "enable/disable debugger" },
{ OPTION_UPDATEINPAUSE, "0", core_options::option_type::BOOLEAN, "keep calling video updates while in pause" },
- { OPTION_DEBUGSCRIPT, nullptr, core_options::option_type::STRING, "script for debugger" },
+ { OPTION_DEBUGSCRIPT, nullptr, core_options::option_type::PATH, "script for debugger" },
{ OPTION_DEBUGLOG, "0", core_options::option_type::BOOLEAN, "write debug console output to debug.log" },
// comm options
@@ -212,7 +212,7 @@ const options_entry emu_options::s_option_entries[] =
{ nullptr, nullptr, core_options::option_type::HEADER, "SCRIPTING OPTIONS" },
{ OPTION_AUTOBOOT_COMMAND ";ab", nullptr, core_options::option_type::STRING, "command to execute after machine boot" },
{ OPTION_AUTOBOOT_DELAY, "0", core_options::option_type::INTEGER, "delay before executing autoboot command (seconds)" },
- { OPTION_AUTOBOOT_SCRIPT ";script", nullptr, core_options::option_type::STRING, "Lua script to execute after machine boot" },
+ { OPTION_AUTOBOOT_SCRIPT ";script", nullptr, core_options::option_type::PATH, "Lua script to execute after machine boot" },
{ OPTION_CONSOLE, "0", core_options::option_type::BOOLEAN, "enable emulator Lua console" },
{ OPTION_PLUGINS, "1", core_options::option_type::BOOLEAN, "enable Lua plugin support" },
{ OPTION_PLUGIN, nullptr, core_options::option_type::STRING, "list of plugins to enable" },
@@ -221,7 +221,7 @@ const options_entry emu_options::s_option_entries[] =
{ nullptr, nullptr, core_options::option_type::HEADER, "HTTP SERVER OPTIONS" },
{ OPTION_HTTP, "0", core_options::option_type::BOOLEAN, "enable HTTP server" },
{ OPTION_HTTP_PORT, "8080", core_options::option_type::INTEGER, "HTTP server port" },
- { OPTION_HTTP_ROOT, "web", core_options::option_type::STRING, "HTTP server document root" },
+ { OPTION_HTTP_ROOT, "web", core_options::option_type::PATH, "HTTP server document root" },
{ nullptr }
};
@@ -255,7 +255,7 @@ namespace
}
protected:
- virtual void internal_set_value(std::string &&newvalue) override
+ virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override
{
m_host.set_system_name(std::move(newvalue));
}
@@ -275,7 +275,7 @@ namespace
}
protected:
- virtual void internal_set_value(std::string &&newvalue) override
+ virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override
{
m_host.set_software(std::move(newvalue));
}
@@ -313,7 +313,7 @@ namespace
}
protected:
- virtual void internal_set_value(std::string &&newvalue) override
+ virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override
{
m_host.specify(std::move(newvalue), false);
}
@@ -339,7 +339,7 @@ namespace
}
protected:
- virtual void internal_set_value(std::string &&newvalue) override
+ virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override
{
m_host.specify(std::move(newvalue), false);
}
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp
index dfe0436e079..aa32a94a860 100644
--- a/src/frontend/mame/clifront.cpp
+++ b/src/frontend/mame/clifront.cpp
@@ -1732,7 +1732,7 @@ void cli_frontend::execute_commands(std::string_view exename)
path_iterator iter(m_options.plugins_path());
std::string pluginpath;
while (iter.next(pluginpath))
- plugin_opts.scan_directory(osd_subst_env(pluginpath), true);
+ plugin_opts.scan_directory(pluginpath, true);
emu_file file_plugin(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
if (file_plugin.open("plugin.ini"))
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index 386d6dc841d..d406a502583 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -1172,7 +1172,7 @@ void lua_engine::initialize()
e.set_value(string_format("%d", val), OPTION_PRIORITY_CMDLINE);
},
[this](core_options::entry &e, const char *val) {
- if(e.type() != core_options::option_type::STRING)
+ if(e.type() != core_options::option_type::STRING && e.type() != core_options::option_type::PATH && e.type() != core_options::option_type::MULTIPATH)
luaL_error(m_lua_state, "Cannot set option to wrong type");
else
e.set_value(val, OPTION_PRIORITY_CMDLINE);
diff --git a/src/frontend/mame/mame.cpp b/src/frontend/mame/mame.cpp
index 5cfe2a5b243..d2d3d886acd 100644
--- a/src/frontend/mame/mame.cpp
+++ b/src/frontend/mame/mame.cpp
@@ -142,10 +142,7 @@ void mame_machine_manager::start_luaengine()
std::string pluginpath;
while (iter.next(pluginpath))
{
- // user may specify environment variables; subsitute them
- pluginpath = osd_subst_env(pluginpath);
-
- // and then scan the directory recursively
+ // scan the directory recursively
m_plugins->scan_directory(pluginpath, true);
}
@@ -202,7 +199,7 @@ void mame_machine_manager::start_luaengine()
std::error_condition const filerr = file.open("boot.lua");
if (!filerr)
{
- const std::string exppath = osd_subst_env(file.fullpath());
+ const std::string exppath = file.fullpath();
auto &l(*lua());
auto load_result = l.load_script(exppath);
if (!load_result.valid())
diff --git a/src/frontend/mame/ui/dirmenu.cpp b/src/frontend/mame/ui/dirmenu.cpp
index ab55b742054..1e28c88cc37 100644
--- a/src/frontend/mame/ui/dirmenu.cpp
+++ b/src/frontend/mame/ui/dirmenu.cpp
@@ -29,50 +29,46 @@ namespace ui {
namespace {
-constexpr int ADDING = 1;
-constexpr int CHANGE = 2;
-
struct folders_entry
{
const char *name;
const char *option;
- const int action;
};
const folders_entry f_folders[] =
{
- { N_p("path-option", "ROMs"), OPTION_MEDIAPATH, ADDING },
- { N_p("path-option", "Software Media"), OPTION_SWPATH, CHANGE },
- { N_p("path-option", "Sound Samples"), OPTION_SAMPLEPATH, ADDING },
- { N_p("path-option", "Artwork"), OPTION_ARTPATH, ADDING },
- { N_p("path-option", "Crosshairs"), OPTION_CROSSHAIRPATH, ADDING },
- { N_p("path-option", "Cheat Files"), OPTION_CHEATPATH, ADDING },
- { N_p("path-option", "Plugins"), OPTION_PLUGINSPATH, ADDING },
- { N_p("path-option", "UI Translations"), OPTION_LANGUAGEPATH, CHANGE },
- { N_p("path-option", "Software Lists"), OPTION_HASHPATH, ADDING },
- { N_p("path-option", "INIs"), OPTION_INIPATH, ADDING },
- { N_p("path-option", "UI Settings"), OPTION_UI_PATH, CHANGE },
- { N_p("path-option", "Plugin Data"), OPTION_PLUGINDATAPATH, CHANGE },
- { N_p("path-option", "DATs"), OPTION_HISTORY_PATH, ADDING },
- { N_p("path-option", "Category INIs"), OPTION_CATEGORYINI_PATH, CHANGE },
- { N_p("path-option", "Snapshots"), OPTION_SNAPSHOT_DIRECTORY, ADDING },
- { N_p("path-option", "Icons"), OPTION_ICONS_PATH, ADDING },
- { N_p("path-option", "Control Panels"), OPTION_CPANELS_PATH, ADDING },
- { N_p("path-option", "Cabinets"), OPTION_CABINETS_PATH, ADDING },
- { N_p("path-option", "Marquees"), OPTION_MARQUEES_PATH, ADDING },
- { N_p("path-option", "PCBs"), OPTION_PCBS_PATH, ADDING },
- { N_p("path-option", "Flyers"), OPTION_FLYERS_PATH, ADDING },
- { N_p("path-option", "Title Screens"), OPTION_TITLES_PATH, ADDING },
- { N_p("path-option", "Game Endings"), OPTION_ENDS_PATH, ADDING },
- { N_p("path-option", "Bosses"), OPTION_BOSSES_PATH, ADDING },
- { N_p("path-option", "Artwork Previews"), OPTION_ARTPREV_PATH, ADDING },
- { N_p("path-option", "Select"), OPTION_SELECT_PATH, ADDING },
- { N_p("path-option", "Game Over Screens"), OPTION_GAMEOVER_PATH, ADDING },
- { N_p("path-option", "HowTo"), OPTION_HOWTO_PATH, ADDING },
- { N_p("path-option", "Logos"), OPTION_LOGOS_PATH, ADDING },
- { N_p("path-option", "Scores"), OPTION_SCORES_PATH, ADDING },
- { N_p("path-option", "Versus"), OPTION_VERSUS_PATH, ADDING },
- { N_p("path-option", "Covers"), OPTION_COVER_PATH, ADDING }
+ { N_p("path-option", "ROMs"), OPTION_MEDIAPATH },
+ { N_p("path-option", "Software Media"), OPTION_SWPATH },
+ { N_p("path-option", "Sound Samples"), OPTION_SAMPLEPATH },
+ { N_p("path-option", "Artwork"), OPTION_ARTPATH },
+ { N_p("path-option", "Crosshairs"), OPTION_CROSSHAIRPATH },
+ { N_p("path-option", "Cheat Files"), OPTION_CHEATPATH },
+ { N_p("path-option", "Plugins"), OPTION_PLUGINSPATH },
+ { N_p("path-option", "UI Translations"), OPTION_LANGUAGEPATH },
+ { N_p("path-option", "Software Lists"), OPTION_HASHPATH },
+ { N_p("path-option", "INIs"), OPTION_INIPATH },
+ { N_p("path-option", "UI Settings"), OPTION_UI_PATH },
+ { N_p("path-option", "Plugin Data"), OPTION_PLUGINDATAPATH },
+ { N_p("path-option", "DATs"), OPTION_HISTORY_PATH },
+ { N_p("path-option", "Category INIs"), OPTION_CATEGORYINI_PATH },
+ { N_p("path-option", "Snapshots"), OPTION_SNAPSHOT_DIRECTORY },
+ { N_p("path-option", "Icons"), OPTION_ICONS_PATH },
+ { N_p("path-option", "Control Panels"), OPTION_CPANELS_PATH },
+ { N_p("path-option", "Cabinets"), OPTION_CABINETS_PATH },
+ { N_p("path-option", "Marquees"), OPTION_MARQUEES_PATH },
+ { N_p("path-option", "PCBs"), OPTION_PCBS_PATH },
+ { N_p("path-option", "Flyers"), OPTION_FLYERS_PATH },
+ { N_p("path-option", "Title Screens"), OPTION_TITLES_PATH },
+ { N_p("path-option", "Game Endings"), OPTION_ENDS_PATH },
+ { N_p("path-option", "Bosses"), OPTION_BOSSES_PATH },
+ { N_p("path-option", "Artwork Previews"), OPTION_ARTPREV_PATH },
+ { N_p("path-option", "Select"), OPTION_SELECT_PATH },
+ { N_p("path-option", "Game Over Screens"), OPTION_GAMEOVER_PATH },
+ { N_p("path-option", "HowTo"), OPTION_HOWTO_PATH },
+ { N_p("path-option", "Logos"), OPTION_LOGOS_PATH },
+ { N_p("path-option", "Scores"), OPTION_SCORES_PATH },
+ { N_p("path-option", "Versus"), OPTION_VERSUS_PATH },
+ { N_p("path-option", "Covers"), OPTION_COVER_PATH }
};
@@ -166,7 +162,7 @@ void menu_remove_folder::populate(float &customtop, float &custombottom)
class menu_add_change_folder : public menu
{
public:
- menu_add_change_folder(mame_ui_manager &mui, render_container &container, int ref);
+ menu_add_change_folder(mame_ui_manager &mui, render_container &container, int ref, bool multipath);
protected:
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
@@ -180,9 +176,9 @@ private:
void update_search();
int const m_ref;
+ bool const m_multipath;
std::string m_current_path;
std::string m_search;
- bool const m_change;
std::vector<std::string> m_folders;
};
@@ -190,10 +186,10 @@ private:
// ctor
//-------------------------------------------------
-menu_add_change_folder::menu_add_change_folder(mame_ui_manager &mui, render_container &container, int ref)
+menu_add_change_folder::menu_add_change_folder(mame_ui_manager &mui, render_container &container, int ref, bool multipath)
: menu(mui, container)
, m_ref(ref)
- , m_change(f_folders[ref].action == CHANGE)
+ , m_multipath(multipath)
{
// configure the starting path
osd_get_full_path(m_current_path, ".");
@@ -255,7 +251,7 @@ void menu_add_change_folder::handle(event const *ev)
{
// Tab key, save current path
std::string error_string;
- if (m_change)
+ if (!m_multipath)
{
if (ui().options().exists(f_folders[m_ref].option))
ui().options().set_value(f_folders[m_ref].option, m_current_path, OPTION_PRIORITY_CMDLINE);
@@ -349,7 +345,7 @@ void menu_add_change_folder::custom_render(void *selectedref, float top, float b
{
std::string const toptext[] = {
util::string_format(
- m_change ? _("Change %1$s Folder - Search: %2$s_") : _("Add %1$s Folder - Search: %2$s_"),
+ m_multipath ? _("Add %1$s Folder - Search: %2$s_") : _("Change %1$s Folder - Search: %2$s_"),
_("path-option", f_folders[m_ref].name),
m_search),
m_current_path };
@@ -428,8 +424,9 @@ class menu_display_actual : public menu
public:
menu_display_actual(mame_ui_manager &mui, render_container &container, int selectedref)
: menu(mui, container)
- , m_heading{ util::string_format((f_folders[selectedref].action == ADDING) ? _("%1$s Folders") : _("%1$s Folder"), _("path-option", f_folders[selectedref].name)) }
, m_ref(selectedref)
+ , m_multipath(is_multipath(f_folders[selectedref].option))
+ , m_heading{ util::string_format(m_multipath ? _("%1$s Folders") : _("%1$s Folder"), _("path-option", f_folders[selectedref].name)) }
{
}
@@ -446,13 +443,30 @@ private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
+ bool is_multipath(std::string_view folder) const;
+
+ int const m_ref;
+ bool const m_multipath;
std::string const m_heading[1];
std::string m_searchpath;
std::vector<std::string> m_folders;
- int const m_ref;
};
//-------------------------------------------------
+// is_multipath
+//-------------------------------------------------
+
+bool menu_display_actual::is_multipath(std::string_view folder) const
+{
+ auto option = ui().options().get_entry(folder);
+ if (!option)
+ option = machine().options().get_entry(folder);
+ assert(option);
+
+ return option->type() == core_options::option_type::MULTIPATH;
+}
+
+//-------------------------------------------------
// handle
//-------------------------------------------------
@@ -468,7 +482,7 @@ void menu_display_actual::handle(event const *ev)
break;
case ADD_CHANGE:
- menu::stack_push<menu_add_change_folder>(ui(), container(), m_ref);
+ menu::stack_push<menu_add_change_folder>(ui(), container(), m_ref, m_multipath);
break;
}
}
@@ -480,21 +494,31 @@ void menu_display_actual::handle(event const *ev)
void menu_display_actual::populate(float &customtop, float &custombottom)
{
- if (ui().options().exists(f_folders[m_ref].option))
- m_searchpath.assign(ui().options().value(f_folders[m_ref].option));
- else
- m_searchpath.assign(machine().options().value(f_folders[m_ref].option));
+ auto const &folder = f_folders[m_ref];
+ auto option = ui().options().get_entry(folder.option);
+ if (!option)
+ option = machine().options().get_entry(folder.option);
+ assert(option);
- path_iterator path(m_searchpath);
- std::string curpath;
- m_folders.clear();
- while (path.next(curpath))
- m_folders.push_back(curpath);
-
- item_append((f_folders[m_ref].action == CHANGE) ? _("Change Folder") : _("Add Folder"), 0, (void *)ADD_CHANGE);
+ m_searchpath.assign(option->value());
- if (m_folders.size() > 1)
- item_append(_("Remove Folder"), 0, (void *)REMOVE);
+ m_folders.clear();
+ if (m_multipath)
+ {
+ path_iterator path(m_searchpath);
+ std::string curpath;
+ while (path.next(curpath))
+ m_folders.push_back(curpath);
+
+ item_append(_("Add Folder"), 0, (void *)ADD_CHANGE);
+ if (m_folders.size() > 1)
+ item_append(_("Remove Folder"), 0, (void *)REMOVE);
+ }
+ else
+ {
+ m_folders.push_back(m_searchpath);
+ item_append(_("Change Folder"), 0, (void *)ADD_CHANGE);
+ }
item_append(menu_item_type::SEPARATOR);
@@ -559,7 +583,7 @@ void menu_directory::handle(event const *ev)
void menu_directory::populate(float &customtop, float &custombottom)
{
for (auto & elem : f_folders)
- item_append(_("path-option", elem.name), 0, (void *)(uintptr_t)elem.action);
+ item_append(_("path-option", elem.name), 0, this); // need a non-null reference pointer - value is immaterial
item_append(menu_item_type::SEPARATOR);
}
diff --git a/src/frontend/mame/ui/moptions.cpp b/src/frontend/mame/ui/moptions.cpp
index ff08ab3f9e6..cf019588834 100644
--- a/src/frontend/mame/ui/moptions.cpp
+++ b/src/frontend/mame/ui/moptions.cpp
@@ -20,31 +20,31 @@
const options_entry ui_options::s_option_entries[] =
{
// search path options
- { nullptr, nullptr, core_options::option_type::HEADER, "UI SEARCH PATH OPTIONS" },
- { OPTION_HISTORY_PATH, "history;dats;.", core_options::option_type::STRING, "path to system/software info files" },
- { OPTION_CATEGORYINI_PATH, "folders", core_options::option_type::STRING, "path to category ini files" },
- { OPTION_CABINETS_PATH, "cabinets;cabdevs", core_options::option_type::STRING, "path to cabinets / devices image" },
- { OPTION_CPANELS_PATH, "cpanel", core_options::option_type::STRING, "path to control panel image" },
- { OPTION_PCBS_PATH, "pcb", core_options::option_type::STRING, "path to pcbs image" },
- { OPTION_FLYERS_PATH, "flyers", core_options::option_type::STRING, "path to flyers image" },
- { OPTION_TITLES_PATH, "titles", core_options::option_type::STRING, "path to titles image" },
- { OPTION_ENDS_PATH, "ends", core_options::option_type::STRING, "path to ends image" },
- { OPTION_MARQUEES_PATH, "marquees", core_options::option_type::STRING, "path to marquees image" },
- { OPTION_ARTPREV_PATH, "artwork preview;artpreview", core_options::option_type::STRING, "path to artwork preview image" },
- { OPTION_BOSSES_PATH, "bosses", core_options::option_type::STRING, "path to bosses image" },
- { OPTION_LOGOS_PATH, "logo", core_options::option_type::STRING, "path to logos image" },
- { OPTION_SCORES_PATH, "scores", core_options::option_type::STRING, "path to scores image" },
- { OPTION_VERSUS_PATH, "versus", core_options::option_type::STRING, "path to versus image" },
- { OPTION_GAMEOVER_PATH, "gameover", core_options::option_type::STRING, "path to gameover image" },
- { OPTION_HOWTO_PATH, "howto", core_options::option_type::STRING, "path to howto image" },
- { OPTION_SELECT_PATH, "select", core_options::option_type::STRING, "path to select image" },
- { OPTION_ICONS_PATH, "icons", core_options::option_type::STRING, "path to ICOns image" },
- { OPTION_COVER_PATH, "covers", core_options::option_type::STRING, "path to software cover image" },
- { OPTION_UI_PATH, "ui", core_options::option_type::STRING, "path to UI files" },
+ { nullptr, nullptr, core_options::option_type::HEADER, "UI SEARCH PATH OPTIONS" },
+ { OPTION_HISTORY_PATH, "history;dats;.", core_options::option_type::MULTIPATH, "path to system/software info files" },
+ { OPTION_CATEGORYINI_PATH, "folders", core_options::option_type::MULTIPATH, "path to category ini files" },
+ { OPTION_CABINETS_PATH, "cabinets;cabdevs", core_options::option_type::MULTIPATH, "path to cabinets / devices image" },
+ { OPTION_CPANELS_PATH, "cpanel", core_options::option_type::MULTIPATH, "path to control panel image" },
+ { OPTION_PCBS_PATH, "pcb", core_options::option_type::MULTIPATH, "path to pcbs image" },
+ { OPTION_FLYERS_PATH, "flyers", core_options::option_type::MULTIPATH, "path to flyers image" },
+ { OPTION_TITLES_PATH, "titles", core_options::option_type::MULTIPATH, "path to titles image" },
+ { OPTION_ENDS_PATH, "ends", core_options::option_type::MULTIPATH, "path to ends image" },
+ { OPTION_MARQUEES_PATH, "marquees", core_options::option_type::MULTIPATH, "path to marquees image" },
+ { OPTION_ARTPREV_PATH, "artwork preview;artpreview", core_options::option_type::MULTIPATH, "path to artwork preview image" },
+ { OPTION_BOSSES_PATH, "bosses", core_options::option_type::MULTIPATH, "path to bosses image" },
+ { OPTION_LOGOS_PATH, "logo", core_options::option_type::MULTIPATH, "path to logos image" },
+ { OPTION_SCORES_PATH, "scores", core_options::option_type::MULTIPATH, "path to scores image" },
+ { OPTION_VERSUS_PATH, "versus", core_options::option_type::MULTIPATH, "path to versus image" },
+ { OPTION_GAMEOVER_PATH, "gameover", core_options::option_type::MULTIPATH, "path to gameover image" },
+ { OPTION_HOWTO_PATH, "howto", core_options::option_type::MULTIPATH, "path to howto image" },
+ { OPTION_SELECT_PATH, "select", core_options::option_type::MULTIPATH, "path to select image" },
+ { OPTION_ICONS_PATH, "icons", core_options::option_type::MULTIPATH, "path to ICOns image" },
+ { OPTION_COVER_PATH, "covers", core_options::option_type::MULTIPATH, "path to software cover image" },
+ { OPTION_UI_PATH, "ui", core_options::option_type::MULTIPATH, "path to UI files" },
// misc options
{ nullptr, nullptr, core_options::option_type::HEADER, "UI MISC OPTIONS" },
- { OPTION_SYSTEM_NAMES, "", core_options::option_type::STRING, "translated system names file" },
+ { OPTION_SYSTEM_NAMES, "", core_options::option_type::MULTIPATH, "translated system names file" },
{ OPTION_SKIP_WARNINGS, "0", core_options::option_type::BOOLEAN, "display fewer repeated warnings about imperfect emulation" },
{ OPTION_REMEMBER_LAST, "1", core_options::option_type::BOOLEAN, "initially select last used system in main menu" },
{ OPTION_ENLARGE_SNAPS, "1", core_options::option_type::BOOLEAN, "enlarge artwork (snapshot, title, etc.) in right panel (keeping aspect ratio)" },
diff --git a/src/frontend/mame/ui/submenu.cpp b/src/frontend/mame/ui/submenu.cpp
index 4e470251b7a..450834a5458 100644
--- a/src/frontend/mame/ui/submenu.cpp
+++ b/src/frontend/mame/ui/submenu.cpp
@@ -173,7 +173,7 @@ submenu::submenu(mame_ui_manager &mui, render_container &container, std::vector<
case option_type::EMU:
sm_option.entry = opts->get_entry(sm_option.name);
sm_option.options = opts;
- if (sm_option.entry->type() == core_options::option_type::STRING)
+ if ((sm_option.entry->type() == core_options::option_type::STRING) || (sm_option.entry->type() == core_options::option_type::PATH) || (sm_option.entry->type() == core_options::option_type::MULTIPATH))
{
sm_option.value.clear();
std::string namestr(sm_option.entry->description());
@@ -197,7 +197,7 @@ submenu::submenu(mame_ui_manager &mui, render_container &container, std::vector<
case option_type::OSD:
sm_option.entry = opts->get_entry(sm_option.name);
sm_option.options = opts;
- if (sm_option.entry->type() == core_options::option_type::STRING)
+ if ((sm_option.entry->type() == core_options::option_type::STRING) || (sm_option.entry->type() == core_options::option_type::PATH) || (sm_option.entry->type() == core_options::option_type::MULTIPATH))
{
sm_option.value.clear();
std::string descr(machine().options().get_entry(sm_option.name)->description()), delim(", ");
@@ -307,6 +307,8 @@ void submenu::handle(event const *ev)
}
break;
case core_options::option_type::STRING:
+ case core_options::option_type::PATH:
+ case core_options::option_type::MULTIPATH:
if (ev->iptkey == IPT_UI_LEFT || ev->iptkey == IPT_UI_RIGHT)
{
changed = true;
diff --git a/src/lib/util/options.cpp b/src/lib/util/options.cpp
index cac92c37020..7bf64c344e4 100644
--- a/src/lib/util/options.cpp
+++ b/src/lib/util/options.cpp
@@ -12,6 +12,7 @@
#include "corefile.h"
#include "corestr.h"
+#include "osdcore.h"
#include <locale>
#include <string>
@@ -20,6 +21,7 @@
#include <cctype>
#include <cstdarg>
#include <cstdlib>
+#include <sstream>
const int core_options::MAX_UNADORNED_OPTIONS;
@@ -113,7 +115,7 @@ options_error_exception::options_error_exception(std::string &&message)
// entry - constructor
//-------------------------------------------------
-core_options::entry::entry(std::vector<std::string> &&names, core_options::option_type type, const char *description)
+core_options::entry::entry(std::vector<std::string> &&names, option_type type, const char *description)
: m_names(std::move(names))
, m_priority(OPTION_PRIORITY_DEFAULT)
, m_type(type)
@@ -122,7 +124,7 @@ core_options::entry::entry(std::vector<std::string> &&names, core_options::optio
assert(m_names.empty() == (m_type == option_type::HEADER));
}
-core_options::entry::entry(std::string &&name, core_options::option_type type, const char *description)
+core_options::entry::entry(std::string &&name, option_type type, const char *description)
: entry(std::vector<std::string>({ std::move(name) }), type, description)
{
}
@@ -150,10 +152,44 @@ const char *core_options::entry::value() const noexcept
//-------------------------------------------------
+// entry::value_unsubstituted
+//-------------------------------------------------
+
+const char *core_options::entry::value_unsubstituted() const noexcept
+{
+ return value();
+}
+
+
+//-------------------------------------------------
+// entry::copy_from
+//-------------------------------------------------
+
+void core_options::entry::copy_from(const entry &that, 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 || that.priority() >= priority())
+ {
+ if (internal_copy_value(that))
+ {
+ m_priority = that.priority();
+
+ // invoke the value changed handler, if appropriate
+ if (m_value_changed_handler)
+ m_value_changed_handler(value());
+ }
+ }
+}
+
+
+//-------------------------------------------------
// entry::set_value
//-------------------------------------------------
-void core_options::entry::set_value(std::string &&newvalue, int priority_value, bool always_override)
+void core_options::entry::set_value(std::string &&newvalue, int priority_value, bool always_override, bool perform_substitutions)
{
// it is invalid to set the value on a header
assert(type() != option_type::HEADER);
@@ -163,7 +199,7 @@ void core_options::entry::set_value(std::string &&newvalue, int priority_value,
// only set the value if we have priority
if (always_override || priority_value >= priority())
{
- internal_set_value(std::move(newvalue));
+ internal_set_value(std::move(newvalue), perform_substitutions);
m_priority = priority_value;
// invoke the value changed handler, if appropriate
@@ -185,6 +221,29 @@ void core_options::entry::set_default_value(std::string &&newvalue)
//-------------------------------------------------
+// entry::internal_copy_value
+//-------------------------------------------------
+
+bool core_options::entry::internal_copy_value(const entry &that)
+{
+ char const *const newvalue = that.value();
+ if (newvalue)
+ {
+ std::string stringval = newvalue;
+ validate(stringval);
+
+ internal_set_value(std::move(stringval), false);
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+//-------------------------------------------------
// entry::validate
//-------------------------------------------------
@@ -273,12 +332,14 @@ void core_options::entry::validate(const std::string &data)
}
break;
- case core_options::option_type::STRING:
+ case option_type::STRING:
+ case option_type::PATH:
+ case option_type::MULTIPATH:
// strings can be anything
break;
- case core_options::option_type::INVALID:
- case core_options::option_type::HEADER:
+ case option_type::INVALID:
+ case option_type::HEADER:
default:
// anything else is invalid
throw options_error_exception("Attempted to set invalid option %s\n", name());
@@ -337,10 +398,12 @@ const std::string &core_options::entry::default_value() const noexcept
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_defdata_unsubst(std::move(defdata))
, m_minimum(std::move(minimum))
, m_maximum(std::move(maximum))
{
+ m_defdata = type_specific_substitutions(m_defdata_unsubst);
+ m_data_unsubst = m_defdata_unsubst;
m_data = m_defdata;
}
@@ -366,6 +429,8 @@ const char *core_options::simple_entry::value() const noexcept
case core_options::option_type::INTEGER:
case core_options::option_type::FLOAT:
case core_options::option_type::STRING:
+ case core_options::option_type::PATH:
+ case core_options::option_type::MULTIPATH:
return m_data.c_str();
default:
@@ -377,6 +442,30 @@ const char *core_options::simple_entry::value() const noexcept
//-------------------------------------------------
+// simple_entry::value_unsubstituted
+//-------------------------------------------------
+
+const char *core_options::simple_entry::value_unsubstituted() const noexcept
+{
+ switch (type())
+ {
+ case core_options::option_type::BOOLEAN:
+ case core_options::option_type::INTEGER:
+ case core_options::option_type::FLOAT:
+ case core_options::option_type::STRING:
+ case core_options::option_type::PATH:
+ case core_options::option_type::MULTIPATH:
+ return m_data_unsubst.c_str();
+
+ default:
+ // this is an option type for which returning a value is
+ // a meaningless operation (e.g. - core_options::option_type::COMMAND)
+ return nullptr;
+ }
+}
+
+
+//-------------------------------------------------
// simple_entry::default_value
//-------------------------------------------------
@@ -388,12 +477,38 @@ const std::string &core_options::simple_entry::default_value() const noexcept
//-------------------------------------------------
-// internal_set_value
+// simple_entry::internal_set_value
+//-------------------------------------------------
+
+void core_options::simple_entry::internal_set_value(std::string &&newvalue, bool perform_substitutions)
+{
+ m_data = perform_substitutions
+ ? type_specific_substitutions(newvalue)
+ : newvalue;
+ m_data_unsubst = std::move(newvalue);
+}
+
+
+//-------------------------------------------------
+// simple_entry::internal_copy_value
//-------------------------------------------------
-void core_options::simple_entry::internal_set_value(std::string &&newvalue)
+bool core_options::simple_entry::internal_copy_value(const entry &that)
{
- m_data = std::move(newvalue);
+ simple_entry const *const simple = dynamic_cast<simple_entry const *>(&that);
+ if (!simple)
+ {
+ return entry::internal_copy_value(that);
+ }
+ else
+ {
+ validate(simple->m_data);
+
+ m_data = simple->m_data;
+ m_data_unsubst = simple->m_data_unsubst;
+
+ return true;
+ }
}
@@ -403,7 +518,47 @@ void core_options::simple_entry::internal_set_value(std::string &&newvalue)
void core_options::simple_entry::set_default_value(std::string &&newvalue)
{
- m_data = m_defdata = std::move(newvalue);
+ m_data = m_defdata = type_specific_substitutions(newvalue);
+ m_data_unsubst = std::move(newvalue);
+}
+
+
+//-------------------------------------------------
+// type_specific_substitutions
+//-------------------------------------------------
+
+std::string core_options::simple_entry::type_specific_substitutions(std::string_view s) const noexcept
+{
+ switch (type())
+ {
+ case option_type::PATH:
+ return osd_subst_env(s);
+
+ case option_type::MULTIPATH:
+ {
+ std::ostringstream result;
+ while (!s.empty())
+ {
+ std::string_view::size_type split = s.find(';');
+ if (std::string_view::npos == split)
+ split = s.length();
+ result << osd_subst_env(s.substr(0, split));
+ if (s.length() > split)
+ {
+ result << s[split];
+ s.remove_prefix(split + 1);
+ }
+ else
+ {
+ s.remove_prefix(split);
+ }
+ }
+ return std::move(result).str();
+ }
+
+ default:
+ return std::string(s);
+ }
}
@@ -717,7 +872,7 @@ void core_options::parse_command_line(const std::vector<std::string> &args, int
}
// set the new data
- do_set_value(*curentry, newdata, priority, error_stream, condition);
+ do_set_value(*curentry, newdata, priority, error_stream, condition, false);
}
// did we have any errors that may need to be aggregated?
@@ -791,7 +946,7 @@ void core_options::parse_ini_file(util::core_file &inifile, int priority, bool i
}
// set the new data
- do_set_value(*curentry, trim_spaces_and_quotes(optiondata), priority, error_stream, condition);
+ do_set_value(*curentry, trim_spaces_and_quotes(optiondata), priority, error_stream, condition, true);
}
// did we have any errors that may need to be aggregated?
@@ -837,11 +992,7 @@ void core_options::copy_from(const core_options &that)
// identify the source entry
const entry::shared_const_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);
- }
+ dest_entry->copy_from(*source_entry, false);
}
}
}
@@ -875,7 +1026,7 @@ std::string core_options::output_ini(const core_options *diff) const
else
{
const std::string &name(curentry->name());
- const char *value(curentry->value());
+ const char *value(curentry->value_unsubstituted());
// check if it's unadorned
bool is_unadorned = false;
@@ -889,7 +1040,7 @@ std::string core_options::output_ini(const core_options *diff) const
if (value)
{
// look up counterpart in diff, if diff is specified
- if (!diff || strcmp(value, diff->value(name.c_str())))
+ if (!diff || strcmp(value, diff->get_entry(name.c_str())->value_unsubstituted()))
{
// output header, if we have one
if (last_header)
@@ -1022,7 +1173,7 @@ void core_options::set_value(std::string_view name, std::string &&value, int pri
{
auto entry = get_entry(name);
assert(entry != nullptr);
- entry->set_value(std::move(value), priority);
+ entry->set_value(std::move(value), priority, false, false);
}
void core_options::set_value(std::string_view name, int value, int priority)
@@ -1063,13 +1214,13 @@ void core_options::remove_entry(core_options::entry &delentry)
// do_set_value
//-------------------------------------------------
-void core_options::do_set_value(entry &curentry, std::string_view data, int priority, std::ostream &error_stream, condition_type &condition)
+void core_options::do_set_value(entry &curentry, std::string_view data, int priority, std::ostream &error_stream, condition_type &condition, bool perform_substitutions)
{
// 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::string(data), priority);
+ curentry.set_value(std::string(data), priority, false, perform_substitutions);
}
catch (options_warning_exception &ex)
{
@@ -1156,7 +1307,7 @@ void core_options::simple_entry::revert(int priority_hi, int priority_lo)
// if our priority is within the range, revert to the default
if (priority() <= priority_hi && priority() >= priority_lo)
{
- set_value(std::string(default_value()), priority(), true);
+ set_value(std::string(m_defdata_unsubst), priority(), true, true);
set_priority(OPTION_PRIORITY_DEFAULT);
}
}
diff --git a/src/lib/util/options.h b/src/lib/util/options.h
index 57ca7160203..99db519a5e5 100644
--- a/src/lib/util/options.h
+++ b/src/lib/util/options.h
@@ -104,7 +104,9 @@ public:
BOOLEAN, // boolean option
INTEGER, // integer option
FLOAT, // floating-point option
- STRING // string option
+ STRING, // string option
+ PATH, // single path option
+ MULTIPATH // semicolon-delimited paths option
};
// information about a single entry in the options
@@ -128,6 +130,7 @@ public:
const std::vector<std::string> &names() const noexcept { return m_names; }
const std::string &name() const noexcept { return m_names[0]; }
virtual const char *value() const noexcept;
+ virtual const char *value_unsubstituted() const noexcept;
int priority() const noexcept { return m_priority; }
void set_priority(int priority) noexcept { m_priority = priority; }
option_type type() const noexcept { return m_type; }
@@ -138,18 +141,20 @@ public:
bool has_range() const noexcept;
// mutators
- void set_value(std::string &&newvalue, int priority, bool always_override = false);
+ void copy_from(const entry &that, bool always_override);
+ void set_value(std::string &&newvalue, int priority, bool always_override = false, bool perform_substitutions = 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); }
virtual void revert(int priority_hi, int priority_lo) { }
protected:
- virtual void internal_set_value(std::string &&newvalue) = 0;
+ virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) = 0;
+ virtual bool internal_copy_value(const entry &that);
- private:
void validate(const std::string &value);
+ private:
const std::vector<std::string> m_names;
int m_priority;
core_options::option_type m_type;
@@ -231,6 +236,7 @@ private:
// getters
virtual const char *value() const noexcept override;
+ virtual const char *value_unsubstituted() const noexcept override;
virtual const char *minimum() const noexcept override;
virtual const char *maximum() const noexcept override;
virtual const std::string &default_value() const noexcept override;
@@ -239,14 +245,19 @@ private:
virtual void set_default_value(std::string &&newvalue) override;
protected:
- virtual void internal_set_value(std::string &&newvalue) override;
+ virtual void internal_set_value(std::string &&newvalue, bool perform_substitutions) override;
+ virtual bool internal_copy_value(const entry &that) override;
private:
// internal state
std::string m_data; // data for this item
+ std::string m_data_unsubst; // data for this item, prior to any substitution
std::string m_defdata; // default data for this item
+ std::string m_defdata_unsubst; // default data for this item, prior to any substitution
std::string m_minimum; // minimum value
std::string m_maximum; // maximum value
+
+ std::string type_specific_substitutions(std::string_view s) const noexcept;
};
// used internally in core_options
@@ -259,7 +270,7 @@ private:
// internal helpers
void add_to_entry_map(const std::string &name, entry::shared_ptr &entry);
- void do_set_value(entry &curentry, std::string_view data, int priority, std::ostream &error_stream, condition_type &condition);
+ void do_set_value(entry &curentry, std::string_view data, int priority, std::ostream &error_stream, condition_type &condition, bool perform_substitutions);
void throw_options_exception_if_appropriate(condition_type condition, std::ostringstream &error_stream);
// internal state
diff --git a/src/osd/modules/file/posixdir.cpp b/src/osd/modules/file/posixdir.cpp
index efe68c2eda9..282a58acfc9 100644
--- a/src/osd/modules/file/posixdir.cpp
+++ b/src/osd/modules/file/posixdir.cpp
@@ -193,7 +193,7 @@ bool posix_directory::open_impl(std::string const &dirname)
{
assert(!m_fd);
- m_path = osd_subst_env(dirname);
+ m_path = dirname;
m_fd.reset(::opendir(m_path.c_str()));
return bool(m_fd);
}
diff --git a/src/osd/modules/file/posixfile.cpp b/src/osd/modules/file/posixfile.cpp
index 3b0e7b4b537..c5ce8bf7b4e 100644
--- a/src/osd/modules/file/posixfile.cpp
+++ b/src/osd/modules/file/posixfile.cpp
@@ -257,8 +257,6 @@ std::error_condition osd_file::open(std::string const &path, std::uint32_t openf
for (auto it = dst.begin(); it != dst.end(); ++it)
*it = (INVPATHSEPCH == *it) ? PATHSEPCH : *it;
#endif
- try { dst = osd_subst_env(dst); }
- catch (...) { return std::errc::not_enough_memory; }
// attempt to open the file
int fd = -1;
diff --git a/src/osd/modules/file/winfile.cpp b/src/osd/modules/file/winfile.cpp
index 173021121f1..84c754cdd6f 100644
--- a/src/osd/modules/file/winfile.cpp
+++ b/src/osd/modules/file/winfile.cpp
@@ -161,12 +161,8 @@ DWORD create_path_recursive(TCHAR *path)
// osd_open
//============================================================
-std::error_condition osd_file::open(std::string const &orig_path, uint32_t openflags, ptr &file, std::uint64_t &filesize) noexcept
+std::error_condition osd_file::open(std::string const &path, uint32_t openflags, ptr &file, std::uint64_t &filesize) noexcept
{
- std::string path;
- try { path = osd_subst_env(orig_path); }
- catch (...) { return std::errc::not_enough_memory; }
-
if (win_check_socket_path(path))
return win_open_socket(path, openflags, file, filesize);
else if (win_check_ptty_path(path))
diff --git a/src/osd/modules/file/winrtfile.cpp b/src/osd/modules/file/winrtfile.cpp
index 3de1c19605d..5053f6e0199 100644
--- a/src/osd/modules/file/winrtfile.cpp
+++ b/src/osd/modules/file/winrtfile.cpp
@@ -160,12 +160,8 @@ DWORD create_path_recursive(TCHAR *path)
// osd_open
//============================================================
-osd_file::error osd_file::open(std::string const &orig_path, uint32_t openflags, ptr &file, std::uint64_t &filesize)
+osd_file::error osd_file::open(std::string const &path, uint32_t openflags, ptr &file, std::uint64_t &filesize)
{
- std::string path;
- try { path = osd_subst_env(orig_path); }
- catch (...) { return std::errc::not_enough_memory; }
-
if (win_check_socket_path(path))
return win_open_socket(path, openflags, file, filesize);
else if (win_check_ptty_path(path))
diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp
index 09254f32042..5b3cebb84b9 100644
--- a/src/osd/modules/lib/osdobj_common.cpp
+++ b/src/osd/modules/lib/osdobj_common.cpp
@@ -164,13 +164,13 @@ const options_entry osd_options::s_option_entries[] =
#endif
{ nullptr, nullptr, core_options::option_type::HEADER, "BGFX POST-PROCESSING OPTIONS" },
- { OSDOPTION_BGFX_PATH, "bgfx", core_options::option_type::STRING, "path to BGFX-related files" },
+ { OSDOPTION_BGFX_PATH, "bgfx", core_options::option_type::PATH, "path to BGFX-related files" },
{ OSDOPTION_BGFX_BACKEND, "auto", core_options::option_type::STRING, "BGFX backend to use (d3d9, d3d11, d3d12, metal, opengl, gles, vulkan)" },
{ OSDOPTION_BGFX_DEBUG, "0", core_options::option_type::BOOLEAN, "enable BGFX debugging statistics" },
{ OSDOPTION_BGFX_SCREEN_CHAINS, "default", core_options::option_type::STRING, "comma-delimited list of screen chain JSON names, colon-delimited per-window" },
{ OSDOPTION_BGFX_SHADOW_MASK, "slot-mask.png", core_options::option_type::STRING, "shadow mask texture name" },
{ OSDOPTION_BGFX_LUT, "lut-default.png", core_options::option_type::STRING, "LUT texture name" },
- { OSDOPTION_BGFX_AVI_NAME, OSDOPTVAL_AUTO, core_options::option_type::STRING, "filename for BGFX output logging" },
+ { OSDOPTION_BGFX_AVI_NAME, OSDOPTVAL_AUTO, core_options::option_type::PATH, "filename for BGFX output logging" },
// End of list
{ nullptr }
diff --git a/src/osd/modules/render/bgfx/chainmanager.cpp b/src/osd/modules/render/bgfx/chainmanager.cpp
index c3b80e88d14..2ae3d9a3daf 100644
--- a/src/osd/modules/render/bgfx/chainmanager.cpp
+++ b/src/osd/modules/render/bgfx/chainmanager.cpp
@@ -92,7 +92,7 @@ void chain_manager::refresh_available_chains()
m_available_chains.clear();
m_available_chains.push_back(chain_desc("none", ""));
- const std::string chains_path = osd_subst_env(util::string_format("%s" PATH_SEPARATOR "chains", m_options.bgfx_path()));
+ const std::string chains_path = util::string_format("%s" PATH_SEPARATOR "chains", m_options.bgfx_path());
find_available_chains(chains_path, "");
destroy_unloaded_chains();
@@ -169,7 +169,7 @@ bgfx_chain* chain_manager::load_chain(std::string name, uint32_t screen_index)
{
name = name + ".json";
}
- std::string path = osd_subst_env(util::string_format("%s" PATH_SEPARATOR "chains" PATH_SEPARATOR, m_options.bgfx_path()));
+ std::string path = util::string_format("%s" PATH_SEPARATOR "chains" PATH_SEPARATOR, m_options.bgfx_path());
path += name;
bx::FileReader reader;
diff --git a/src/osd/modules/render/bgfx/effectmanager.cpp b/src/osd/modules/render/bgfx/effectmanager.cpp
index f57f56f708d..33e056b45fe 100644
--- a/src/osd/modules/render/bgfx/effectmanager.cpp
+++ b/src/osd/modules/render/bgfx/effectmanager.cpp
@@ -33,7 +33,7 @@ static bool prepare_effect_document(std::string &name, osd_options &options, rap
full_name = full_name + ".json";
}
- std::string path = osd_subst_env(util::string_format("%s" PATH_SEPARATOR "effects" PATH_SEPARATOR, options.bgfx_path()));
+ std::string path = util::string_format("%s" PATH_SEPARATOR "effects" PATH_SEPARATOR, options.bgfx_path());
path += full_name;
bx::FileReader reader;
diff --git a/src/osd/modules/render/bgfx/shadermanager.cpp b/src/osd/modules/render/bgfx/shadermanager.cpp
index dd894426794..11e298a4e7a 100644
--- a/src/osd/modules/render/bgfx/shadermanager.cpp
+++ b/src/osd/modules/render/bgfx/shadermanager.cpp
@@ -119,7 +119,7 @@ std::string shader_manager::make_path_string(osd_options &options, std::string n
fatalerror("Unknown BGFX renderer type %d", bgfx::getRendererType());
}
shader_path += PATH_SEPARATOR;
- return osd_subst_env(shader_path);
+ return shader_path;
}
const bgfx::Memory* shader_manager::load_mem(std::string name)
diff --git a/src/osd/sdl/sdlmain.cpp b/src/osd/sdl/sdlmain.cpp
index f238c7bd2cd..241e7f46148 100644
--- a/src/osd/sdl/sdlmain.cpp
+++ b/src/osd/sdl/sdlmain.cpp
@@ -77,7 +77,7 @@ int sdl_entered_debugger;
const options_entry sdl_options::s_option_entries[] =
{
- { SDLOPTION_INIPATH, INI_PATH, core_options::option_type::STRING, "path to ini files" },
+ { SDLOPTION_INIPATH, INI_PATH, core_options::option_type::MULTIPATH, "path to ini files" },
// performance options
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL PERFORMANCE OPTIONS" },
@@ -99,7 +99,7 @@ const options_entry sdl_options::s_option_entries[] =
// keyboard mapping
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL KEYBOARD MAPPING" },
{ SDLOPTION_KEYMAP, "0", core_options::option_type::BOOLEAN, "enable keymap" },
- { SDLOPTION_KEYMAP_FILE, "keymap.dat", core_options::option_type::STRING, "keymap filename" },
+ { SDLOPTION_KEYMAP_FILE, "keymap.dat", core_options::option_type::PATH, "keymap filename" },
// joystick mapping
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL JOYSTICK MAPPING" },
diff --git a/src/osd/windows/winmain.cpp b/src/osd/windows/winmain.cpp
index ab9ba5e9167..293074b3ec8 100644
--- a/src/osd/windows/winmain.cpp
+++ b/src/osd/windows/winmain.cpp
@@ -176,10 +176,10 @@ const options_entry windows_options::s_option_entries[] =
// post-processing options
{ nullptr, nullptr, core_options::option_type::HEADER, "DIRECT3D POST-PROCESSING OPTIONS" },
- { WINOPTION_HLSLPATH, "hlsl", core_options::option_type::STRING, "path to HLSL support files" },
+ { WINOPTION_HLSLPATH, "hlsl", core_options::option_type::PATH, "path to HLSL support files" },
{ WINOPTION_HLSL_ENABLE";hlsl", "0", core_options::option_type::BOOLEAN, "enable HLSL post-processing (PS3.0 required)" },
{ WINOPTION_HLSL_OVERSAMPLING, "0", core_options::option_type::BOOLEAN, "enable HLSL oversampling" },
- { WINOPTION_HLSL_WRITE, OSDOPTVAL_AUTO, core_options::option_type::STRING, "enable HLSL AVI writing (huge disk bandwidth suggested)" },
+ { WINOPTION_HLSL_WRITE, OSDOPTVAL_AUTO, core_options::option_type::PATH, "enable HLSL AVI writing (huge disk bandwidth suggested)" },
{ WINOPTION_HLSL_SNAP_WIDTH, "2048", core_options::option_type::STRING, "HLSL upscaled-snapshot width" },
{ WINOPTION_HLSL_SNAP_HEIGHT, "1536", core_options::option_type::STRING, "HLSL upscaled-snapshot height" },
{ WINOPTION_SHADOW_MASK_TILE_MODE, "0", core_options::option_type::INTEGER, "shadow mask tile mode (0 for screen based, 1 for source based)" },
@@ -262,9 +262,9 @@ const options_entry windows_options::s_option_entries[] =
{ WINOPTION_BLOOM_LEVEL6_WEIGHT, "0.04", core_options::option_type::FLOAT, "bloom level 6 weight (1/4 smaller that level 5 target)" },
{ WINOPTION_BLOOM_LEVEL7_WEIGHT, "0.02", core_options::option_type::FLOAT, "bloom level 7 weight (1/4 smaller that level 6 target)" },
{ WINOPTION_BLOOM_LEVEL8_WEIGHT, "0.01", core_options::option_type::FLOAT, "bloom level 8 weight (1/4 smaller that level 7 target)" },
- { WINOPTION_LUT_TEXTURE, "lut-default.png", core_options::option_type::STRING, "3D LUT texture filename for screen, PNG format" },
+ { WINOPTION_LUT_TEXTURE, "lut-default.png", core_options::option_type::PATH, "3D LUT texture filename for screen, PNG format" },
{ WINOPTION_LUT_ENABLE, "0", core_options::option_type::BOOLEAN, "Enables 3D LUT to be applied to screen after post-processing" },
- { WINOPTION_UI_LUT_TEXTURE, "lut-default.png", core_options::option_type::STRING, "3D LUT texture filename of UI, PNG format" },
+ { WINOPTION_UI_LUT_TEXTURE, "lut-default.png", core_options::option_type::PATH, "3D LUT texture filename of UI, PNG format" },
{ WINOPTION_UI_LUT_ENABLE, "0", core_options::option_type::BOOLEAN, "enable 3D LUT to be applied to UI and artwork after post-processing" },
// full screen options