X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fsettings.cpp;h=55404319e8f9615a6f57b2ec5bdb42c9d41f38d6;hb=f780bae05cc2fdd23a6d7326c770783da8d94ea3;hp=8d2e9fa6c8a699c0240e19dabdacdc8977da277c;hpb=b0c4fd6d3f1c8e44896358ee9b0af20e9b304944;p=dragonfireclient.git diff --git a/src/settings.cpp b/src/settings.cpp index 8d2e9fa6c..55404319e 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -20,8 +20,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "irrlichttypes_bloated.h" #include "exceptions.h" -#include "jthread/jmutexautolock.h" -#include "strfnd.h" +#include "threading/mutex_auto_lock.h" +#include "util/strfnd.h" #include #include #include @@ -33,6 +33,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include +static Settings main_settings; +Settings *g_settings = &main_settings; +std::string g_settings_path; Settings::~Settings() { @@ -53,8 +56,8 @@ Settings & Settings::operator = (const Settings &other) if (&other == this) return *this; - JMutexAutoLock lock(m_mutex); - JMutexAutoLock lock2(other.m_mutex); + MutexAutoLock lock(m_mutex); + MutexAutoLock lock2(other.m_mutex); clearNoLock(); updateNoLock(other); @@ -63,32 +66,32 @@ Settings & Settings::operator = (const Settings &other) } -std::string Settings::sanitizeName(const std::string &name) +bool Settings::checkNameValid(const std::string &name) { - std::string n(name); + bool valid = name.find_first_of("=\"{}#") == std::string::npos; + if (valid) + valid = std::find_if(name.begin(), name.end(), ::isspace) == name.end(); - for (const char *s = "\t\n\v\f\r\b =\"{}#"; *s; s++) - n.erase(std::remove(n.begin(), n.end(), *s), n.end()); - - return n; + if (!valid) { + errorstream << "Invalid setting name \"" << name << "\"" + << std::endl; + return false; + } + return true; } -std::string Settings::sanitizeValue(const std::string &value) +bool Settings::checkValueValid(const std::string &value) { - std::string v(value); - size_t p = 0; - - if (v.substr(0, 3) == "\"\"\"") - v.erase(0, 3); - - while ((p = v.find("\n\"\"\"")) != std::string::npos) - v.erase(p, 4); - - return v; + if (value.substr(0, 3) == "\"\"\"" || + value.find("\n\"\"\"") != std::string::npos) { + errorstream << "Invalid character sequence '\"\"\"' found in" + " setting value!" << std::endl; + return false; + } + return true; } - std::string Settings::getMultiline(std::istream &is, size_t *num_lines) { size_t lines = 1; @@ -127,7 +130,7 @@ bool Settings::readConfigFile(const char *filename) bool Settings::parseConfigLines(std::istream &is, const std::string &end) { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); std::string line, name, value; @@ -166,12 +169,10 @@ bool Settings::parseConfigLines(std::istream &is, const std::string &end) void Settings::writeLines(std::ostream &os, u32 tab_depth) const { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); - for (std::map::const_iterator - it = m_settings.begin(); - it != m_settings.end(); ++it) - printEntry(os, it->first, it->second, tab_depth); + for (const auto &setting_it : m_settings) + printEntry(os, setting_it.first, setting_it.second, tab_depth); } @@ -203,7 +204,7 @@ void Settings::printEntry(std::ostream &os, const std::string &name, bool Settings::updateConfigObject(std::istream &is, std::ostream &os, const std::string &end, u32 tab_depth) { - std::map::const_iterator it; + SettingEntries::const_iterator it; std::set present_entries; std::string line, name, value; bool was_modified = false; @@ -226,11 +227,14 @@ bool Settings::updateConfigObject(std::istream &is, std::ostream &os, case SPE_KVPAIR: it = m_settings.find(name); if (it != m_settings.end() && - (it->second.is_group || it->second.value != value)) { + (it->second.is_group || it->second.value != value)) { printEntry(os, name, it->second, tab_depth); was_modified = true; + } else if (it == m_settings.end()) { + // Remove by skipping + was_modified = true; + break; } else { - assert(it->second.group == NULL); os << line << "\n"; if (event == SPE_MULTILINE) os << value << "\n\"\"\"\n"; @@ -241,9 +245,16 @@ bool Settings::updateConfigObject(std::istream &is, std::ostream &os, it = m_settings.find(name); if (it != m_settings.end() && it->second.is_group) { os << line << "\n"; - assert(it->second.group != NULL); + sanity_check(it->second.group != NULL); was_modified |= it->second.group->updateConfigObject(is, os, "}", tab_depth + 1); + } else if (it == m_settings.end()) { + // Remove by skipping + was_modified = true; + Settings removed_group; // Move 'is' to group end + std::stringstream ss; + removed_group.updateConfigObject(is, ss, "}", tab_depth + 1); + break; } else { printEntry(os, name, it->second, tab_depth); was_modified = true; @@ -271,7 +282,7 @@ bool Settings::updateConfigObject(std::istream &is, std::ostream &os, bool Settings::updateConfigFile(const char *filename) { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); std::ifstream is(filename); std::ostringstream os(std::ios_base::binary); @@ -324,7 +335,7 @@ bool Settings::parseCommandLine(int argc, char *argv[], ValueType type = n->second.type; - std::string value = ""; + std::string value; if (type == VALUETYPE_FLAG) { value = "true"; @@ -352,9 +363,9 @@ bool Settings::parseCommandLine(int argc, char *argv[], const SettingsEntry &Settings::getEntry(const std::string &name) const { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); - std::map::const_iterator n; + SettingEntries::const_iterator n; if ((n = m_settings.find(name)) == m_settings.end()) { if ((n = m_defaults.find(name)) == m_defaults.end()) throw SettingNotFoundException("Setting [" + name + "] not found."); @@ -363,6 +374,18 @@ const SettingsEntry &Settings::getEntry(const std::string &name) const } +const SettingsEntry &Settings::getEntryDefault(const std::string &name) const +{ + MutexAutoLock lock(m_mutex); + + SettingEntries::const_iterator n; + if ((n = m_defaults.find(name)) == m_defaults.end()) { + throw SettingNotFoundException("Setting [" + name + "] not found."); + } + return n->second; +} + + Settings *Settings::getGroup(const std::string &name) const { const SettingsEntry &entry = getEntry(name); @@ -372,7 +395,7 @@ Settings *Settings::getGroup(const std::string &name) const } -std::string Settings::get(const std::string &name) const +const std::string &Settings::get(const std::string &name) const { const SettingsEntry &entry = getEntry(name); if (entry.is_group) @@ -381,6 +404,15 @@ std::string Settings::get(const std::string &name) const } +const std::string &Settings::getDefault(const std::string &name) const +{ + const SettingsEntry &entry = getEntryDefault(name); + if (entry.is_group) + throw SettingNotFoundException("Setting [" + name + "] is a group."); + return entry.value; +} + + bool Settings::getBool(const std::string &name) const { return is_yes(get(name)); @@ -399,6 +431,11 @@ s16 Settings::getS16(const std::string &name) const } +u32 Settings::getU32(const std::string &name) const +{ + return (u32) stoi(get(name)); +} + s32 Settings::getS32(const std::string &name) const { return stoi(get(name)); @@ -447,12 +484,33 @@ v3f Settings::getV3F(const std::string &name) const u32 Settings::getFlagStr(const std::string &name, const FlagDesc *flagdesc, u32 *flagmask) const { - std::string val = get(name); - return std::isdigit(val[0]) - ? stoi(val) - : readFlagString(val, flagdesc, flagmask); -} + u32 flags = 0; + u32 mask_default = 0; + std::string value; + // Read default value (if there is any) + if (getDefaultNoEx(name, value)) { + flags = std::isdigit(value[0]) + ? stoi(value) + : readFlagString(value, flagdesc, &mask_default); + } + + // Apply custom flags "on top" + value = get(name); + u32 flags_user; + u32 mask_user = U32_MAX; + flags_user = std::isdigit(value[0]) + ? stoi(value) // Override default + : readFlagString(value, flagdesc, &mask_user); + + flags &= ~mask_user; + flags |= flags_user; + + if (flagmask) + *flagmask = mask_default | mask_user; + + return flags; +} // N.B. if getStruct() is used to read a non-POD aggregate type, // the behavior is undefined. @@ -502,7 +560,7 @@ bool Settings::getNoiseParamsFromValue(const std::string &name, np.persist = stof(f.next(",")); std::string optional_params = f.next(""); - if (optional_params != "") + if (!optional_params.empty()) np.lacunarity = stof(optional_params); return true; @@ -535,7 +593,7 @@ bool Settings::getNoiseParamsFromGroup(const std::string &name, bool Settings::exists(const std::string &name) const { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); return (m_settings.find(name) != m_settings.end() || m_defaults.find(name) != m_defaults.end()); @@ -545,10 +603,8 @@ bool Settings::exists(const std::string &name) const std::vector Settings::getNames() const { std::vector names; - for (std::map::const_iterator - i = m_settings.begin(); - i != m_settings.end(); ++i) { - names.push_back(i->first); + for (const auto &settings_it : m_settings) { + names.push_back(settings_it.first); } return names; } @@ -570,6 +626,17 @@ bool Settings::getEntryNoEx(const std::string &name, SettingsEntry &val) const } +bool Settings::getEntryDefaultNoEx(const std::string &name, SettingsEntry &val) const +{ + try { + val = getEntryDefault(name); + return true; + } catch (SettingNotFoundException &e) { + return false; + } +} + + bool Settings::getGroupNoEx(const std::string &name, Settings *&val) const { try { @@ -592,6 +659,17 @@ bool Settings::getNoEx(const std::string &name, std::string &val) const } +bool Settings::getDefaultNoEx(const std::string &name, std::string &val) const +{ + try { + val = getDefault(name); + return true; + } catch (SettingNotFoundException &e) { + return false; + } +} + + bool Settings::getFlag(const std::string &name) const { try { @@ -679,19 +757,16 @@ bool Settings::getV3FNoEx(const std::string &name, v3f &val) const } -// N.B. getFlagStrNoEx() does not set val, but merely modifies it. Thus, -// val must be initialized before using getFlagStrNoEx(). The intention of -// this is to simplify modifying a flags field from a default value. bool Settings::getFlagStrNoEx(const std::string &name, u32 &val, - FlagDesc *flagdesc) const + const FlagDesc *flagdesc) const { - try { - u32 flags, flagmask; - - flags = getFlagStr(name, flagdesc, &flagmask); + if (!flagdesc) { + if (!(flagdesc = getFlagDescFallback(name))) + return false; // Not found + } - val &= ~flagmask; - val |= flags; + try { + val = getFlagStr(name, flagdesc, nullptr); return true; } catch (SettingNotFoundException &e) { @@ -704,112 +779,124 @@ bool Settings::getFlagStrNoEx(const std::string &name, u32 &val, * Setters * ***********/ -void Settings::setEntry(const std::string &name, const void *data, +bool Settings::setEntry(const std::string &name, const void *data, bool set_group, bool set_default) { Settings *old_group = NULL; - std::string n = sanitizeName(name); + if (!checkNameValid(name)) + return false; + if (!set_group && !checkValueValid(*(const std::string *)data)) + return false; { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); - SettingsEntry &entry = set_default ? m_defaults[n] : m_settings[n]; + SettingsEntry &entry = set_default ? m_defaults[name] : m_settings[name]; old_group = entry.group; - entry.value = set_group ? "" : sanitizeValue(*(const std::string *)data); + entry.value = set_group ? "" : *(const std::string *)data; entry.group = set_group ? *(Settings **)data : NULL; entry.is_group = set_group; } delete old_group; + + return true; } -void Settings::set(const std::string &name, const std::string &value) +bool Settings::set(const std::string &name, const std::string &value) { - setEntry(name, &value, false, false); + if (!setEntry(name, &value, false, false)) + return false; doCallbacks(name); + return true; } -void Settings::setDefault(const std::string &name, const std::string &value) +bool Settings::setDefault(const std::string &name, const std::string &value) { - setEntry(name, &value, false, true); + return setEntry(name, &value, false, true); } -void Settings::setGroup(const std::string &name, Settings *group) +bool Settings::setGroup(const std::string &name, Settings *group) { - setEntry(name, &group, true, false); + return setEntry(name, &group, true, false); } -void Settings::setGroupDefault(const std::string &name, Settings *group) +bool Settings::setGroupDefault(const std::string &name, Settings *group) { - setEntry(name, &group, true, true); + return setEntry(name, &group, true, true); } -void Settings::setBool(const std::string &name, bool value) +bool Settings::setBool(const std::string &name, bool value) { - set(name, value ? "true" : "false"); + return set(name, value ? "true" : "false"); } -void Settings::setS16(const std::string &name, s16 value) +bool Settings::setS16(const std::string &name, s16 value) { - set(name, itos(value)); + return set(name, itos(value)); } -void Settings::setU16(const std::string &name, u16 value) +bool Settings::setU16(const std::string &name, u16 value) { - set(name, itos(value)); + return set(name, itos(value)); } -void Settings::setS32(const std::string &name, s32 value) +bool Settings::setS32(const std::string &name, s32 value) { - set(name, itos(value)); + return set(name, itos(value)); } -void Settings::setU64(const std::string &name, u64 value) +bool Settings::setU64(const std::string &name, u64 value) { std::ostringstream os; os << value; - set(name, os.str()); + return set(name, os.str()); } -void Settings::setFloat(const std::string &name, float value) +bool Settings::setFloat(const std::string &name, float value) { - set(name, ftos(value)); + return set(name, ftos(value)); } -void Settings::setV2F(const std::string &name, v2f value) +bool Settings::setV2F(const std::string &name, v2f value) { std::ostringstream os; os << "(" << value.X << "," << value.Y << ")"; - set(name, os.str()); + return set(name, os.str()); } -void Settings::setV3F(const std::string &name, v3f value) +bool Settings::setV3F(const std::string &name, v3f value) { std::ostringstream os; os << "(" << value.X << "," << value.Y << "," << value.Z << ")"; - set(name, os.str()); + return set(name, os.str()); } -void Settings::setFlagStr(const std::string &name, u32 flags, +bool Settings::setFlagStr(const std::string &name, u32 flags, const FlagDesc *flagdesc, u32 flagmask) { - set(name, writeFlagString(flags, flagdesc, flagmask)); + if (!flagdesc) { + if (!(flagdesc = getFlagDescFallback(name))) + return false; // Not found + } + + return set(name, writeFlagString(flags, flagdesc, flagmask)); } @@ -820,12 +907,11 @@ bool Settings::setStruct(const std::string &name, const std::string &format, if (!serializeStructToString(&structstr, format, value)) return false; - set(name, structstr); - return true; + return set(name, structstr); } -void Settings::setNoiseParams(const std::string &name, +bool Settings::setNoiseParams(const std::string &name, const NoiseParams &np, bool set_default) { Settings *group = new Settings; @@ -839,37 +925,51 @@ void Settings::setNoiseParams(const std::string &name, group->setFloat("lacunarity", np.lacunarity); group->setFlagStr("flags", np.flags, flagdesc_noiseparams, np.flags); - setEntry(name, &group, true, set_default); + return setEntry(name, &group, true, set_default); } bool Settings::remove(const std::string &name) { - JMutexAutoLock lock(m_mutex); + // Lock as short as possible, unlock before doCallbacks() + m_mutex.lock(); + + SettingEntries::iterator it = m_settings.find(name); + if (it != m_settings.end()) { + delete it->second.group; + m_settings.erase(it); + m_mutex.unlock(); - delete m_settings[name].group; - return m_settings.erase(name); + doCallbacks(name); + return true; + } + + m_mutex.unlock(); + return false; } void Settings::clear() { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); clearNoLock(); } +void Settings::clearDefaults() +{ + MutexAutoLock lock(m_mutex); + clearDefaultsNoLock(); +} void Settings::updateValue(const Settings &other, const std::string &name) { if (&other == this) return; - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); try { - std::string val = other.get(name); - - m_settings[name] = val; + m_settings[name] = other.get(name); } catch (SettingNotFoundException &e) { } } @@ -880,8 +980,8 @@ void Settings::update(const Settings &other) if (&other == this) return; - JMutexAutoLock lock(m_mutex); - JMutexAutoLock lock2(other.m_mutex); + MutexAutoLock lock(m_mutex); + MutexAutoLock lock2(other.m_mutex); updateNoLock(other); } @@ -924,38 +1024,92 @@ void Settings::updateNoLock(const Settings &other) void Settings::clearNoLock() { - std::map::const_iterator it; - for (it = m_settings.begin(); it != m_settings.end(); ++it) + + for (SettingEntries::const_iterator it = m_settings.begin(); + it != m_settings.end(); ++it) delete it->second.group; m_settings.clear(); - for (it = m_defaults.begin(); it != m_defaults.end(); ++it) + clearDefaultsNoLock(); +} + +void Settings::clearDefaultsNoLock() +{ + for (SettingEntries::const_iterator it = m_defaults.begin(); + it != m_defaults.end(); ++it) delete it->second.group; m_defaults.clear(); } +void Settings::setDefault(const std::string &name, const FlagDesc *flagdesc, + u32 flags) +{ + m_flags[name] = flagdesc; + setDefault(name, writeFlagString(flags, flagdesc, U32_MAX)); +} + +void Settings::overrideDefaults(Settings *other) +{ + for (const auto &setting : other->m_settings) { + if (setting.second.is_group) { + setGroupDefault(setting.first, setting.second.group); + continue; + } + const FlagDesc *flagdesc = getFlagDescFallback(setting.first); + if (flagdesc) { + // Flags cannot be copied directly. + // 1) Get the current set flags + u32 flags = getFlagStr(setting.first, flagdesc, nullptr); + // 2) Set the flags as defaults + other->setDefault(setting.first, flagdesc, flags); + // 3) Get the newly set flags and override the default setting value + setDefault(setting.first, flagdesc, + other->getFlagStr(setting.first, flagdesc, nullptr)); + continue; + } + // Also covers FlagDesc settings + setDefault(setting.first, setting.second.value); + } +} -void Settings::registerChangedCallback(std::string name, - setting_changed_callback cbf) +const FlagDesc *Settings::getFlagDescFallback(const std::string &name) const { - m_callbacks[name].push_back(cbf); + auto it = m_flags.find(name); + return it == m_flags.end() ? nullptr : it->second; } +void Settings::registerChangedCallback(const std::string &name, + SettingsChangedCallback cbf, void *userdata) +{ + MutexAutoLock lock(m_callback_mutex); + m_callbacks[name].emplace_back(cbf, userdata); +} -void Settings::doCallbacks(const std::string name) +void Settings::deregisterChangedCallback(const std::string &name, + SettingsChangedCallback cbf, void *userdata) { - std::vector tempvector; - { - JMutexAutoLock lock(m_mutex); - if (m_callbacks.find(name) != m_callbacks.end()) - { - tempvector = m_callbacks[name]; - } + MutexAutoLock lock(m_callback_mutex); + SettingsCallbackMap::iterator it_cbks = m_callbacks.find(name); + + if (it_cbks != m_callbacks.end()) { + SettingsCallbackList &cbks = it_cbks->second; + + SettingsCallbackList::iterator position = + std::find(cbks.begin(), cbks.end(), std::make_pair(cbf, userdata)); + + if (position != cbks.end()) + cbks.erase(position); } +} - std::vector::iterator iter; - for (iter = tempvector.begin(); iter != tempvector.end(); iter++) - { - (*iter)(name); +void Settings::doCallbacks(const std::string &name) const +{ + MutexAutoLock lock(m_callback_mutex); + + SettingsCallbackMap::const_iterator it_cbks = m_callbacks.find(name); + if (it_cbks != m_callbacks.end()) { + SettingsCallbackList::const_iterator it; + for (it = it_cbks->second.begin(); it != it_cbks->second.end(); ++it) + (it->first)(name, it->second); } }