X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fsettings.cpp;h=e95bd436d527dcda81df3d98186380880ca90712;hb=c6766b275f25368e78eeffc68719b0ca1979c819;hp=34348cc06fde032ff6e0e8ef2d710321b1e15896;hpb=360660947b8137fba78981932de6b503b9889e62;p=oweals%2Fminetest.git diff --git a/src/settings.cpp b/src/settings.cpp index 34348cc06..e95bd436d 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -29,14 +29,17 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" #include "util/serialize.h" #include "filesys.h" +#include "noise.h" #include +#include +static Settings main_settings; +Settings *g_settings = &main_settings; +std::string g_settings_path; Settings::~Settings() { - std::map::const_iterator it; - for (it = m_settings.begin(); it != m_settings.end(); ++it) - delete it->second.group; + clear(); } @@ -63,22 +66,65 @@ Settings & Settings::operator = (const Settings &other) } -std::string Settings::sanitizeString(const std::string &value) +bool Settings::checkNameValid(const std::string &name) +{ + bool valid = name.find_first_of("=\"{}#") == std::string::npos; + if (valid) valid = trim(name) == name; + if (!valid) { + errorstream << "Invalid setting name \"" << name << "\"" + << std::endl; + return false; + } + return true; +} + + +bool Settings::checkValueValid(const std::string &value) { - std::string str = value; - for (const char *s = "\t\n\v\f\r\b =\""; *s; s++) - str.erase(std::remove(str.begin(), str.end(), *s), str.end()); + 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; +} + - return str; +std::string Settings::sanitizeName(const std::string &name) +{ + std::string n = trim(name); + + for (const char *s = "=\"{}#"; *s; s++) + n.erase(std::remove(n.begin(), n.end(), *s), n.end()); + + return n; } -std::string Settings::getMultiline(std::istream &is) +std::string Settings::sanitizeValue(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; +} + + +std::string Settings::getMultiline(std::istream &is, size_t *num_lines) +{ + size_t lines = 1; std::string value; std::string line; while (is.good()) { + lines++; std::getline(is, line); if (line == "\"\"\"") break; @@ -90,10 +136,23 @@ std::string Settings::getMultiline(std::istream &is) if (len) value.erase(len - 1); + if (num_lines) + *num_lines = lines; + return value; } +bool Settings::readConfigFile(const char *filename) +{ + std::ifstream is(filename); + if (!is.good()) + return false; + + return parseConfigLines(is, ""); +} + + bool Settings::parseConfigLines(std::istream &is, const std::string &end) { JMutexAutoLock lock(m_mutex); @@ -115,11 +174,12 @@ bool Settings::parseConfigLines(std::istream &is, const std::string &end) case SPE_END: return true; case SPE_GROUP: { - Settings *branch = new Settings; - if (!branch->parseConfigLines(is, "}")) + Settings *group = new Settings; + if (!group->parseConfigLines(is, "}")) { + delete group; return false; - - m_settings[name] = SettingsEntry(branch); + } + m_settings[name] = SettingsEntry(group); break; } case SPE_MULTILINE: @@ -132,53 +192,38 @@ bool Settings::parseConfigLines(std::istream &is, const std::string &end) } -bool Settings::readConfigFile(const char *filename) -{ - std::ifstream is(filename); - if (!is.good()) - return false; - - return parseConfigLines(is, ""); -} - - void Settings::writeLines(std::ostream &os, u32 tab_depth) const { JMutexAutoLock lock(m_mutex); for (std::map::const_iterator it = m_settings.begin(); - it != m_settings.end(); ++it) { - bool is_multiline = it->second.value.find('\n') != std::string::npos; - printValue(os, it->first, it->second, is_multiline, tab_depth); - } + it != m_settings.end(); ++it) + printEntry(os, it->first, it->second, tab_depth); } -void Settings::printValue(std::ostream &os, const std::string &name, - const SettingsEntry &entry, bool is_value_multiline, u32 tab_depth) +void Settings::printEntry(std::ostream &os, const std::string &name, + const SettingsEntry &entry, u32 tab_depth) { for (u32 i = 0; i != tab_depth; i++) os << "\t"; - os << name << " = "; - - if (is_value_multiline) - os << "\"\"\"\n" << entry.value << "\n\"\"\"\n"; - else - os << entry.value << "\n"; - - Settings *group = entry.group; - if (group) { - for (u32 i = 0; i != tab_depth; i++) - os << "\t"; + if (entry.is_group) { os << name << " = {\n"; - group->writeLines(os, tab_depth + 1); + + entry.group->writeLines(os, tab_depth + 1); for (u32 i = 0; i != tab_depth; i++) os << "\t"; - os << "}\n"; + } else { + os << name << " = "; + + if (entry.value.find('\n') != std::string::npos) + os << "\"\"\"\n" << entry.value << "\n\"\"\"\n"; + else + os << entry.value << "\n"; } } @@ -187,10 +232,10 @@ bool Settings::updateConfigObject(std::istream &is, std::ostream &os, const std::string &end, u32 tab_depth) { std::map::const_iterator it; - std::set settings_in_config; + std::set present_entries; + std::string line, name, value; bool was_modified = false; bool end_found = false; - std::string line, name, value; // Add any settings that exist in the config file with the current value // in the object if existing @@ -200,49 +245,38 @@ bool Settings::updateConfigObject(std::istream &is, std::ostream &os, switch (event) { case SPE_END: + os << line << (is.eof() ? "" : "\n"); end_found = true; break; - case SPE_KVPAIR: case SPE_MULTILINE: + value = getMultiline(is); + /* FALLTHROUGH */ + case SPE_KVPAIR: it = m_settings.find(name); - if (it != m_settings.end()) { + if (it != m_settings.end() && + (it->second.is_group || it->second.value != value)) { + printEntry(os, name, it->second, tab_depth); + was_modified = true; + } else { + os << line << "\n"; if (event == SPE_MULTILINE) - value = getMultiline(is); - - if (value != it->second.value) { - value = it->second.value; - was_modified = true; - } + os << value << "\n\"\"\"\n"; } - - settings_in_config.insert(name); - - printValue(os, name, SettingsEntry(value), - event == SPE_MULTILINE, tab_depth); - + present_entries.insert(name); break; - case SPE_GROUP: { - Settings *group = NULL; + case SPE_GROUP: it = m_settings.find(name); - if (it != m_settings.end()) - group = it->second.group; - - settings_in_config.insert(name); - - os << name << " = {\n"; - - if (group) { - was_modified |= group->updateConfigObject(is, os, "}", tab_depth + 1); + if (it != m_settings.end() && it->second.is_group) { + os << line << "\n"; + sanity_check(it->second.group != NULL); + was_modified |= it->second.group->updateConfigObject(is, os, + "}", tab_depth + 1); } else { - Settings dummy_settings; - dummy_settings.updateConfigObject(is, os, "}", tab_depth + 1); + printEntry(os, name, it->second, tab_depth); + was_modified = true; } - - for (u32 i = 0; i != tab_depth; i++) - os << "\t"; - os << "}\n"; + present_entries.insert(name); break; - } default: os << line << (is.eof() ? "" : "\n"); break; @@ -251,13 +285,11 @@ bool Settings::updateConfigObject(std::istream &is, std::ostream &os, // Add any settings in the object that don't exist in the config file yet for (it = m_settings.begin(); it != m_settings.end(); ++it) { - if (settings_in_config.find(it->first) != settings_in_config.end()) + if (present_entries.find(it->first) != present_entries.end()) continue; + printEntry(os, it->first, it->second, tab_depth); was_modified = true; - - bool is_multiline = it->second.value.find('\n') != std::string::npos; - printValue(os, it->first, it->second, is_multiline, tab_depth); } return was_modified; @@ -271,7 +303,10 @@ bool Settings::updateConfigFile(const char *filename) std::ifstream is(filename); std::ostringstream os(std::ios_base::binary); - if (!updateConfigObject(is, os, "")) + bool was_modified = updateConfigObject(is, os, ""); + is.close(); + + if (!was_modified) return true; if (!fs::safeWriteToFile(filename, os.str())) { @@ -357,13 +392,19 @@ const SettingsEntry &Settings::getEntry(const std::string &name) const Settings *Settings::getGroup(const std::string &name) const { - return getEntry(name).group; + const SettingsEntry &entry = getEntry(name); + if (!entry.is_group) + throw SettingNotFoundException("Setting [" + name + "] is not a group."); + return entry.group; } std::string Settings::get(const std::string &name) const { - return getEntry(name).value; + const SettingsEntry &entry = getEntry(name); + if (entry.is_group) + throw SettingNotFoundException("Setting [" + name + "] is a group."); + return entry.value; } @@ -460,6 +501,65 @@ bool Settings::getStruct(const std::string &name, const std::string &format, } +bool Settings::getNoiseParams(const std::string &name, NoiseParams &np) const +{ + return getNoiseParamsFromGroup(name, np) || getNoiseParamsFromValue(name, np); +} + + +bool Settings::getNoiseParamsFromValue(const std::string &name, + NoiseParams &np) const +{ + std::string value; + + if (!getNoEx(name, value)) + return false; + + Strfnd f(value); + + np.offset = stof(f.next(",")); + np.scale = stof(f.next(",")); + f.next("("); + np.spread.X = stof(f.next(",")); + np.spread.Y = stof(f.next(",")); + np.spread.Z = stof(f.next(")")); + f.next(","); + np.seed = stoi(f.next(",")); + np.octaves = stoi(f.next(",")); + np.persist = stof(f.next(",")); + + std::string optional_params = f.next(""); + if (optional_params != "") + np.lacunarity = stof(optional_params); + + return true; +} + + +bool Settings::getNoiseParamsFromGroup(const std::string &name, + NoiseParams &np) const +{ + Settings *group = NULL; + + if (!getGroupNoEx(name, group)) + return false; + + group->getFloatNoEx("offset", np.offset); + group->getFloatNoEx("scale", np.scale); + group->getV3FNoEx("spread", np.spread); + group->getS32NoEx("seed", np.seed); + group->getU16NoEx("octaves", np.octaves); + group->getFloatNoEx("persistence", np.persist); + group->getFloatNoEx("lacunarity", np.lacunarity); + + np.flags = 0; + if (!group->getFlagStrNoEx("flags", np.flags, flagdesc_noiseparams)) + np.flags = NOISE_FLAG_DEFAULTS; + + return true; +} + + bool Settings::exists(const std::string &name) const { JMutexAutoLock lock(m_mutex); @@ -631,93 +731,119 @@ bool Settings::getFlagStrNoEx(const std::string &name, u32 &val, * Setters * ***********/ - -void Settings::set(const std::string &name, const std::string &value) +bool Settings::setEntry(const std::string &name, const void *data, + bool set_group, bool set_default) { - JMutexAutoLock lock(m_mutex); + Settings *old_group = NULL; + + if (!checkNameValid(name)) + return false; + if (!set_group && !checkValueValid(*(const std::string *)data)) + return false; + + { + JMutexAutoLock lock(m_mutex); - m_settings[name].value = value; + SettingsEntry &entry = set_default ? m_defaults[name] : m_settings[name]; + old_group = entry.group; + + 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::setGroup(const std::string &name, Settings *group) +bool Settings::set(const std::string &name, const std::string &value) { - JMutexAutoLock lock(m_mutex); + if (!setEntry(name, &value, false, false)) + return false; - delete m_settings[name].group; - m_settings[name].group = group; + 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) { - JMutexAutoLock lock(m_mutex); + return setEntry(name, &value, false, true); +} + - m_defaults[name].value = value; +bool Settings::setGroup(const std::string &name, Settings *group) +{ + return setEntry(name, &group, true, false); } -void Settings::setGroupDefault(const std::string &name, Settings *group) +bool Settings::setGroupDefault(const std::string &name, Settings *group) { - JMutexAutoLock lock(m_mutex); + return setEntry(name, &group, true, true); +} + - delete m_defaults[name].group; - m_defaults[name].group = group; +bool Settings::setBool(const std::string &name, bool value) +{ + return set(name, value ? "true" : "false"); } -void Settings::setBool(const std::string &name, bool value) +bool Settings::setS16(const std::string &name, s16 value) { - set(name, value ? "true" : "false"); + return set(name, itos(value)); } -void Settings::setS16(const std::string &name, s16 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)); + return set(name, writeFlagString(flags, flagdesc, flagmask)); } @@ -728,14 +854,33 @@ 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); +} + + +bool Settings::setNoiseParams(const std::string &name, + const NoiseParams &np, bool set_default) +{ + Settings *group = new Settings; + + group->setFloat("offset", np.offset); + group->setFloat("scale", np.scale); + group->setV3F("spread", np.spread); + group->setS32("seed", np.seed); + group->setU16("octaves", np.octaves); + group->setFloat("persistence", np.persist); + group->setFloat("lacunarity", np.lacunarity); + group->setFlagStr("flags", np.flags, flagdesc_noiseparams, np.flags); + + return setEntry(name, &group, true, set_default); } bool Settings::remove(const std::string &name) { JMutexAutoLock lock(m_mutex); + + delete m_settings[name].group; return m_settings.erase(name); } @@ -746,6 +891,11 @@ void Settings::clear() clearNoLock(); } +void Settings::clearDefaults() +{ + JMutexAutoLock lock(m_mutex); + clearDefaultsNoLock(); +} void Settings::updateValue(const Settings &other, const std::string &name) { @@ -812,32 +962,56 @@ void Settings::updateNoLock(const Settings &other) void Settings::clearNoLock() { + std::map::const_iterator it; + for (it = m_settings.begin(); it != m_settings.end(); ++it) + delete it->second.group; m_settings.clear(); + + clearDefaultsNoLock(); +} + +void Settings::clearDefaultsNoLock() +{ + std::map::const_iterator it; + for (it = m_defaults.begin(); it != m_defaults.end(); ++it) + delete it->second.group; m_defaults.clear(); } void Settings::registerChangedCallback(std::string name, - setting_changed_callback cbf) + setting_changed_callback cbf, void *userdata) { - m_callbacks[name].push_back(cbf); + JMutexAutoLock lock(m_callbackMutex); + m_callbacks[name].push_back(std::make_pair(cbf, userdata)); } +void Settings::deregisterChangedCallback(std::string name, setting_changed_callback cbf, void *userdata) +{ + JMutexAutoLock lock(m_callbackMutex); + std::map > >::iterator iterToVector = m_callbacks.find(name); + if (iterToVector != m_callbacks.end()) + { + std::vector > &vector = iterToVector->second; + + std::vector >::iterator position = + std::find(vector.begin(), vector.end(), std::make_pair(cbf, userdata)); + + if (position != vector.end()) + vector.erase(position); + } +} void Settings::doCallbacks(const std::string name) { - std::vector tempvector; + JMutexAutoLock lock(m_callbackMutex); + std::map > >::iterator iterToVector = m_callbacks.find(name); + if (iterToVector != m_callbacks.end()) { - JMutexAutoLock lock(m_mutex); - if (m_callbacks.find(name) != m_callbacks.end()) + std::vector >::iterator iter; + for (iter = iterToVector->second.begin(); iter != iterToVector->second.end(); iter++) { - tempvector = m_callbacks[name]; + (iter->first)(name, iter->second); } } - - for (std::vector::iterator iter = tempvector.begin(); - iter != tempvector.end(); iter ++) - { - (*iter)(name); - } }