From 175b7a28e5f82bd6da9f4c3e22ce6493c05f4f09 Mon Sep 17 00:00:00 2001 From: kwolekr Date: Sun, 30 Nov 2014 15:49:04 -0500 Subject: [PATCH] settings: Add setting groups and multiline entries --- src/settings.cpp | 428 +++++++++++++++++++++++++++++------------------ src/settings.h | 100 +++++++---- src/test.cpp | 212 ++++++++++++++++------- 3 files changed, 486 insertions(+), 254 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index 001d93f5e..9485c7d74 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -32,6 +32,14 @@ with this program; if not, write to the Free Software Foundation, Inc., #include +Settings::~Settings() +{ + std::map::const_iterator it; + for (it = m_settings.begin(); it != m_settings.end(); ++it) + delete it->second.group; +} + + Settings & Settings::operator += (const Settings &other) { update(other); @@ -55,23 +63,62 @@ Settings & Settings::operator = (const Settings &other) } -bool Settings::parseConfigLines(std::istream &is, - const std::string &end) +std::string Settings::getMultiline(std::istream &is) +{ + std::string value; + std::string line; + + while (is.good()) { + std::getline(is, line); + if (line == "\"\"\"") + break; + value += line; + value.push_back('\n'); + } + + size_t len = value.size(); + if (len) + value.erase(len - 1); + + return value; +} + + +bool Settings::parseConfigLines(std::istream &is, const std::string &end) { JMutexAutoLock lock(m_mutex); - std::string name, value; - bool end_found = false; + std::string line, name, value; - while (is.good() && !end_found) { - if (parseConfigObject(is, name, value, end, end_found)) { - m_settings[name] = value; + while (is.good()) { + std::getline(is, line); + SettingsParseEvent event = parseConfigObject(line, end, name, value); + + switch (event) { + case SPE_NONE: + case SPE_INVALID: + case SPE_COMMENT: + break; + case SPE_KVPAIR: + m_settings[name] = SettingsEntry(value); + break; + case SPE_END: + return true; + case SPE_GROUP: { + Settings *branch = new Settings; + if (!branch->parseConfigLines(is, "}")) + return false; + + m_settings[name] = SettingsEntry(branch); + break; + } + case SPE_MULTILINE: + m_settings[name] = SettingsEntry(getMultiline(is)); + break; } } - if (!end.empty() && !end_found) { - return false; - } - return true; + + return end.empty(); } @@ -81,92 +128,146 @@ bool Settings::readConfigFile(const char *filename) if (!is.good()) return false; - JMutexAutoLock lock(m_mutex); - - std::string name, value; - - while (is.good()) { - if (parseConfigObject(is, name, value)) { - m_settings[name] = value; - } - } - - return true; + return parseConfigLines(is, ""); } -void Settings::writeLines(std::ostream &os) const +void Settings::writeLines(std::ostream &os, u32 tab_depth) const { JMutexAutoLock lock(m_mutex); - for (std::map::const_iterator - i = m_settings.begin(); - i != m_settings.end(); ++i) { - os << i->first << " = " << i->second << '\n'; + 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); } } +void Settings::printValue(std::ostream &os, const std::string &name, + const SettingsEntry &entry, bool is_value_multiline, 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"; + + os << name << " = {\n"; + group->writeLines(os, tab_depth + 1); + + for (u32 i = 0; i != tab_depth; i++) + os << "\t"; + + os << "}\n"; + } +} + + +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; + 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 + while (is.good() && !end_found) { + std::getline(is, line); + SettingsParseEvent event = parseConfigObject(line, end, name, value); + + switch (event) { + case SPE_END: + end_found = true; + break; + case SPE_KVPAIR: + case SPE_MULTILINE: + it = m_settings.find(name); + if (it != m_settings.end()) { + if (event == SPE_MULTILINE) + value = getMultiline(is); + + if (value != it->second.value) { + value = it->second.value; + was_modified = true; + } + } + + settings_in_config.insert(name); + + printValue(os, name, SettingsEntry(value), + event == SPE_MULTILINE, tab_depth); + + break; + case SPE_GROUP: { + Settings *group = NULL; + 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); + } else { + Settings dummy_settings; + dummy_settings.updateConfigObject(is, os, "}", tab_depth + 1); + } + + for (u32 i = 0; i != tab_depth; i++) + os << "\t"; + os << "}\n"; + break; + } + default: + os << line << (is.eof() ? "" : "\n"); + break; + } + } + + // 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()) + continue; + + 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; +} + + bool Settings::updateConfigFile(const char *filename) { - std::list objects; - std::set updated; - bool changed = false; - JMutexAutoLock lock(m_mutex); - // Read the file and check for differences - { - std::ifstream is(filename); - while (is.good()) { - getUpdatedConfigObject(is, objects, - updated, changed); - } - } + std::ifstream is(filename); + std::ostringstream os(std::ios_base::binary); - // If something not yet determined to have been changed, check if - // any new stuff was added - if (!changed) { - for (std::map::const_iterator - i = m_settings.begin(); - i != m_settings.end(); ++i) { - if (updated.find(i->first) == updated.end()) { - changed = true; - break; - } - } - } - - // If nothing was actually changed, skip writing the file - if (!changed) { + if (!updateConfigObject(is, os, "")) return true; - } - // Write stuff back - { - std::ostringstream ss(std::ios_base::binary); - - // Write changes settings - for (std::list::const_iterator - i = objects.begin(); - i != objects.end(); ++i) { - ss << (*i); - } - - // Write new settings - for (std::map::const_iterator - i = m_settings.begin(); - i != m_settings.end(); ++i) { - if (updated.find(i->first) != updated.end()) - continue; - ss << i->first << " = " << i->second << '\n'; - } - - if (!fs::safeWriteToFile(filename, ss.str())) { - errorstream << "Error writing configuration file: \"" - << filename << "\"" << std::endl; - return false; - } + if (!fs::safeWriteToFile(filename, os.str())) { + errorstream << "Error writing configuration file: \"" + << filename << "\"" << std::endl; + return false; } return true; @@ -231,20 +332,31 @@ bool Settings::parseCommandLine(int argc, char *argv[], ***********/ -std::string Settings::get(const std::string &name) const +const SettingsEntry &Settings::getEntry(const std::string &name) const { JMutexAutoLock lock(m_mutex); - std::map::const_iterator n; + std::map::const_iterator n; if ((n = m_settings.find(name)) == m_settings.end()) { - if ((n = m_defaults.find(name)) == m_defaults.end()) { + 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 +{ + return getEntry(name).group; +} + + +std::string Settings::get(const std::string &name) const +{ + return getEntry(name).value; +} + + bool Settings::getBool(const std::string &name) const { return is_yes(get(name)); @@ -309,7 +421,7 @@ v3f Settings::getV3F(const std::string &name) const u32 Settings::getFlagStr(const std::string &name, const FlagDesc *flagdesc, - u32 *flagmask) const + u32 *flagmask) const { std::string val = get(name); return std::isdigit(val[0]) @@ -321,7 +433,7 @@ u32 Settings::getFlagStr(const std::string &name, const FlagDesc *flagdesc, // N.B. if getStruct() is used to read a non-POD aggregate type, // the behavior is undefined. bool Settings::getStruct(const std::string &name, const std::string &format, - void *out, size_t olen) const + void *out, size_t olen) const { std::string valstr; @@ -350,7 +462,7 @@ bool Settings::exists(const std::string &name) const std::vector Settings::getNames() const { std::vector names; - for (std::map::const_iterator + for (std::map::const_iterator i = m_settings.begin(); i != m_settings.end(); ++i) { names.push_back(i->first); @@ -364,6 +476,27 @@ std::vector Settings::getNames() const * Getters that don't throw exceptions * ***************************************/ +bool Settings::getEntryNoEx(const std::string &name, SettingsEntry &val) const +{ + try { + val = getEntry(name); + return true; + } catch (SettingNotFoundException &e) { + return false; + } +} + + +bool Settings::getGroupNoEx(const std::string &name, Settings *&val) const +{ + try { + val = getGroup(name); + return true; + } catch (SettingNotFoundException &e) { + return false; + } +} + bool Settings::getNoEx(const std::string &name, std::string &val) const { @@ -466,7 +599,8 @@ 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 +bool Settings::getFlagStrNoEx(const std::string &name, u32 &val, + FlagDesc *flagdesc) const { try { u32 flags, flagmask; @@ -483,33 +617,42 @@ bool Settings::getFlagStrNoEx(const std::string &name, u32 &val, FlagDesc *flagd } - /*********** * Setters * ***********/ -void Settings::set(const std::string &name, std::string value) +void Settings::set(const std::string &name, const std::string &value) { JMutexAutoLock lock(m_mutex); - m_settings[name] = value; + m_settings[name].value = value; } -void Settings::set(const std::string &name, const char *value) +void Settings::setGroup(const std::string &name, Settings *group) { JMutexAutoLock lock(m_mutex); - m_settings[name] = value; + delete m_settings[name].group; + m_settings[name].group = group; } -void Settings::setDefault(const std::string &name, std::string value) +void Settings::setDefault(const std::string &name, const std::string &value) { JMutexAutoLock lock(m_mutex); - m_defaults[name] = value; + m_defaults[name].value = value; +} + + +void Settings::setGroupDefault(const std::string &name, Settings *group) +{ + JMutexAutoLock lock(m_mutex); + + delete m_defaults[name].group; + m_defaults[name].group = group; } @@ -568,7 +711,8 @@ void Settings::setFlagStr(const std::string &name, u32 flags, } -bool Settings::setStruct(const std::string &name, const std::string &format, void *value) +bool Settings::setStruct(const std::string &name, const std::string &format, + void *value) { std::string structstr; if (!serializeStructToString(&structstr, format, value)) @@ -602,6 +746,7 @@ void Settings::updateValue(const Settings &other, const std::string &name) try { std::string val = other.get(name); + m_settings[name] = val; } catch (SettingNotFoundException &e) { } @@ -620,78 +765,31 @@ void Settings::update(const Settings &other) } -void Settings::registerChangedCallback(std::string name, - setting_changed_callback cbf) +SettingsParseEvent Settings::parseConfigObject(const std::string &line, + const std::string &end, std::string &name, std::string &value) { - m_callbacks[name].push_back(cbf); -} - - -inline bool Settings::parseConfigObject(std::istream &is, - std::string &name, std::string &value) -{ - bool end_found = false; - return parseConfigObject(is, name, value, "", end_found); -} - - -// NOTE: This function might be expanded to allow multi-line settings. -bool Settings::parseConfigObject(std::istream &is, - std::string &name, std::string &value, - const std::string &end, bool &end_found) -{ - std::string line; - std::getline(is, line); std::string trimmed_line = trim(line); - // Ignore empty lines and comments - if (trimmed_line.empty() || trimmed_line[0] == '#') { - value = trimmed_line; - return false; - } - if (trimmed_line == end) { - end_found = true; - return false; - } + if (trimmed_line.empty()) + return SPE_NONE; + if (trimmed_line[0] == '#') + return SPE_COMMENT; + if (trimmed_line == end) + return SPE_END; - Strfnd sf(trimmed_line); + size_t pos = trimmed_line.find('='); + if (pos == std::string::npos) + return SPE_INVALID; - name = trim(sf.next("=")); - if (name.empty()) { - value = trimmed_line; - return false; - } + name = trim(trimmed_line.substr(0, pos)); + value = trim(trimmed_line.substr(pos + 1)); - value = trim(sf.next("\n")); + if (value == "{") + return SPE_GROUP; + if (value == "\"\"\"") + return SPE_MULTILINE; - return true; -} - - -void Settings::getUpdatedConfigObject(std::istream &is, - std::list &dst, - std::set &updated, - bool &changed) -{ - std::string name, value; - - if (!parseConfigObject(is, name, value)) { - dst.push_back(value + (is.eof() ? "" : "\n")); - return; - } - - if (m_settings.find(name) != m_settings.end()) { - std::string new_value = m_settings[name]; - - if (new_value != value) { - changed = true; - } - - dst.push_back(name + " = " + new_value + (is.eof() ? "" : "\n")); - updated.insert(name); - } else { // File contains a setting which is not in m_settings - changed = true; - } + return SPE_KVPAIR; } @@ -708,6 +806,14 @@ void Settings::clearNoLock() m_defaults.clear(); } + +void Settings::registerChangedCallback(std::string name, + setting_changed_callback cbf) +{ + m_callbacks[name].push_back(cbf); +} + + void Settings::doCallbacks(const std::string name) { std::vector tempvector; diff --git a/src/settings.h b/src/settings.h index 0faccba4d..d0bd203d3 100644 --- a/src/settings.h +++ b/src/settings.h @@ -28,14 +28,27 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include -enum ValueType -{ +class Settings; + +/** function type to register a changed callback */ +typedef void (*setting_changed_callback)(const std::string); + +enum ValueType { VALUETYPE_STRING, VALUETYPE_FLAG // Doesn't take any arguments }; -struct ValueSpec -{ +enum SettingsParseEvent { + SPE_NONE, + SPE_INVALID, + SPE_COMMENT, + SPE_KVPAIR, + SPE_END, + SPE_GROUP, + SPE_MULTILINE, +}; + +struct ValueSpec { ValueSpec(ValueType a_type, const char *a_help=NULL) { type = a_type; @@ -46,13 +59,39 @@ struct ValueSpec }; /** function type to register a changed callback */ -typedef void (*setting_changed_callback)(const std::string); + +struct SettingsEntry { + SettingsEntry() + { + group = NULL; + } + + SettingsEntry(const std::string &value_) + { + value = value_; + group = NULL; + } + + SettingsEntry(Settings *group_) + { + group = group_; + } + + SettingsEntry(const std::string &value_, Settings *group_) + { + value = value_; + group = group_; + } + + std::string value; + Settings *group; +}; -class Settings -{ +class Settings { public: Settings() {} + ~Settings(); Settings & operator += (const Settings &other); Settings & operator = (const Settings &other); @@ -70,13 +109,23 @@ public: bool parseCommandLine(int argc, char *argv[], std::map &allowed_options); bool parseConfigLines(std::istream &is, const std::string &end = ""); - void writeLines(std::ostream &os) const; + void writeLines(std::ostream &os, u32 tab_depth=0) const; + SettingsParseEvent parseConfigObject(const std::string &line, + const std::string &end, std::string &name, std::string &value); + bool updateConfigObject(std::istream &is, std::ostream &os, + const std::string &end, u32 tab_depth=0); + + static std::string getMultiline(std::istream &is); + static void printValue(std::ostream &os, const std::string &name, + const SettingsEntry &entry, bool is_value_multiline, u32 tab_depth=0); /*********** * Getters * ***********/ + const SettingsEntry &getEntry(const std::string &name) const; + Settings *getGroup(const std::string &name) const; std::string get(const std::string &name) const; bool getBool(const std::string &name) const; u16 getU16(const std::string &name) const; @@ -102,6 +151,8 @@ public: * Getters that don't throw exceptions * ***************************************/ + bool getEntryNoEx(const std::string &name, SettingsEntry &val) const; + bool getGroupNoEx(const std::string &name, Settings *&val) const; bool getNoEx(const std::string &name, std::string &val) const; bool getFlag(const std::string &name) const; bool getU16NoEx(const std::string &name, u16 &val) const; @@ -121,9 +172,12 @@ public: * Setters * ***********/ - void set(const std::string &name, std::string value); - void set(const std::string &name, const char *value); - void setDefault(const std::string &name, std::string value); + // N.B. Groups not allocated with new must be set to NULL in the settings + // tree before object destruction. + void set(const std::string &name, const std::string &value); + void setGroup(const std::string &name, Settings *group); + void setDefault(const std::string &name, const std::string &value); + void setGroupDefault(const std::string &name, Settings *group); void setBool(const std::string &name, bool value); void setS16(const std::string &name, s16 value); void setS32(const std::string &name, s32 value); @@ -145,34 +199,14 @@ public: void registerChangedCallback(std::string name, setting_changed_callback cbf); private: - /*********************** - * Reading and writing * - ***********************/ - - bool parseConfigObject(std::istream &is, - std::string &name, std::string &value); - bool parseConfigObject(std::istream &is, - std::string &name, std::string &value, - const std::string &end, bool &end_found); - /* - * Reads a configuration object from stream (usually a single line) - * and adds it to dst. - * Preserves comments and empty lines. - * Setting names that were added to dst are also added to updated. - */ - void getUpdatedConfigObject(std::istream &is, - std::list &dst, - std::set &updated, - bool &changed); - void updateNoLock(const Settings &other); void clearNoLock(); void doCallbacks(std::string name); - std::map m_settings; - std::map m_defaults; + std::map m_settings; + std::map m_defaults; std::map > m_callbacks; // All methods that access m_settings/m_defaults directly should lock this. mutable JMutex m_mutex; diff --git a/src/test.cpp b/src/test.cpp index 6cd7983fc..6454f8a28 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -418,29 +418,88 @@ struct TestPath: public TestBase } }; +#define TEST_CONFIG_TEXT_BEFORE \ + "leet = 1337\n" \ + "leetleet = 13371337\n" \ + "leetleet_neg = -13371337\n" \ + "floaty_thing = 1.1\n" \ + "stringy_thing = asd /( ¤%&(/\" BLÖÄRP\n" \ + "coord = (1, 2, 4.5)\n" \ + " # this is just a comment\n" \ + "this is an invalid line\n" \ + "asdf = {\n" \ + " a = 5\n" \ + " b = 2.5\n" \ + " c = \"\"\"\n" \ + "testy\n" \ + " testa \n" \ + "\"\"\"\n" \ + "\n" \ + "}\n" \ + "blarg = \"\"\" \n" \ + "some multiline text\n" \ + " with leading whitespace!\n" \ + "\"\"\"\n" \ + "zoop = true" + +#define TEST_CONFIG_TEXT_AFTER \ + "leet = 1337\n" \ + "leetleet = 13371337\n" \ + "leetleet_neg = -13371337\n" \ + "floaty_thing = 1.1\n" \ + "stringy_thing = asd /( ¤%&(/\" BLÖÄRP\n" \ + "coord = (1, 2, 4.5)\n" \ + " # this is just a comment\n" \ + "this is an invalid line\n" \ + "asdf = {\n" \ + " a = 5\n" \ + " b = 2.5\n" \ + " c = \"\"\"\n" \ + "testy\n" \ + " testa \n" \ + "\"\"\"\n" \ + "\n" \ + "}\n" \ + "blarg = \"\"\"\n" \ + "some multiline text\n" \ + " with leading whitespace!\n" \ + "\"\"\"\n" \ + "zoop = true\n" \ + "coord2 = (1,2,3.3)\n" \ + "floaty_thing_2 = 1.2\n" \ + "groupy_thing = \n" \ + "groupy_thing = {\n" \ + " animals = \n" \ + " animals = {\n" \ + " cat = meow\n" \ + " dog = woof\n" \ + " }\n" \ + " num_apples = 4\n" \ + " num_oranges = 53\n" \ + "}\n" + + struct TestSettings: public TestBase { void Run() { Settings s; + // Test reading of settings - std::istringstream is( - "leet = 1337\n" - "leetleet = 13371337\n" - "leetleet_neg = -13371337\n" - "floaty_thing = 1.1\n" - "stringy_thing = asd /( ¤%&(/\" BLÖÄRP\n" - "coord = (1, 2, 4.5)"); + std::istringstream is(TEST_CONFIG_TEXT_BEFORE); s.parseConfigLines(is); + UASSERT(s.getS32("leet") == 1337); UASSERT(s.getS16("leetleet") == 32767); UASSERT(s.getS16("leetleet_neg") == -32768); + // Not sure if 1.1 is an exact value as a float, but doesn't matter UASSERT(fabs(s.getFloat("floaty_thing") - 1.1) < 0.001); UASSERT(s.get("stringy_thing") == "asd /( ¤%&(/\" BLÖÄRP"); UASSERT(fabs(s.getV3F("coord").X - 1.0) < 0.001); UASSERT(fabs(s.getV3F("coord").Y - 2.0) < 0.001); UASSERT(fabs(s.getV3F("coord").Z - 4.5) < 0.001); + // Test the setting of settings too s.setFloat("floaty_thing_2", 1.2); s.setV3F("coord2", v3f(1, 2, 3.3)); @@ -449,6 +508,39 @@ struct TestSettings: public TestBase UASSERT(fabs(s.getV3F("coord2").X - 1.0) < 0.001); UASSERT(fabs(s.getV3F("coord2").Y - 2.0) < 0.001); UASSERT(fabs(s.getV3F("coord2").Z - 3.3) < 0.001); + + // Test settings groups + Settings *group = s.getGroup("asdf"); + UASSERT(group != NULL); + UASSERT(s.getGroup("zoop") == NULL); + UASSERT(group->getS16("a") == 5); + UASSERT(fabs(group->getFloat("b") - 2.5) < 0.001); + + Settings *group3 = new Settings; + group3->set("cat", "meow"); + group3->set("dog", "woof"); + + Settings *group2 = new Settings; + group2->setS16("num_apples", 4); + group2->setS16("num_oranges", 53); + group2->setGroup("animals", group3); + s.setGroup("groupy_thing", group2); + + // Test multiline settings + UASSERT(group->get("c") == "testy\n testa "); + UASSERT(s.get("blarg") == + "some multiline text\n" + " with leading whitespace!"); + + // Test writing + std::ostringstream os(std::ios_base::binary); + is.clear(); + is.seekg(0); + + UASSERT(s.updateConfigObject(is, os, "", 0) == true); + //printf(">>>> expected config:\n%s\n", TEST_CONFIG_TEXT_AFTER); + //printf(">>>> actual config:\n%s\n", os.str().c_str()); + UASSERT(os.str() == TEST_CONFIG_TEXT_AFTER); } }; @@ -470,7 +562,7 @@ struct TestSerialization: public TestBase UASSERT(serializeWideString(L"") == mkstr("\0\0")); UASSERT(serializeLongString("") == mkstr("\0\0\0\0")); UASSERT(serializeJsonString("") == "\"\""); - + std::string teststring = "Hello world!"; UASSERT(serializeString(teststring) == mkstr("\0\14Hello world!")); @@ -596,12 +688,12 @@ struct TestCompress: public TestBase fromdata[1]=5; fromdata[2]=5; fromdata[3]=1; - + std::ostringstream os(std::ios_base::binary); compress(fromdata, os, 0); std::string str_out = os.str(); - + infostream<<"str_out.size()="< "; for(u32 i=0; i "; for(u32 i=0; iget(n).light_propagates == true); @@ -753,28 +845,28 @@ struct TestVoxelManipulator: public TestBase VoxelArea a(v3s16(-1,-1,-1), v3s16(1,1,1)); UASSERT(a.index(0,0,0) == 1*3*3 + 1*3 + 1); UASSERT(a.index(-1,-1,-1) == 0); - + VoxelArea c(v3s16(-2,-2,-2), v3s16(2,2,2)); // An area that is 1 bigger in x+ and z- VoxelArea d(v3s16(-2,-2,-3), v3s16(3,2,2)); - + std::list aa; d.diff(c, aa); - + // Correct results std::vector results; results.push_back(VoxelArea(v3s16(-2,-2,-3),v3s16(3,2,-3))); results.push_back(VoxelArea(v3s16(3,-2,-2),v3s16(3,2,2))); UASSERT(aa.size() == results.size()); - + infostream<<"Result of diff:"<::const_iterator i = aa.begin(); i != aa.end(); ++i) { i->print(infostream); infostream<::iterator j = std::find(results.begin(), results.end(), *i); UASSERT(j != results.end()); results.erase(j); @@ -784,13 +876,13 @@ struct TestVoxelManipulator: public TestBase /* VoxelManipulator */ - + VoxelManipulator v; v.print(infostream, nodedef); infostream<<"*** Setting (-1,0,-1)=2 ***"<channels[chn]; u16 sn = ch->next_outgoing_seqnum; @@ -1881,7 +1973,7 @@ struct TestConnection: public TestBase UASSERT(size == data1.getSize()); UASSERT(memcmp(*data1, *recvdata, data1.getSize()) == 0); UASSERT(peer_id == PEER_ID_SERVER); - + infostream<<"** running client.Receive()"< data1(datasize); for(u16 i=0; i recvdata; infostream<<"** running client.Receive()"<