/* Minetest Copyright (C) 2010-2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef SETTINGS_HEADER #define SETTINGS_HEADER #include "irrlichttypes_bloated.h" #include "exceptions.h" #include #include "jthread/jmutex.h" #include "jthread/jmutexautolock.h" #include "strfnd.h" #include #include #include #include "debug.h" #include "log.h" #include "util/string.h" #include "util/serialize.h" #include #include #include #include "filesys.h" #include enum ValueType { VALUETYPE_STRING, VALUETYPE_FLAG // Doesn't take any arguments }; struct ValueSpec { ValueSpec(ValueType a_type, const char *a_help=NULL) { type = a_type; help = a_help; } ValueType type; const char *help; }; class Settings { public: Settings() { } void writeLines(std::ostream &os) { JMutexAutoLock lock(m_mutex); for(std::map::iterator i = m_settings.begin(); i != m_settings.end(); ++i) { std::string name = i->first; std::string value = i->second; os< getNames(){ std::vector names; for(std::map::iterator i = m_settings.begin(); i != m_settings.end(); ++i) { names.push_back(i->first); } return names; } // remove a setting bool remove(const std::string& name) { return m_settings.erase(name); } bool parseConfigLine(const std::string &line) { JMutexAutoLock lock(m_mutex); std::string trimmedline = trim(line); // Ignore empty lines and comments if(trimmedline.size() == 0 || trimmedline[0] == '#') return true; //infostream<<"trimmedline=\""< &dst, std::set &updated, bool &value_changed) { JMutexAutoLock lock(m_mutex); if(is.eof()) return false; // NOTE: This function will be expanded to allow multi-line settings std::string line; std::getline(is, line); std::string trimmedline = trim(line); std::string line_end = ""; if(is.eof() == false) line_end = "\n"; // Ignore empty lines and comments if(trimmedline.size() == 0 || trimmedline[0] == '#') { dst.push_back(line+line_end); return true; } Strfnd sf(trim(line)); std::string name = sf.next("="); name = trim(name); if(name == "") { dst.push_back(line+line_end); return true; } std::string value = sf.next("\n"); value = trim(value); if(m_settings.find(name) != m_settings.end()) { std::string newvalue = m_settings[name]; if(newvalue != value) { infostream<<"Changing value of \""< \""< objects; std::set updated; bool something_actually_changed = false; // Read and modify stuff { std::ifstream is(filename); if(is.good() == false) { infostream<<"updateConfigFile():" " Error opening configuration file" " for reading: \"" <::iterator i = m_settings.begin(); i != m_settings.end(); ++i) { if(updated.find(i->first) != updated.end()) continue; something_actually_changed = true; break; } } // If nothing was actually changed, skip writing the file if(!something_actually_changed){ infostream<<"Skipping writing of "<::iterator i = objects.begin(); i != objects.end(); ++i) { ss<<(*i); } /* Write stuff that was not already in the file */ for(std::map::iterator i = m_settings.begin(); i != m_settings.end(); ++i) { if(updated.find(i->first) != updated.end()) continue; std::string name = i->first; std::string value = i->second; infostream<<"Adding \""< &allowed_options) { int nonopt_index = 0; int i=1; for(;;) { if(i >= argc) break; std::string argname = argv[i]; if(argname.substr(0, 2) != "--") { // If option doesn't start with -, read it in as nonoptX if(argname[0] != '-'){ std::string name = "nonopt"; name += itos(nonopt_index); set(name, argname); nonopt_index++; i++; continue; } errorstream<<"Invalid command-line parameter \"" < expected."<::iterator n; n = allowed_options.find(name); if(n == allowed_options.end()) { errorstream<<"Unknown command-line parameter \"" <second.type; std::string value = ""; if(type == VALUETYPE_FLAG) { value = "true"; } else { if(i >= argc) { errorstream<<"Invalid command-line parameter \"" <::iterator n; n = m_settings.find(name); if(n == m_settings.end()) { n = m_defaults.find(name); if(n == m_defaults.end()) { throw SettingNotFoundException(("Setting [" + name + "] not found ").c_str()); } } return n->second; } //////////// Get setting bool getBool(std::string name) { return is_yes(get(name)); } bool getFlag(std::string name) { try { return getBool(name); } catch(SettingNotFoundException &e) { return false; } } // Asks if empty bool getBoolAsk(std::string name, std::string question, bool def) { // If it is in settings if(exists(name)) return getBool(name); std::string s; char templine[10]; std::cout<>value; return value; } u32 getFlagStr(std::string name, FlagDesc *flagdesc, u32 *flagmask) { std::string val = get(name); return (std::isdigit(val[0])) ? stoi(val) : readFlagString(val, flagdesc, flagmask); } // N.B. if getStruct() is used to read a non-POD aggregate type, // the behavior is undefined. bool getStruct(std::string name, std::string format, void *out, size_t olen) { std::string valstr; try { valstr = get(name); } catch (SettingNotFoundException &e) { return false; } if (!deSerializeStringToStruct(valstr, format, out, olen)) return false; return true; } //////////// Try to get value, no exception thrown bool getNoEx(std::string name, std::string &val) { try { val = get(name); return true; } catch (SettingNotFoundException &e) { return false; } } // 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 getFlagStrNoEx(std::string name, u32 &val, FlagDesc *flagdesc) { try { u32 flags, flagmask; flags = getFlagStr(name, flagdesc, &flagmask); val &= ~flagmask; val |= flags; return true; } catch (SettingNotFoundException &e) { return false; } } bool getFloatNoEx(std::string name, float &val) { try { val = getFloat(name); return true; } catch (SettingNotFoundException &e) { return false; } } bool getU16NoEx(std::string name, int &val) { try { val = getU16(name); return true; } catch (SettingNotFoundException &e) { return false; } } bool getU16NoEx(std::string name, u16 &val) { try { val = getU16(name); return true; } catch (SettingNotFoundException &e) { return false; } } bool getS16NoEx(std::string name, int &val) { try { val = getU16(name); return true; } catch (SettingNotFoundException &e) { return false; } } bool getS16NoEx(std::string name, s16 &val) { try { val = getS16(name); return true; } catch (SettingNotFoundException &e) { return false; } } bool getS32NoEx(std::string name, s32 &val) { try { val = getS32(name); return true; } catch (SettingNotFoundException &e) { return false; } } bool getV3FNoEx(std::string name, v3f &val) { try { val = getV3F(name); return true; } catch (SettingNotFoundException &e) { return false; } } bool getV2FNoEx(std::string name, v2f &val) { try { val = getV2F(name); return true; } catch (SettingNotFoundException &e) { return false; } } bool getU64NoEx(std::string name, u64 &val) { try { val = getU64(name); return true; } catch (SettingNotFoundException &e) { return false; } } //////////// Set setting // N.B. if setStruct() is used to write a non-POD aggregate type, // the behavior is undefined. bool setStruct(std::string name, std::string format, void *value) { std::string structstr; if (!serializeStructToString(&structstr, format, value)) return false; set(name, structstr); return true; } void setFlagStr(std::string name, u32 flags, FlagDesc *flagdesc, u32 flagmask) { set(name, writeFlagString(flags, flagdesc, flagmask)); } void setBool(std::string name, bool value) { if(value) set(name, "true"); else set(name, "false"); } void setFloat(std::string name, float value) { set(name, ftos(value)); } void setV3F(std::string name, v3f value) { std::ostringstream os; os<<"("< m_settings; std::map m_defaults; // All methods that access m_settings/m_defaults directly should lock this. JMutex m_mutex; }; #endif