summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/options.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/options.cpp')
-rw-r--r--src/lib/util/options.cpp201
1 files changed, 176 insertions, 25 deletions
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);
}
}