LogCabin
|
00001 /* 00002 * This file was downloaded from: 00003 * http://www-personal.umich.edu/~wagnerr/ConfigFile.html 00004 * 00005 * Copyright (c) 2004 Richard J. Wagner 00006 * 00007 * Permission is hereby granted, free of charge, to any person obtaining a copy 00008 * of this software and associated documentation files (the "Software"), to 00009 * deal in the Software without restriction, including without limitation the 00010 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 00011 * sell copies of the Software, and to permit persons to whom the Software is 00012 * furnished to do so, subject to the following conditions: 00013 * 00014 * The above copyright notice and this permission notice shall be included in 00015 * all copies or substantial portions of the Software. 00016 * 00017 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00018 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00019 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00020 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00021 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 00022 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 00023 * IN THE SOFTWARE. 00024 * 00025 * ------------------------------------------------ 00026 * 00027 * It was subsequently modified: 00028 * 00029 * Copyright (c) 2012 Stanford University 00030 * Copyright (c) 2015 Diego Ongaro 00031 * 00032 * Permission to use, copy, modify, and distribute this software for any 00033 * purpose with or without fee is hereby granted, provided that the above 00034 * copyright notice and this permission notice appear in all copies. 00035 * 00036 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES 00037 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 00038 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR 00039 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00040 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 00041 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 00042 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00043 */ 00044 00045 #include <iostream> 00046 #include <map> 00047 #include <sstream> 00048 #include <stdexcept> 00049 #include <string> 00050 #include <typeinfo> 00051 00052 #ifndef LOGCABIN_CORE_CONFIG_H 00053 #define LOGCABIN_CORE_CONFIG_H 00054 00055 namespace LogCabin { 00056 namespace Core { 00057 00058 /** 00059 * Reads and writes configuration files. 00060 */ 00061 class Config { 00062 typedef std::string string; 00063 00064 public: 00065 /** 00066 * Base class for Config exceptions. 00067 */ 00068 struct Exception : public std::runtime_error { 00069 explicit Exception(const std::string& error); 00070 }; 00071 00072 00073 struct FileNotFound : public Exception { 00074 explicit FileNotFound(const string& filename); 00075 virtual ~FileNotFound() throw() {} 00076 string filename; 00077 }; 00078 00079 // thrown only by T read(key) variant of read() 00080 struct KeyNotFound : public Exception { 00081 explicit KeyNotFound(const string& key); 00082 virtual ~KeyNotFound() throw() {} 00083 string key; 00084 }; 00085 00086 struct ConversionError : public Exception { 00087 ConversionError(const string& key, 00088 const string& value, 00089 const string& typeName); 00090 virtual ~ConversionError() throw() {} 00091 string key; 00092 string value; 00093 string typeName; 00094 }; 00095 00096 /** 00097 * Construct an empty Config. 00098 */ 00099 explicit Config(const string& delimiter = "=", 00100 const string& comment = "#"); 00101 00102 /** 00103 * Construct a Config from the given map of options. 00104 */ 00105 explicit Config(const std::map<string, string>& options); 00106 00107 /** 00108 * Load a Config from a file. 00109 * This is a convenience wrapper around operator>>. 00110 * \throw FileNotFound 00111 */ 00112 void readFile(const string& filename); 00113 00114 /** 00115 * Read configuration. 00116 */ 00117 friend std::istream& operator>>(std::istream& is, Config& cf); 00118 00119 /** 00120 * Write configuration. 00121 */ 00122 friend std::ostream& operator<<(std::ostream& os, const Config& cf); 00123 00124 /** 00125 * Read the value corresponding to a key. 00126 * \return 00127 * The desired value, converted to a T. 00128 * \throw KeyNotFound 00129 * If the key does not exist. 00130 * \throw ConversionError 00131 * If the value could not be converted to a T. 00132 */ 00133 template<class T = string> 00134 T read(const string& key) const; 00135 00136 /** 00137 * Return the value corresponding to key or given default value if key is 00138 * not found. 00139 * \throw ConversionError 00140 * If the value could not be converted to a T. 00141 */ 00142 template<class T = string> 00143 T read(const string& key, const T& value) const; 00144 00145 /** 00146 * Check whether key exists in configuration. 00147 */ 00148 bool keyExists(const string& key) const; 00149 00150 /** 00151 * Set a key to the given value. 00152 */ 00153 template<class T> void set(const string& key, const T& value); 00154 00155 /** 00156 * Set a key to the given string value. 00157 */ 00158 void set(const string& key, const string& value); 00159 00160 /** 00161 * Remove a key and its value. 00162 * If the key does not exist, this will do nothing. 00163 */ 00164 void remove(const string& key); 00165 00166 private: 00167 /** 00168 * Convert from a T to a string. 00169 * Type T must support << operator. 00170 */ 00171 template<class T> 00172 static string toString(const T& t); 00173 00174 /** 00175 * Convert from a string to a T. 00176 * Type T must support >> operator. 00177 * 00178 * For boolean conversions, "false", "f", "no", "n", "0" are false, and 00179 * "true", "t", "yes", "y", "1" are true. 00180 * 00181 * \throw ConversionError 00182 */ 00183 template<class T> 00184 static T fromString(const string& key, const string& s); 00185 00186 /** 00187 * Read a line, strip comments, and trim it. 00188 */ 00189 std::string readLine(std::istream& is) const; 00190 00191 /// Separator between key and value, usually "=". 00192 const string delimiter; 00193 00194 /// Starts a comment, usually "#". 00195 const string comment; 00196 00197 /// Extracted keys and values. 00198 std::map<string, string> contents; 00199 }; 00200 00201 template<class T> 00202 std::string 00203 Config::toString(const T& t) 00204 { 00205 std::ostringstream ost; 00206 ost.setf(std::ostringstream::boolalpha); 00207 ost << t; 00208 return ost.str(); 00209 } 00210 00211 template<class T> 00212 T 00213 Config::fromString(const string& key, const string& s) 00214 { 00215 T t; 00216 std::istringstream ist(s); 00217 ist >> t; 00218 if (!ist || !ist.eof()) 00219 throw ConversionError(key, s, typeid(T).name()); 00220 return t; 00221 } 00222 00223 template<> 00224 std::string 00225 Config::fromString<std::string>(const string& key, const string& s); 00226 00227 template<> 00228 bool 00229 Config::fromString<bool>(const string& key, const string& s); 00230 00231 00232 template<class T> 00233 T 00234 Config::read(const string& key) const 00235 { 00236 auto p = contents.find(key); 00237 if (p == contents.end()) 00238 throw KeyNotFound(key); 00239 return fromString<T>(key, p->second); 00240 } 00241 00242 template<class T> 00243 T 00244 Config::read(const string& key, const T& value) const 00245 { 00246 auto p = contents.find(key); 00247 if (p == contents.end()) 00248 return value; 00249 return fromString<T>(key, p->second); 00250 } 00251 00252 template<class T> 00253 void 00254 Config::set(const string& key, const T& value) 00255 { 00256 set(key, toString(value)); 00257 } 00258 00259 } // namespace LogCabin::Core 00260 } // namespace LogCabin 00261 00262 #endif /* LOGCABIN_CORE_CONFIG_H */