diff options
Diffstat (limited to 'src/lib/util/options.cpp')
-rw-r--r-- | src/lib/util/options.cpp | 538 |
1 files changed, 406 insertions, 132 deletions
diff --git a/src/lib/util/options.cpp b/src/lib/util/options.cpp index cffb7493fe3..a111c211f0e 100644 --- a/src/lib/util/options.cpp +++ b/src/lib/util/options.cpp @@ -8,14 +8,21 @@ ***************************************************************************/ -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> -#include <assert.h> #include "options.h" + +#include "corefile.h" #include "corestr.h" +#include "osdcore.h" + +#include <locale> #include <string> +#include <cassert> +#include <cctype> +#include <cstdarg> +#include <cstdlib> +#include <sstream> + const int core_options::MAX_UNADORNED_OPTIONS; @@ -50,17 +57,19 @@ const char *const core_options::s_option_unadorned[MAX_UNADORNED_OPTIONS] = namespace { - void trim_spaces_and_quotes(std::string &data) + std::string_view trim_spaces_and_quotes(std::string_view data) { // trim any whitespace - strtrimspace(data); + data = strtrimspace(data); // trim quotes - if (data.find_first_of('"') == 0 && data.find_last_of('"') == data.length() - 1) + if (data.length() >= 2 && data.front() == '"' && data.back() == '"') { - data.erase(0, 1); - data.erase(data.length() - 1, 1); + data.remove_prefix(1); + data.remove_suffix(1); } + + return data; } }; @@ -106,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) @@ -115,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) { } @@ -134,7 +143,7 @@ core_options::entry::~entry() // entry::value //------------------------------------------------- -const char *core_options::entry::value() const +const char *core_options::entry::value() const noexcept { // returning 'nullptr' from here signifies a value entry that is essentially "write only" // and cannot be meaningfully persisted (e.g. - a command or the software name) @@ -143,18 +152,54 @@ const char *core_options::entry::value() const //------------------------------------------------- +// 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); + validate(newvalue); + // 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 @@ -176,57 +221,125 @@ 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 //------------------------------------------------- void core_options::entry::validate(const std::string &data) { - float fval; - int ival; + std::istringstream str(data); + str.imbue(std::locale::classic()); switch (type()) { case option_type::BOOLEAN: - // booleans must be 0 or 1 - if (sscanf(data.c_str(), "%d", &ival) != 1 || ival < 0 || ival > 1) - throw options_warning_exception("Illegal boolean value for %s: \"%s\"; reverting to %s\n", name(), data, value()); + { + // booleans must be 0 or 1 + int ival; + if (!(str >> ival) || (0 > ival) || (1 < ival)) + throw options_warning_exception("Illegal boolean value for %s: \"%s\"; reverting to %s\n", name(), data, value()); + } break; case option_type::INTEGER: - // integers must be integral - if (sscanf(data.c_str(), "%d", &ival) != 1) - throw options_warning_exception("Illegal integer value for %s: \"%s\"; reverting to %s\n", name(), data, value()); - - // range checking - if (has_range()) { - int minimum_integer = atoi(minimum()); - int maximum_integer = atoi(maximum()); - if (ival < minimum_integer || ival > maximum_integer) - throw options_warning_exception("Out-of-range integer value for %s: \"%s\" (must be between %d and %d); reverting to %s\n", name(), data, minimum_integer, maximum_integer, value()); + // integers must be integral + int ival; + if (!(str >> ival)) + throw options_warning_exception("Illegal integer value for %s: \"%s\"; reverting to %s\n", name(), data, value()); + + // range checking + char const *const strmin(minimum()); + char const *const strmax(maximum()); + int imin(0), imax(0); + if (strmin && *strmin) + { + str.str(strmin); + str.seekg(0); + str >> imin; + } + if (strmax && *strmax) + { + str.str(strmax); + str.seekg(0); + str >> imax; + } + if ((strmin && *strmin && (ival < imin)) || (strmax && *strmax && (ival > imax))) + { + if (!strmax || !*strmax) + throw options_warning_exception("Out-of-range integer value for %s: \"%s\" (must be no less than %d); reverting to %s\n", name(), data, imin, value()); + else if (!strmin || !*strmin) + throw options_warning_exception("Out-of-range integer value for %s: \"%s\" (must be no greater than %d); reverting to %s\n", name(), data, imax, value()); + else + throw options_warning_exception("Out-of-range integer value for %s: \"%s\" (must be between %d and %d, inclusive); reverting to %s\n", name(), data, imin, imax, value()); + } } break; case option_type::FLOAT: - if (sscanf(data.c_str(), "%f", &fval) != 1) - throw options_warning_exception("Illegal float value for %s: \"%s\"; reverting to %s\n", name(), data, value()); - - // range checking - if (has_range()) { - float minimum_float = atof(minimum()); - float maximum_float = atof(maximum()); - if (fval < minimum_float || fval > maximum_float) - throw options_warning_exception("Out-of-range float value for %s: \"%s\" (must be between %f and %f); reverting to %s\n", name(), data, minimum_float, maximum_float, value()); + float fval; + if (!(str >> fval)) + throw options_warning_exception("Illegal float value for %s: \"%s\"; reverting to %s\n", name(), data, value()); + + // range checking + char const *const strmin(minimum()); + char const *const strmax(maximum()); + float fmin(0), fmax(0); + if (strmin && *strmin) + { + str.str(strmin); + str.seekg(0); + str >> fmin; + } + if (strmax && *strmax) + { + str.str(strmax); + str.seekg(0); + str >> fmax; + } + if ((strmin && *strmin && (fval < fmin)) || (strmax && *strmax && (fval > fmax))) + { + if (!strmax || !*strmax) + throw options_warning_exception("Out-of-range float value for %s: \"%s\" (must be no less than %f); reverting to %s\n", name(), data, fmin, value()); + else if (!strmin || !*strmin) + throw options_warning_exception("Out-of-range float value for %s: \"%s\" (must be no greater than %f); reverting to %s\n", name(), data, fmax, value()); + else + throw options_warning_exception("Out-of-range float value for %s: \"%s\" (must be between %f and %f, inclusive); reverting to %s\n", name(), data, fmin, fmax, value()); + } } break; - case OPTION_STRING: + case option_type::STRING: + case option_type::PATH: + case option_type::MULTIPATH: // strings can be anything break; - case OPTION_INVALID: - case OPTION_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()); @@ -238,7 +351,7 @@ void core_options::entry::validate(const std::string &data) // entry::minimum //------------------------------------------------- -const char *core_options::entry::minimum() const +const char *core_options::entry::minimum() const noexcept { return nullptr; } @@ -248,7 +361,7 @@ const char *core_options::entry::minimum() const // entry::maximum //------------------------------------------------- -const char *core_options::entry::maximum() const +const char *core_options::entry::maximum() const noexcept { return nullptr; } @@ -258,7 +371,7 @@ const char *core_options::entry::maximum() const // entry::has_range //------------------------------------------------- -bool core_options::entry::has_range() const +bool core_options::entry::has_range() const noexcept { return minimum() && maximum(); } @@ -268,11 +381,10 @@ bool core_options::entry::has_range() const // entry::default_value //------------------------------------------------- -const std::string &core_options::entry::default_value() const +const std::string &core_options::entry::default_value() const noexcept { - // I don't really want this generally available, but MewUI seems to need it. Please - // do not use - throw false; + // I don't really want this generally available, but MewUI seems to need it. Please do not use. + abort(); } @@ -286,10 +398,12 @@ const std::string &core_options::entry::default_value() const 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; } @@ -307,25 +421,47 @@ core_options::simple_entry::~simple_entry() // simple_entry::value //------------------------------------------------- -const char *core_options::simple_entry::value() const +const char *core_options::simple_entry::value() const noexcept +{ + switch (type()) + { + case option_type::BOOLEAN: + case option_type::INTEGER: + case option_type::FLOAT: + case option_type::STRING: + case option_type::PATH: + case option_type::MULTIPATH: + return m_data.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::value_unsubstituted +//------------------------------------------------- + +const char *core_options::simple_entry::value_unsubstituted() const noexcept { - const char *result; 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: - result = m_data.c_str(); - break; + 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) - result = nullptr; - break; + return nullptr; } - return result; } @@ -333,7 +469,7 @@ const char *core_options::simple_entry::value() const // simple_entry::default_value //------------------------------------------------- -const std::string &core_options::simple_entry::default_value() const +const std::string &core_options::simple_entry::default_value() const noexcept { // only MewUI seems to need this; please don't use return m_defdata; @@ -341,12 +477,50 @@ const std::string &core_options::simple_entry::default_value() const //------------------------------------------------- -// 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 + { + switch (simple->type()) + { + case option_type::BOOLEAN: + case option_type::INTEGER: + case option_type::FLOAT: + case option_type::STRING: + case option_type::PATH: + case option_type::MULTIPATH: + validate(simple->m_data); + + m_data = simple->m_data; + m_data_unsubst = simple->m_data_unsubst; + + return true; + + default: + return false; + } + } } @@ -356,7 +530,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 = m_defdata_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); + } } @@ -364,7 +578,7 @@ void core_options::simple_entry::set_default_value(std::string &&newvalue) // minimum //------------------------------------------------- -const char *core_options::simple_entry::minimum() const +const char *core_options::simple_entry::minimum() const noexcept { return m_minimum.c_str(); } @@ -374,7 +588,7 @@ const char *core_options::simple_entry::minimum() const // maximum //------------------------------------------------- -const char *core_options::simple_entry::maximum() const +const char *core_options::simple_entry::maximum() const noexcept { return m_maximum.c_str(); } @@ -412,11 +626,7 @@ void core_options::add_entry(entry::shared_ptr &&entry, const char *after_header for (const std::string &name : entry->names()) { // append the entry - add_to_entry_map(std::string(name), entry); - - // for booleans, add the "-noXYZ" option as well - if (entry->type() == option_type::BOOLEAN) - add_to_entry_map(std::string("no") + name, entry); + add_to_entry_map(name, entry); } // and add the entry to the vector @@ -429,13 +639,13 @@ void core_options::add_entry(entry::shared_ptr &&entry, const char *after_header // map //------------------------------------------------- -void core_options::add_to_entry_map(std::string &&name, entry::shared_ptr &entry) +void core_options::add_to_entry_map(const std::string &name, entry::shared_ptr &entry) { // it is illegal to call this method for something that already exists assert(m_entrymap.find(name) == m_entrymap.end()); // append the entry - m_entrymap.emplace(std::make_pair(name, entry::weak_ptr(entry))); + m_entrymap.emplace(std::make_pair(std::string_view(name), entry::weak_ptr(entry))); } @@ -454,26 +664,39 @@ void core_options::add_entry(const options_entry &opt, bool override_existing) { // first extract any range std::string namestr(opt.name); - int lparen = namestr.find_first_of('(', 0); - int dash = namestr.find_first_of('-', lparen + 1); - int rparen = namestr.find_first_of(')', dash + 1); - if (lparen != -1 && dash != -1 && rparen != -1) + std::string::size_type lparen = namestr.find_first_of('(', 0); + if (lparen != std::string::npos) { - strtrimspace(minimum.assign(namestr.substr(lparen + 1, dash - (lparen + 1)))); - strtrimspace(maximum.assign(namestr.substr(dash + 1, rparen - (dash + 1)))); - namestr.erase(lparen, rparen + 1 - lparen); + std::string::size_type dash = namestr.find_first_of('-', lparen + 1); + if (dash != std::string::npos) + { + std::string::size_type rparen = namestr.find_first_of(')', dash + 1); + if (rparen != std::string::npos) + { + minimum.assign(strtrimspace(std::string_view(&namestr[lparen + 1], dash - (lparen + 1)))); + maximum.assign(strtrimspace(std::string_view(&namestr[dash + 1], rparen - (dash + 1)))); + namestr.erase(lparen, rparen + 1 - lparen); + } + } } // then chop up any semicolon-separated names - size_t semi; + std::string::size_type semi; while ((semi = namestr.find_first_of(';')) != std::string::npos) { names.push_back(namestr.substr(0, semi)); + + // for booleans, add the "-noXYZ" option as well + if (opt.type == option_type::BOOLEAN) + names.push_back(std::string("no") + names.back()); + namestr.erase(0, semi + 1); } // finally add the last item names.push_back(std::move(namestr)); + if (opt.type == option_type::BOOLEAN) + names.push_back(std::string("no") + names.back()); } // we might be called with an existing entry @@ -482,7 +705,7 @@ void core_options::add_entry(const options_entry &opt, bool override_existing) { for (const std::string &name : names) { - existing_entry = get_entry(name.c_str()); + existing_entry = get_entry(name); if (existing_entry) break; } @@ -558,10 +781,12 @@ void core_options::add_entries(const options_entry *entrylist, bool override_exi // of an option //------------------------------------------------- -void core_options::set_default_value(const char *name, const char *defvalue) +void core_options::set_default_value(std::string_view name, std::string &&defvalue) { // update the data and default data - get_entry(name)->set_default_value(defvalue); + auto entry = get_entry(name); + assert(entry != nullptr); + entry->set_default_value(std::move(defvalue)); } @@ -570,10 +795,12 @@ void core_options::set_default_value(const char *name, const char *defvalue) // of an option //------------------------------------------------- -void core_options::set_description(const char *name, const char *description) +void core_options::set_description(std::string_view name, const char *description) { // update the data and default data - get_entry(name)->set_description(description); + auto entry = get_entry(name); + assert(entry != nullptr); + entry->set_description(description); } @@ -596,7 +823,7 @@ void core_options::parse_command_line(const std::vector<std::string> &args, int if (!args[arg].empty() && args[arg][0] == '-') { auto curentry = get_entry(&args[arg][1]); - if (curentry && curentry->type() == OPTION_COMMAND) + if (curentry && curentry->type() == core_options::option_type::COMMAND) { // can only have one command if (!m_command.empty()) @@ -619,7 +846,7 @@ void core_options::parse_command_line(const std::vector<std::string> &args, int // special case - collect unadorned arguments after commands into a special place if (is_unadorned && !m_command.empty()) { - m_command_arguments.push_back(std::move(args[arg])); + m_command_arguments.push_back(args[arg]); command_argument_processed(); continue; } @@ -634,11 +861,11 @@ void core_options::parse_command_line(const std::vector<std::string> &args, int } // at this point, we've already processed commands - if (curentry->type() == OPTION_COMMAND) + if (curentry->type() == core_options::option_type::COMMAND) continue; // get the data for this argument, special casing booleans - std::string newdata; + std::string_view newdata; if (curentry->type() == option_type::BOOLEAN) { newdata = (strncmp(&curarg[1], "no", 2) == 0) ? "0" : "1"; @@ -657,7 +884,7 @@ void core_options::parse_command_line(const std::vector<std::string> &args, int } // set the new data - do_set_value(*curentry, std::move(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? @@ -677,7 +904,7 @@ void core_options::parse_ini_file(util::core_file &inifile, int priority, bool i // loop over lines in the file char buffer[4096]; - while (inifile.gets(buffer, ARRAY_LENGTH(buffer)) != nullptr) + while (inifile.gets(buffer, std::size(buffer)) != nullptr) { // find the extent of the name char *optionname; @@ -731,9 +958,7 @@ void core_options::parse_ini_file(util::core_file &inifile, int priority, bool i } // set the new data - std::string data = optiondata; - trim_spaces_and_quotes(data); - do_set_value(*curentry, std::move(data), 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? @@ -777,13 +1002,9 @@ void core_options::copy_from(const core_options &that) if (dest_entry->names().size() > 0) { // identify the source entry - const entry::shared_ptr source_entry = that.get_entry(dest_entry->name()); + 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); } } } @@ -799,6 +1020,7 @@ std::string core_options::output_ini(const core_options *diff) const { // INI files are complete, so always start with a blank buffer std::ostringstream buffer; + buffer.imbue(std::locale::classic()); int num_valid_headers = 0; int unadorned_index = 0; @@ -816,7 +1038,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; @@ -830,7 +1052,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) @@ -869,13 +1091,16 @@ std::string core_options::output_help() const // loop over all items for (auto &curentry : m_entries) { - // header: just print if (curentry->type() == option_type::HEADER) + { + // header: just print util::stream_format(buffer, "\n#\n# %s\n#\n", curentry->description()); - - // otherwise, output entries for all non-deprecated items + } else if (curentry->description() != nullptr) - util::stream_format(buffer, "-%-20s%s\n", curentry->name(), curentry->description()); + { + // otherwise, output entries for all non-deprecated items + util::stream_format(buffer, "-%-19s %s\n", curentry->name(), curentry->description()); + } } return buffer.str(); } @@ -885,9 +1110,10 @@ std::string core_options::output_help() const // value - return the raw option value //------------------------------------------------- -const char *core_options::value(const char *option) const +const char *core_options::value(std::string_view option) const noexcept { - return get_entry(option)->value(); + auto const entry = get_entry(option); + return entry ? entry->value() : nullptr; } @@ -895,9 +1121,48 @@ const char *core_options::value(const char *option) const // description - return description of option //------------------------------------------------- -const char *core_options::description(const char *option) const +const char *core_options::description(std::string_view option) const noexcept +{ + auto const entry = get_entry(option); + return entry ? entry->description() : nullptr; +} + + +//------------------------------------------------- +// value - return the option value as an integer +//------------------------------------------------- + +int core_options::int_value(std::string_view option) const { - return get_entry(option)->description(); + char const *const data = value(option); + if (!data) + return 0; + std::istringstream str(data); + str.imbue(std::locale::classic()); + int ival; + if (str >> ival) + return ival; + else + return 0; +} + + +//------------------------------------------------- +// value - return the option value as a float +//------------------------------------------------- + +float core_options::float_value(std::string_view option) const +{ + char const *const data = value(option); + if (!data) + return 0.0f; + std::istringstream str(data); + str.imbue(std::locale::classic()); + float fval; + if (str >> fval) + return fval; + else + return 0.0f; } @@ -909,24 +1174,31 @@ const char *core_options::description(const char *option) const // set_value - set the raw option value //------------------------------------------------- -void core_options::set_value(const std::string &name, const std::string &value, int priority) +void core_options::set_value(std::string_view name, std::string_view value, int priority) +{ + set_value(name, std::string(value), priority); +} + +void core_options::set_value(std::string_view name, const char *value, int priority) { set_value(name, std::string(value), priority); } -void core_options::set_value(const std::string &name, std::string &&value, int priority) +void core_options::set_value(std::string_view name, std::string &&value, int priority) { - get_entry(name)->set_value(std::move(value), priority); + auto entry = get_entry(name); + assert(entry != nullptr); + entry->set_value(std::move(value), priority, false, false); } -void core_options::set_value(const std::string &name, int value, int priority) +void core_options::set_value(std::string_view name, int value, int priority) { - set_value(name, string_format("%d", value), priority); + set_value(name, util::string_format("%d", value), priority); } -void core_options::set_value(const std::string &name, float value, int priority) +void core_options::set_value(std::string_view name, float value, int priority) { - set_value(name, string_format("%f", value), priority); + set_value(name, util::string_format("%f", value), priority); } @@ -957,13 +1229,13 @@ void core_options::remove_entry(core_options::entry &delentry) // do_set_value //------------------------------------------------- -void core_options::do_set_value(entry &curentry, std::string &&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::move(data), priority); + curentry.set_value(std::string(data), priority, false, perform_substitutions); } catch (options_warning_exception &ex) { @@ -984,13 +1256,13 @@ void core_options::do_set_value(entry &curentry, std::string &&data, int priorit // get_entry //------------------------------------------------- -const core_options::entry::shared_ptr core_options::get_entry(const std::string &name) const +core_options::entry::shared_const_ptr core_options::get_entry(std::string_view name) const noexcept { auto curentry = m_entrymap.find(name); return (curentry != m_entrymap.end()) ? curentry->second.lock() : nullptr; } -core_options::entry::shared_ptr core_options::get_entry(const std::string &name) +core_options::entry::shared_ptr core_options::get_entry(std::string_view name) noexcept { auto curentry = m_entrymap.find(name); return (curentry != m_entrymap.end()) ? curentry->second.lock() : nullptr; @@ -1001,9 +1273,11 @@ core_options::entry::shared_ptr core_options::get_entry(const std::string &name) // set_value_changed_handler //------------------------------------------------- -void core_options::set_value_changed_handler(const std::string &name, std::function<void(const char *)> &&handler) +void core_options::set_value_changed_handler(std::string_view name, std::function<void(const char *)> &&handler) { - get_entry(name)->set_value_changed_handler(std::move(handler)); + auto entry = get_entry(name); + assert(entry != nullptr); + entry->set_value_changed_handler(std::move(handler)); } @@ -1011,17 +1285,17 @@ void core_options::set_value_changed_handler(const std::string &name, std::funct // header_exists //------------------------------------------------- -bool core_options::header_exists(const char *description) const +bool core_options::header_exists(const char *description) const noexcept { auto iter = std::find_if( - m_entries.begin(), - m_entries.end(), - [description](const auto &entry) - { - return entry->type() == option_type::HEADER - && entry->description() - && !strcmp(entry->description(), description); - }); + m_entries.begin(), + m_entries.end(), + [description](const auto &entry) + { + return entry->type() == option_type::HEADER + && entry->description() + && !strcmp(entry->description(), description); + }); return iter != m_entries.end(); } @@ -1034,7 +1308,7 @@ bool core_options::header_exists(const char *description) const void core_options::revert(int priority_hi, int priority_lo) { for (entry::shared_ptr &curentry : m_entries) - if (curentry->type() != option_type::HEADER) + if (curentry->type() != option_type::HEADER && curentry->type() != option_type::COMMAND) curentry->revert(priority_hi, priority_lo); } @@ -1048,7 +1322,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); } } |