LCOV - code coverage report
Current view: top level - src - settings.cpp (source / functions) Hit Total Coverage
Test: report Lines: 167 508 32.9 %
Date: 2015-07-11 18:23:49 Functions: 30 75 40.0 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include "settings.h"
      21             : #include "irrlichttypes_bloated.h"
      22             : #include "exceptions.h"
      23             : #include "jthread/jmutexautolock.h"
      24             : #include "strfnd.h"
      25             : #include <iostream>
      26             : #include <fstream>
      27             : #include <sstream>
      28             : #include "debug.h"
      29             : #include "log.h"
      30             : #include "util/serialize.h"
      31             : #include "filesys.h"
      32             : #include "noise.h"
      33             : #include <cctype>
      34             : #include <algorithm>
      35             : 
      36           1 : static Settings main_settings;
      37             : Settings *g_settings = &main_settings;
      38           1 : std::string g_settings_path;
      39             : 
      40          26 : Settings::~Settings()
      41             : {
      42          13 :         clear();
      43          13 : }
      44             : 
      45             : 
      46           0 : Settings & Settings::operator += (const Settings &other)
      47             : {
      48           0 :         update(other);
      49             : 
      50           0 :         return *this;
      51             : }
      52             : 
      53             : 
      54           0 : Settings & Settings::operator = (const Settings &other)
      55             : {
      56           0 :         if (&other == this)
      57           0 :                 return *this;
      58             : 
      59           0 :         JMutexAutoLock lock(m_mutex);
      60           0 :         JMutexAutoLock lock2(other.m_mutex);
      61             : 
      62           0 :         clearNoLock();
      63           0 :         updateNoLock(other);
      64             : 
      65           0 :         return *this;
      66             : }
      67             : 
      68             : 
      69         247 : bool Settings::checkNameValid(const std::string &name)
      70             : {
      71         247 :         bool valid = name.find_first_of("=\"{}#") == std::string::npos;
      72         247 :         if (valid) valid = trim(name) == name;
      73         247 :         if (!valid) {
      74           0 :                 errorstream << "Invalid setting name \"" << name << "\""
      75           0 :                         << std::endl;
      76           0 :                 return false;
      77             :         }
      78         247 :         return true;
      79             : }
      80             : 
      81             : 
      82         247 : bool Settings::checkValueValid(const std::string &value)
      83             : {
      84         494 :         if (value.substr(0, 3) == "\"\"\"" ||
      85         247 :                 value.find("\n\"\"\"") != std::string::npos) {
      86             :                 errorstream << "Invalid character sequence '\"\"\"' found in"
      87           0 :                         " setting value!" << std::endl;
      88           0 :                 return false;
      89             :         }
      90         247 :         return true;
      91             : }
      92             : 
      93             : 
      94           0 : std::string Settings::sanitizeName(const std::string &name)
      95             : {
      96           0 :         std::string n = trim(name);
      97             : 
      98           0 :         for (const char *s = "=\"{}#"; *s; s++)
      99           0 :                 n.erase(std::remove(n.begin(), n.end(), *s), n.end());
     100             : 
     101           0 :         return n;
     102             : }
     103             : 
     104             : 
     105           0 : std::string Settings::sanitizeValue(const std::string &value)
     106             : {
     107           0 :         std::string v(value);
     108           0 :         size_t p = 0;
     109             : 
     110           0 :         if (v.substr(0, 3) == "\"\"\"")
     111           0 :                 v.erase(0, 3);
     112             : 
     113           0 :         while ((p = v.find("\n\"\"\"")) != std::string::npos)
     114           0 :                 v.erase(p, 4);
     115             : 
     116           0 :         return v;
     117             : }
     118             : 
     119             : 
     120           0 : std::string Settings::getMultiline(std::istream &is, size_t *num_lines)
     121             : {
     122           0 :         size_t lines = 1;
     123           0 :         std::string value;
     124           0 :         std::string line;
     125             : 
     126           0 :         while (is.good()) {
     127           0 :                 lines++;
     128           0 :                 std::getline(is, line);
     129           0 :                 if (line == "\"\"\"")
     130           0 :                         break;
     131           0 :                 value += line;
     132           0 :                 value.push_back('\n');
     133             :         }
     134             : 
     135           0 :         size_t len = value.size();
     136           0 :         if (len)
     137           0 :                 value.erase(len - 1);
     138             : 
     139           0 :         if (num_lines)
     140           0 :                 *num_lines = lines;
     141             : 
     142           0 :         return value;
     143             : }
     144             : 
     145             : 
     146          12 : bool Settings::readConfigFile(const char *filename)
     147             : {
     148          24 :         std::ifstream is(filename);
     149          12 :         if (!is.good())
     150           0 :                 return false;
     151             : 
     152          12 :         return parseConfigLines(is, "");
     153             : }
     154             : 
     155             : 
     156          12 : bool Settings::parseConfigLines(std::istream &is, const std::string &end)
     157             : {
     158          24 :         JMutexAutoLock lock(m_mutex);
     159             : 
     160          24 :         std::string line, name, value;
     161             : 
     162         598 :         while (is.good()) {
     163         293 :                 std::getline(is, line);
     164         293 :                 SettingsParseEvent event = parseConfigObject(line, end, name, value);
     165             : 
     166         293 :                 switch (event) {
     167             :                 case SPE_NONE:
     168             :                 case SPE_INVALID:
     169             :                 case SPE_COMMENT:
     170          14 :                         break;
     171             :                 case SPE_KVPAIR:
     172         279 :                         m_settings[name] = SettingsEntry(value);
     173         279 :                         break;
     174             :                 case SPE_END:
     175           0 :                         return true;
     176             :                 case SPE_GROUP: {
     177           0 :                         Settings *group = new Settings;
     178           0 :                         if (!group->parseConfigLines(is, "}")) {
     179           0 :                                 delete group;
     180           0 :                                 return false;
     181             :                         }
     182           0 :                         m_settings[name] = SettingsEntry(group);
     183           0 :                         break;
     184             :                 }
     185             :                 case SPE_MULTILINE:
     186           0 :                         m_settings[name] = SettingsEntry(getMultiline(is));
     187           0 :                         break;
     188             :                 }
     189             :         }
     190             : 
     191          12 :         return end.empty();
     192             : }
     193             : 
     194             : 
     195           0 : void Settings::writeLines(std::ostream &os, u32 tab_depth) const
     196             : {
     197           0 :         JMutexAutoLock lock(m_mutex);
     198             : 
     199           0 :         for (std::map<std::string, SettingsEntry>::const_iterator
     200           0 :                         it = m_settings.begin();
     201           0 :                         it != m_settings.end(); ++it)
     202           0 :                 printEntry(os, it->first, it->second, tab_depth);
     203           0 : }
     204             : 
     205             : 
     206           0 : void Settings::printEntry(std::ostream &os, const std::string &name,
     207             :         const SettingsEntry &entry, u32 tab_depth)
     208             : {
     209           0 :         for (u32 i = 0; i != tab_depth; i++)
     210           0 :                 os << "\t";
     211             : 
     212           0 :         if (entry.is_group) {
     213           0 :                 os << name << " = {\n";
     214             : 
     215           0 :                 entry.group->writeLines(os, tab_depth + 1);
     216             : 
     217           0 :                 for (u32 i = 0; i != tab_depth; i++)
     218           0 :                         os << "\t";
     219           0 :                 os << "}\n";
     220             :         } else {
     221           0 :                 os << name << " = ";
     222             : 
     223           0 :                 if (entry.value.find('\n') != std::string::npos)
     224           0 :                         os << "\"\"\"\n" << entry.value << "\n\"\"\"\n";
     225             :                 else
     226           0 :                         os << entry.value << "\n";
     227             :         }
     228           0 : }
     229             : 
     230             : 
     231           1 : bool Settings::updateConfigObject(std::istream &is, std::ostream &os,
     232             :         const std::string &end, u32 tab_depth)
     233             : {
     234           1 :         std::map<std::string, SettingsEntry>::const_iterator it;
     235           2 :         std::set<std::string> present_entries;
     236           2 :         std::string line, name, value;
     237           1 :         bool was_modified = false;
     238           1 :         bool end_found = false;
     239             : 
     240             :         // Add any settings that exist in the config file with the current value
     241             :         // in the object if existing
     242         107 :         while (is.good() && !end_found) {
     243          53 :                 std::getline(is, line);
     244          53 :                 SettingsParseEvent event = parseConfigObject(line, end, name, value);
     245             : 
     246          53 :                 switch (event) {
     247             :                 case SPE_END:
     248           0 :                         os << line << (is.eof() ? "" : "\n");
     249           0 :                         end_found = true;
     250           0 :                         break;
     251             :                 case SPE_MULTILINE:
     252           0 :                         value = getMultiline(is);
     253             :                         /* FALLTHROUGH */
     254             :                 case SPE_KVPAIR:
     255          52 :                         it = m_settings.find(name);
     256         104 :                         if (it != m_settings.end() &&
     257         104 :                                 (it->second.is_group || it->second.value != value)) {
     258           0 :                                 printEntry(os, name, it->second, tab_depth);
     259           0 :                                 was_modified = true;
     260             :                         } else {
     261          52 :                                 os << line << "\n";
     262          52 :                                 if (event == SPE_MULTILINE)
     263           0 :                                         os << value << "\n\"\"\"\n";
     264             :                         }
     265          52 :                         present_entries.insert(name);
     266          52 :                         break;
     267             :                 case SPE_GROUP:
     268           0 :                         it = m_settings.find(name);
     269           0 :                         if (it != m_settings.end() && it->second.is_group) {
     270           0 :                                 os << line << "\n";
     271           0 :                                 sanity_check(it->second.group != NULL);
     272           0 :                                 was_modified |= it->second.group->updateConfigObject(is, os,
     273           0 :                                         "}", tab_depth + 1);
     274             :                         } else {
     275           0 :                                 printEntry(os, name, it->second, tab_depth);
     276           0 :                                 was_modified = true;
     277             :                         }
     278           0 :                         present_entries.insert(name);
     279           0 :                         break;
     280             :                 default:
     281           1 :                         os << line << (is.eof() ? "" : "\n");
     282           1 :                         break;
     283             :                 }
     284             :         }
     285             : 
     286             :         // Add any settings in the object that don't exist in the config file yet
     287          53 :         for (it = m_settings.begin(); it != m_settings.end(); ++it) {
     288          52 :                 if (present_entries.find(it->first) != present_entries.end())
     289          52 :                         continue;
     290             : 
     291           0 :                 printEntry(os, it->first, it->second, tab_depth);
     292           0 :                 was_modified = true;
     293             :         }
     294             : 
     295           2 :         return was_modified;
     296             : }
     297             : 
     298             : 
     299           1 : bool Settings::updateConfigFile(const char *filename)
     300             : {
     301           2 :         JMutexAutoLock lock(m_mutex);
     302             : 
     303           2 :         std::ifstream is(filename);
     304           2 :         std::ostringstream os(std::ios_base::binary);
     305             : 
     306           1 :         bool was_modified = updateConfigObject(is, os, "");
     307           1 :         is.close();
     308             : 
     309           1 :         if (!was_modified)
     310           1 :                 return true;
     311             : 
     312           0 :         if (!fs::safeWriteToFile(filename, os.str())) {
     313           0 :                 errorstream << "Error writing configuration file: \""
     314           0 :                         << filename << "\"" << std::endl;
     315           0 :                 return false;
     316             :         }
     317             : 
     318           0 :         return true;
     319             : }
     320             : 
     321             : 
     322           1 : bool Settings::parseCommandLine(int argc, char *argv[],
     323             :                 std::map<std::string, ValueSpec> &allowed_options)
     324             : {
     325           1 :         int nonopt_index = 0;
     326           1 :         for (int i = 1; i < argc; i++) {
     327           0 :                 std::string arg_name = argv[i];
     328           0 :                 if (arg_name.substr(0, 2) != "--") {
     329             :                         // If option doesn't start with -, read it in as nonoptX
     330           0 :                         if (arg_name[0] != '-'){
     331           0 :                                 std::string name = "nonopt";
     332           0 :                                 name += itos(nonopt_index);
     333           0 :                                 set(name, arg_name);
     334           0 :                                 nonopt_index++;
     335           0 :                                 continue;
     336             :                         }
     337           0 :                         errorstream << "Invalid command-line parameter \""
     338           0 :                                         << arg_name << "\": --<option> expected." << std::endl;
     339           0 :                         return false;
     340             :                 }
     341             : 
     342           0 :                 std::string name = arg_name.substr(2);
     343             : 
     344           0 :                 std::map<std::string, ValueSpec>::iterator n;
     345           0 :                 n = allowed_options.find(name);
     346           0 :                 if (n == allowed_options.end()) {
     347           0 :                         errorstream << "Unknown command-line parameter \""
     348           0 :                                         << arg_name << "\"" << std::endl;
     349           0 :                         return false;
     350             :                 }
     351             : 
     352           0 :                 ValueType type = n->second.type;
     353             : 
     354           0 :                 std::string value = "";
     355             : 
     356           0 :                 if (type == VALUETYPE_FLAG) {
     357           0 :                         value = "true";
     358             :                 } else {
     359           0 :                         if ((i + 1) >= argc) {
     360           0 :                                 errorstream << "Invalid command-line parameter \""
     361           0 :                                                 << name << "\": missing value" << std::endl;
     362           0 :                                 return false;
     363             :                         }
     364           0 :                         value = argv[++i];
     365             :                 }
     366             : 
     367           0 :                 set(name, value);
     368             :         }
     369             : 
     370           1 :         return true;
     371             : }
     372             : 
     373             : 
     374             : 
     375             : /***********
     376             :  * Getters *
     377             :  ***********/
     378             : 
     379             : 
     380      101446 : const SettingsEntry &Settings::getEntry(const std::string &name) const
     381             : {
     382      202892 :         JMutexAutoLock lock(m_mutex);
     383             : 
     384      101446 :         std::map<std::string, SettingsEntry>::const_iterator n;
     385      101446 :         if ((n = m_settings.find(name)) == m_settings.end()) {
     386       61660 :                 if ((n = m_defaults.find(name)) == m_defaults.end())
     387          33 :                         throw SettingNotFoundException("Setting [" + name + "] not found.");
     388             :         }
     389      202826 :         return n->second;
     390             : }
     391             : 
     392             : 
     393           0 : Settings *Settings::getGroup(const std::string &name) const
     394             : {
     395           0 :         const SettingsEntry &entry = getEntry(name);
     396           0 :         if (!entry.is_group)
     397           0 :                 throw SettingNotFoundException("Setting [" + name + "] is not a group.");
     398           0 :         return entry.group;
     399             : }
     400             : 
     401             : 
     402      101446 : std::string Settings::get(const std::string &name) const
     403             : {
     404      101446 :         const SettingsEntry &entry = getEntry(name);
     405      101413 :         if (entry.is_group)
     406           0 :                 throw SettingNotFoundException("Setting [" + name + "] is a group.");
     407      101413 :         return entry.value;
     408             : }
     409             : 
     410             : 
     411       77020 : bool Settings::getBool(const std::string &name) const
     412             : {
     413       77020 :         return is_yes(get(name));
     414             : }
     415             : 
     416             : 
     417       10171 : u16 Settings::getU16(const std::string &name) const
     418             : {
     419       10171 :         return stoi(get(name), 0, 65535);
     420             : }
     421             : 
     422             : 
     423           4 : s16 Settings::getS16(const std::string &name) const
     424             : {
     425           4 :         return stoi(get(name), -32768, 32767);
     426             : }
     427             : 
     428             : 
     429        1803 : s32 Settings::getS32(const std::string &name) const
     430             : {
     431        1803 :         return stoi(get(name));
     432             : }
     433             : 
     434             : 
     435        7731 : float Settings::getFloat(const std::string &name) const
     436             : {
     437        7731 :         return stof(get(name));
     438             : }
     439             : 
     440             : 
     441           0 : u64 Settings::getU64(const std::string &name) const
     442             : {
     443           0 :         u64 value = 0;
     444           0 :         std::string s = get(name);
     445           0 :         std::istringstream ss(s);
     446           0 :         ss >> value;
     447           0 :         return value;
     448             : }
     449             : 
     450             : 
     451           0 : v2f Settings::getV2F(const std::string &name) const
     452             : {
     453           0 :         v2f value;
     454           0 :         Strfnd f(get(name));
     455           0 :         f.next("(");
     456           0 :         value.X = stof(f.next(","));
     457           0 :         value.Y = stof(f.next(")"));
     458           0 :         return value;
     459             : }
     460             : 
     461             : 
     462           3 : v3f Settings::getV3F(const std::string &name) const
     463             : {
     464           3 :         v3f value;
     465           6 :         Strfnd f(get(name));
     466           3 :         f.next("(");
     467           3 :         value.X = stof(f.next(","));
     468           3 :         value.Y = stof(f.next(","));
     469           3 :         value.Z = stof(f.next(")"));
     470           6 :         return value;
     471             : }
     472             : 
     473             : 
     474           0 : u32 Settings::getFlagStr(const std::string &name, const FlagDesc *flagdesc,
     475             :         u32 *flagmask) const
     476             : {
     477           0 :         std::string val = get(name);
     478           0 :         return std::isdigit(val[0])
     479           0 :                 ? stoi(val)
     480           0 :                 : readFlagString(val, flagdesc, flagmask);
     481             : }
     482             : 
     483             : 
     484             : // N.B. if getStruct() is used to read a non-POD aggregate type,
     485             : // the behavior is undefined.
     486           0 : bool Settings::getStruct(const std::string &name, const std::string &format,
     487             :         void *out, size_t olen) const
     488             : {
     489           0 :         std::string valstr;
     490             : 
     491             :         try {
     492           0 :                 valstr = get(name);
     493           0 :         } catch (SettingNotFoundException &e) {
     494           0 :                 return false;
     495             :         }
     496             : 
     497           0 :         if (!deSerializeStringToStruct(valstr, format, out, olen))
     498           0 :                 return false;
     499             : 
     500           0 :         return true;
     501             : }
     502             : 
     503             : 
     504           0 : bool Settings::getNoiseParams(const std::string &name, NoiseParams &np) const
     505             : {
     506           0 :         return getNoiseParamsFromGroup(name, np) || getNoiseParamsFromValue(name, np);
     507             : }
     508             : 
     509             : 
     510           0 : bool Settings::getNoiseParamsFromValue(const std::string &name,
     511             :         NoiseParams &np) const
     512             : {
     513           0 :         std::string value;
     514             : 
     515           0 :         if (!getNoEx(name, value))
     516           0 :                 return false;
     517             : 
     518           0 :         Strfnd f(value);
     519             : 
     520           0 :         np.offset   = stof(f.next(","));
     521           0 :         np.scale    = stof(f.next(","));
     522           0 :         f.next("(");
     523           0 :         np.spread.X = stof(f.next(","));
     524           0 :         np.spread.Y = stof(f.next(","));
     525           0 :         np.spread.Z = stof(f.next(")"));
     526           0 :         f.next(",");
     527           0 :         np.seed     = stoi(f.next(","));
     528           0 :         np.octaves  = stoi(f.next(","));
     529           0 :         np.persist  = stof(f.next(","));
     530             : 
     531           0 :         std::string optional_params = f.next("");
     532           0 :         if (optional_params != "")
     533           0 :                 np.lacunarity = stof(optional_params);
     534             : 
     535           0 :         return true;
     536             : }
     537             : 
     538             : 
     539           0 : bool Settings::getNoiseParamsFromGroup(const std::string &name,
     540             :         NoiseParams &np) const
     541             : {
     542           0 :         Settings *group = NULL;
     543             : 
     544           0 :         if (!getGroupNoEx(name, group))
     545           0 :                 return false;
     546             : 
     547           0 :         group->getFloatNoEx("offset",      np.offset);
     548           0 :         group->getFloatNoEx("scale",       np.scale);
     549           0 :         group->getV3FNoEx("spread",        np.spread);
     550           0 :         group->getS32NoEx("seed",          np.seed);
     551           0 :         group->getU16NoEx("octaves",       np.octaves);
     552           0 :         group->getFloatNoEx("persistence", np.persist);
     553           0 :         group->getFloatNoEx("lacunarity",  np.lacunarity);
     554             : 
     555           0 :         np.flags = 0;
     556           0 :         if (!group->getFlagStrNoEx("flags", np.flags, flagdesc_noiseparams))
     557           0 :                 np.flags = NOISE_FLAG_DEFAULTS;
     558             : 
     559           0 :         return true;
     560             : }
     561             : 
     562             : 
     563          23 : bool Settings::exists(const std::string &name) const
     564             : {
     565          46 :         JMutexAutoLock lock(m_mutex);
     566             : 
     567         111 :         return (m_settings.find(name) != m_settings.end() ||
     568          88 :                 m_defaults.find(name) != m_defaults.end());
     569             : }
     570             : 
     571             : 
     572           0 : std::vector<std::string> Settings::getNames() const
     573             : {
     574           0 :         std::vector<std::string> names;
     575           0 :         for (std::map<std::string, SettingsEntry>::const_iterator
     576           0 :                         i = m_settings.begin();
     577           0 :                         i != m_settings.end(); ++i) {
     578           0 :                 names.push_back(i->first);
     579             :         }
     580           0 :         return names;
     581             : }
     582             : 
     583             : 
     584             : 
     585             : /***************************************
     586             :  * Getters that don't throw exceptions *
     587             :  ***************************************/
     588             : 
     589           0 : bool Settings::getEntryNoEx(const std::string &name, SettingsEntry &val) const
     590             : {
     591             :         try {
     592           0 :                 val = getEntry(name);
     593           0 :                 return true;
     594           0 :         } catch (SettingNotFoundException &e) {
     595           0 :                 return false;
     596             :         }
     597             : }
     598             : 
     599             : 
     600           0 : bool Settings::getGroupNoEx(const std::string &name, Settings *&val) const
     601             : {
     602             :         try {
     603           0 :                 val = getGroup(name);
     604           0 :                 return true;
     605           0 :         } catch (SettingNotFoundException &e) {
     606           0 :                 return false;
     607             :         }
     608             : }
     609             : 
     610             : 
     611           0 : bool Settings::getNoEx(const std::string &name, std::string &val) const
     612             : {
     613             :         try {
     614           0 :                 val = get(name);
     615           0 :                 return true;
     616           0 :         } catch (SettingNotFoundException &e) {
     617           0 :                 return false;
     618             :         }
     619             : }
     620             : 
     621             : 
     622          16 : bool Settings::getFlag(const std::string &name) const
     623             : {
     624             :         try {
     625          16 :                 return getBool(name);
     626          32 :         } catch(SettingNotFoundException &e) {
     627          16 :                 return false;
     628             :         }
     629             : }
     630             : 
     631             : 
     632           0 : bool Settings::getFloatNoEx(const std::string &name, float &val) const
     633             : {
     634             :         try {
     635           0 :                 val = getFloat(name);
     636           0 :                 return true;
     637           0 :         } catch (SettingNotFoundException &e) {
     638           0 :                 return false;
     639             :         }
     640             : }
     641             : 
     642             : 
     643           0 : bool Settings::getU16NoEx(const std::string &name, u16 &val) const
     644             : {
     645             :         try {
     646           0 :                 val = getU16(name);
     647           0 :                 return true;
     648           0 :         } catch (SettingNotFoundException &e) {
     649           0 :                 return false;
     650             :         }
     651             : }
     652             : 
     653             : 
     654           0 : bool Settings::getS16NoEx(const std::string &name, s16 &val) const
     655             : {
     656             :         try {
     657           0 :                 val = getS16(name);
     658           0 :                 return true;
     659           0 :         } catch (SettingNotFoundException &e) {
     660           0 :                 return false;
     661             :         }
     662             : }
     663             : 
     664             : 
     665           0 : bool Settings::getS32NoEx(const std::string &name, s32 &val) const
     666             : {
     667             :         try {
     668           0 :                 val = getS32(name);
     669           0 :                 return true;
     670           0 :         } catch (SettingNotFoundException &e) {
     671           0 :                 return false;
     672             :         }
     673             : }
     674             : 
     675             : 
     676           0 : bool Settings::getU64NoEx(const std::string &name, u64 &val) const
     677             : {
     678             :         try {
     679           0 :                 val = getU64(name);
     680           0 :                 return true;
     681           0 :         } catch (SettingNotFoundException &e) {
     682           0 :                 return false;
     683             :         }
     684             : }
     685             : 
     686             : 
     687           0 : bool Settings::getV2FNoEx(const std::string &name, v2f &val) const
     688             : {
     689             :         try {
     690           0 :                 val = getV2F(name);
     691           0 :                 return true;
     692           0 :         } catch (SettingNotFoundException &e) {
     693           0 :                 return false;
     694             :         }
     695             : }
     696             : 
     697             : 
     698           0 : bool Settings::getV3FNoEx(const std::string &name, v3f &val) const
     699             : {
     700             :         try {
     701           0 :                 val = getV3F(name);
     702           0 :                 return true;
     703           0 :         } catch (SettingNotFoundException &e) {
     704           0 :                 return false;
     705             :         }
     706             : }
     707             : 
     708             : 
     709             : // N.B. getFlagStrNoEx() does not set val, but merely modifies it.  Thus,
     710             : // val must be initialized before using getFlagStrNoEx().  The intention of
     711             : // this is to simplify modifying a flags field from a default value.
     712           0 : bool Settings::getFlagStrNoEx(const std::string &name, u32 &val,
     713             :         FlagDesc *flagdesc) const
     714             : {
     715             :         try {
     716             :                 u32 flags, flagmask;
     717             : 
     718           0 :                 flags = getFlagStr(name, flagdesc, &flagmask);
     719             : 
     720           0 :                 val &= ~flagmask;
     721           0 :                 val |=  flags;
     722             : 
     723           0 :                 return true;
     724           0 :         } catch (SettingNotFoundException &e) {
     725           0 :                 return false;
     726             :         }
     727             : }
     728             : 
     729             : 
     730             : /***********
     731             :  * Setters *
     732             :  ***********/
     733             : 
     734         247 : bool Settings::setEntry(const std::string &name, const void *data,
     735             :         bool set_group, bool set_default)
     736             : {
     737         247 :         Settings *old_group = NULL;
     738             : 
     739         247 :         if (!checkNameValid(name))
     740           0 :                 return false;
     741         247 :         if (!set_group && !checkValueValid(*(const std::string *)data))
     742           0 :                 return false;
     743             : 
     744             :         {
     745         494 :                 JMutexAutoLock lock(m_mutex);
     746             : 
     747         247 :                 SettingsEntry &entry = set_default ? m_defaults[name] : m_settings[name];
     748         247 :                 old_group = entry.group;
     749             : 
     750         247 :                 entry.value    = set_group ? "" : *(const std::string *)data;
     751         247 :                 entry.group    = set_group ? *(Settings **)data : NULL;
     752         247 :                 entry.is_group = set_group;
     753             :         }
     754             : 
     755         247 :         delete old_group;
     756             : 
     757         247 :         return true;
     758             : }
     759             : 
     760             : 
     761          12 : bool Settings::set(const std::string &name, const std::string &value)
     762             : {
     763          12 :         if (!setEntry(name, &value, false, false))
     764           0 :                 return false;
     765             : 
     766          12 :         doCallbacks(name);
     767          12 :         return true;
     768             : }
     769             : 
     770             : 
     771         235 : bool Settings::setDefault(const std::string &name, const std::string &value)
     772             : {
     773         235 :         return setEntry(name, &value, false, true);
     774             : }
     775             : 
     776             : 
     777           0 : bool Settings::setGroup(const std::string &name, Settings *group)
     778             : {
     779           0 :         return setEntry(name, &group, true, false);
     780             : }
     781             : 
     782             : 
     783           0 : bool Settings::setGroupDefault(const std::string &name, Settings *group)
     784             : {
     785           0 :         return setEntry(name, &group, true, true);
     786             : }
     787             : 
     788             : 
     789           0 : bool Settings::setBool(const std::string &name, bool value)
     790             : {
     791           0 :         return set(name, value ? "true" : "false");
     792             : }
     793             : 
     794             : 
     795           0 : bool Settings::setS16(const std::string &name, s16 value)
     796             : {
     797           0 :         return set(name, itos(value));
     798             : }
     799             : 
     800             : 
     801           0 : bool Settings::setU16(const std::string &name, u16 value)
     802             : {
     803           0 :         return set(name, itos(value));
     804             : }
     805             : 
     806             : 
     807           0 : bool Settings::setS32(const std::string &name, s32 value)
     808             : {
     809           0 :         return set(name, itos(value));
     810             : }
     811             : 
     812             : 
     813           0 : bool Settings::setU64(const std::string &name, u64 value)
     814             : {
     815           0 :         std::ostringstream os;
     816           0 :         os << value;
     817           0 :         return set(name, os.str());
     818             : }
     819             : 
     820             : 
     821           0 : bool Settings::setFloat(const std::string &name, float value)
     822             : {
     823           0 :         return set(name, ftos(value));
     824             : }
     825             : 
     826             : 
     827           0 : bool Settings::setV2F(const std::string &name, v2f value)
     828             : {
     829           0 :         std::ostringstream os;
     830           0 :         os << "(" << value.X << "," << value.Y << ")";
     831           0 :         return set(name, os.str());
     832             : }
     833             : 
     834             : 
     835           0 : bool Settings::setV3F(const std::string &name, v3f value)
     836             : {
     837           0 :         std::ostringstream os;
     838           0 :         os << "(" << value.X << "," << value.Y << "," << value.Z << ")";
     839           0 :         return set(name, os.str());
     840             : }
     841             : 
     842             : 
     843           0 : bool Settings::setFlagStr(const std::string &name, u32 flags,
     844             :         const FlagDesc *flagdesc, u32 flagmask)
     845             : {
     846           0 :         return set(name, writeFlagString(flags, flagdesc, flagmask));
     847             : }
     848             : 
     849             : 
     850           0 : bool Settings::setStruct(const std::string &name, const std::string &format,
     851             :         void *value)
     852             : {
     853           0 :         std::string structstr;
     854           0 :         if (!serializeStructToString(&structstr, format, value))
     855           0 :                 return false;
     856             : 
     857           0 :         return set(name, structstr);
     858             : }
     859             : 
     860             : 
     861           0 : bool Settings::setNoiseParams(const std::string &name,
     862             :         const NoiseParams &np, bool set_default)
     863             : {
     864           0 :         Settings *group = new Settings;
     865             : 
     866           0 :         group->setFloat("offset",      np.offset);
     867           0 :         group->setFloat("scale",       np.scale);
     868           0 :         group->setV3F("spread",        np.spread);
     869           0 :         group->setS32("seed",          np.seed);
     870           0 :         group->setU16("octaves",       np.octaves);
     871           0 :         group->setFloat("persistence", np.persist);
     872           0 :         group->setFloat("lacunarity",  np.lacunarity);
     873           0 :         group->setFlagStr("flags",     np.flags, flagdesc_noiseparams, np.flags);
     874             : 
     875           0 :         return setEntry(name, &group, true, set_default);
     876             : }
     877             : 
     878             : 
     879           0 : bool Settings::remove(const std::string &name)
     880             : {
     881           0 :         JMutexAutoLock lock(m_mutex);
     882             : 
     883           0 :         delete m_settings[name].group;
     884           0 :         return m_settings.erase(name);
     885             : }
     886             : 
     887             : 
     888          13 : void Settings::clear()
     889             : {
     890          26 :         JMutexAutoLock lock(m_mutex);
     891          13 :         clearNoLock();
     892          13 : }
     893             : 
     894           0 : void Settings::clearDefaults()
     895             : {
     896           0 :         JMutexAutoLock lock(m_mutex);
     897           0 :         clearDefaultsNoLock();
     898           0 : }
     899             : 
     900           0 : void Settings::updateValue(const Settings &other, const std::string &name)
     901             : {
     902           0 :         if (&other == this)
     903           0 :                 return;
     904             : 
     905           0 :         JMutexAutoLock lock(m_mutex);
     906             : 
     907             :         try {
     908           0 :                 std::string val = other.get(name);
     909             : 
     910           0 :                 m_settings[name] = val;
     911           0 :         } catch (SettingNotFoundException &e) {
     912             :         }
     913             : }
     914             : 
     915             : 
     916           0 : void Settings::update(const Settings &other)
     917             : {
     918           0 :         if (&other == this)
     919           0 :                 return;
     920             : 
     921           0 :         JMutexAutoLock lock(m_mutex);
     922           0 :         JMutexAutoLock lock2(other.m_mutex);
     923             : 
     924           0 :         updateNoLock(other);
     925             : }
     926             : 
     927             : 
     928         346 : SettingsParseEvent Settings::parseConfigObject(const std::string &line,
     929             :         const std::string &end, std::string &name, std::string &value)
     930             : {
     931         692 :         std::string trimmed_line = trim(line);
     932             : 
     933         346 :         if (trimmed_line.empty())
     934          15 :                 return SPE_NONE;
     935         331 :         if (trimmed_line[0] == '#')
     936           0 :                 return SPE_COMMENT;
     937         331 :         if (trimmed_line == end)
     938           0 :                 return SPE_END;
     939             : 
     940         331 :         size_t pos = trimmed_line.find('=');
     941         331 :         if (pos == std::string::npos)
     942           0 :                 return SPE_INVALID;
     943             : 
     944         331 :         name  = trim(trimmed_line.substr(0, pos));
     945         331 :         value = trim(trimmed_line.substr(pos + 1));
     946             : 
     947         331 :         if (value == "{")
     948           0 :                 return SPE_GROUP;
     949         331 :         if (value == "\"\"\"")
     950           0 :                 return SPE_MULTILINE;
     951             : 
     952         331 :         return SPE_KVPAIR;
     953             : }
     954             : 
     955             : 
     956           0 : void Settings::updateNoLock(const Settings &other)
     957             : {
     958           0 :         m_settings.insert(other.m_settings.begin(), other.m_settings.end());
     959           0 :         m_defaults.insert(other.m_defaults.begin(), other.m_defaults.end());
     960           0 : }
     961             : 
     962             : 
     963          13 : void Settings::clearNoLock()
     964             : {
     965          13 :         std::map<std::string, SettingsEntry>::const_iterator it;
     966         292 :         for (it = m_settings.begin(); it != m_settings.end(); ++it)
     967         279 :                 delete it->second.group;
     968          13 :         m_settings.clear();
     969             : 
     970          13 :         clearDefaultsNoLock();
     971          13 : }
     972             : 
     973          13 : void Settings::clearDefaultsNoLock()
     974             : {
     975          13 :         std::map<std::string, SettingsEntry>::const_iterator it;
     976         248 :         for (it = m_defaults.begin(); it != m_defaults.end(); ++it)
     977         235 :                 delete it->second.group;
     978          13 :         m_defaults.clear();
     979          13 : }
     980             : 
     981             : 
     982           9 : void Settings::registerChangedCallback(std::string name,
     983             :         setting_changed_callback cbf, void *userdata)
     984             : {
     985          18 :         JMutexAutoLock lock(m_callbackMutex);
     986           9 :         m_callbacks[name].push_back(std::make_pair(cbf, userdata));
     987           9 : }
     988             : 
     989           1 : void Settings::deregisterChangedCallback(std::string name, setting_changed_callback cbf, void *userdata)
     990             : {
     991           2 :         JMutexAutoLock lock(m_callbackMutex);
     992           1 :         std::map<std::string, std::vector<std::pair<setting_changed_callback, void*> > >::iterator iterToVector = m_callbacks.find(name);
     993           1 :         if (iterToVector != m_callbacks.end())
     994             :         {
     995           1 :                 std::vector<std::pair<setting_changed_callback, void*> > &vector = iterToVector->second;
     996             : 
     997             :                 std::vector<std::pair<setting_changed_callback, void*> >::iterator position =
     998           1 :                         std::find(vector.begin(), vector.end(), std::make_pair(cbf, userdata));
     999             : 
    1000           1 :                 if (position != vector.end())
    1001           1 :                         vector.erase(position);
    1002             :         }
    1003           1 : }
    1004             : 
    1005          12 : void Settings::doCallbacks(const std::string name)
    1006             : {
    1007          24 :         JMutexAutoLock lock(m_callbackMutex);
    1008          12 :         std::map<std::string, std::vector<std::pair<setting_changed_callback, void*> > >::iterator iterToVector = m_callbacks.find(name);
    1009          12 :         if (iterToVector != m_callbacks.end())
    1010             :         {
    1011           0 :                 std::vector<std::pair<setting_changed_callback, void*> >::iterator iter;
    1012           0 :                 for (iter = iterToVector->second.begin(); iter != iterToVector->second.end(); iter++)
    1013             :                 {
    1014           0 :                         (iter->first)(name, iter->second);
    1015             :                 }
    1016             :         }
    1017          15 : }

Generated by: LCOV version 1.11