IBR-DTNSuite
0.8
|
00001 // ConfigFile.h 00002 // Class for reading named values from configuration files 00003 // Richard J. Wagner v2.1 24 May 2004 wagnerr@umich.edu 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 // Typical usage 00026 // ------------- 00027 // 00028 // Given a configuration file "settings.inp": 00029 // atoms = 25 00030 // length = 8.0 # nanometers 00031 // name = Reece Surcher 00032 // 00033 // Named values are read in various ways, with or without default values: 00034 // ConfigFile config( "settings.inp" ); 00035 // int atoms = config.read<int>( "atoms" ); 00036 // double length = config.read( "length", 10.0 ); 00037 // string author, title; 00038 // config.readInto( author, "name" ); 00039 // config.readInto( title, "title", string("Untitled") ); 00040 // 00041 // See file example.cpp for more examples. 00042 00043 #ifndef IBRCOMMON_CONFIGFILE_H 00044 #define IBRCOMMON_CONFIGFILE_H 00045 00046 #include <string> 00047 #include <map> 00048 #include <iostream> 00049 #include <fstream> 00050 #include <sstream> 00051 00052 using std::string; 00053 00054 namespace ibrcommon 00055 { 00056 class ConfigFile { 00057 // Data 00058 protected: 00059 string myDelimiter; // separator between key and value 00060 string myComment; // separator between value and comments 00061 string mySentry; // optional string to signal end of file 00062 std::map<string,string> myContents; // extracted keys and values 00063 00064 typedef std::map<string,string>::iterator mapi; 00065 typedef std::map<string,string>::const_iterator mapci; 00066 00067 // Methods 00068 public: 00069 ConfigFile( string filename, 00070 string delimiter = "=", 00071 string comment = "#", 00072 string sentry = "EndConfigFile" ); 00073 ConfigFile(); 00074 00075 // Search for key and read value or optional default value 00076 template<class T> T read( const string& key ) const; // call as read<T> 00077 template<class T> T read( const string& key, const T& value ) const; 00078 template<class T> bool readInto( T& var, const string& key ) const; 00079 template<class T> 00080 bool readInto( T& var, const string& key, const T& value ) const; 00081 00082 // Modify keys and values 00083 template<class T> void add( string key, const T& value ); 00084 void remove( const string& key ); 00085 00086 // Check whether key exists in configuration 00087 bool keyExists( const string& key ) const; 00088 00089 // Check or change configuration syntax 00090 string getDelimiter() const { return myDelimiter; } 00091 string getComment() const { return myComment; } 00092 string getSentry() const { return mySentry; } 00093 string setDelimiter( const string& s ) 00094 { string old = myDelimiter; myDelimiter = s; return old; } 00095 string setComment( const string& s ) 00096 { string old = myComment; myComment = s; return old; } 00097 00098 // Write or read configuration 00099 friend std::ostream& operator<<( std::ostream& os, const ConfigFile& cf ); 00100 friend std::istream& operator>>( std::istream& is, ConfigFile& cf ); 00101 00102 protected: 00103 template<class T> static string T_as_string( const T& t ); 00104 template<class T> static T string_as_T( const string& s ); 00105 static void trim( string& s ); 00106 00107 00108 // Exception types 00109 public: 00110 struct file_not_found { 00111 string filename; 00112 file_not_found( const string& filename_ = string() ) 00113 : filename(filename_) {} }; 00114 struct key_not_found { // thrown only by T read(key) variant of read() 00115 string key; 00116 key_not_found( const string& key_ = string() ) 00117 : key(key_) {} }; 00118 }; 00119 00120 00121 /* static */ 00122 template<class T> 00123 string ConfigFile::T_as_string( const T& t ) 00124 { 00125 // Convert from a T to a string 00126 // Type T must support << operator 00127 std::ostringstream ost; 00128 ost << t; 00129 return ost.str(); 00130 } 00131 00132 00133 /* static */ 00134 template<class T> 00135 T ConfigFile::string_as_T( const string& s ) 00136 { 00137 // Convert from a string to a T 00138 // Type T must support >> operator 00139 T t; 00140 std::istringstream ist(s); 00141 ist >> t; 00142 return t; 00143 } 00144 00145 00146 /* static */ 00147 template<> 00148 inline string ConfigFile::string_as_T<string>( const string& s ) 00149 { 00150 // Convert from a string to a string 00151 // In other words, do nothing 00152 return s; 00153 } 00154 00155 00156 /* static */ 00157 template<> 00158 inline bool ConfigFile::string_as_T<bool>( const string& s ) 00159 { 00160 // Convert from a string to a bool 00161 // Interpret "false", "F", "no", "n", "0" as false 00162 // Interpret "true", "T", "yes", "y", "1", "-1", or anything else as true 00163 bool b = true; 00164 string sup = s; 00165 for( string::iterator p = sup.begin(); p != sup.end(); ++p ) 00166 *p = toupper(*p); // make string all caps 00167 if( sup==string("FALSE") || sup==string("F") || 00168 sup==string("NO") || sup==string("N") || 00169 sup==string("0") || sup==string("NONE") ) 00170 b = false; 00171 return b; 00172 } 00173 00174 00175 template<class T> 00176 T ConfigFile::read( const string& key ) const 00177 { 00178 // Read the value corresponding to key 00179 mapci p = myContents.find(key); 00180 if( p == myContents.end() ) throw key_not_found(key); 00181 return string_as_T<T>( p->second ); 00182 } 00183 00184 00185 template<class T> 00186 T ConfigFile::read( const string& key, const T& value ) const 00187 { 00188 // Return the value corresponding to key or given default value 00189 // if key is not found 00190 mapci p = myContents.find(key); 00191 if( p == myContents.end() ) return value; 00192 return string_as_T<T>( p->second ); 00193 } 00194 00195 00196 template<class T> 00197 bool ConfigFile::readInto( T& var, const string& key ) const 00198 { 00199 // Get the value corresponding to key and store in var 00200 // Return true if key is found 00201 // Otherwise leave var untouched 00202 mapci p = myContents.find(key); 00203 bool found = ( p != myContents.end() ); 00204 if( found ) var = string_as_T<T>( p->second ); 00205 return found; 00206 } 00207 00208 00209 template<class T> 00210 bool ConfigFile::readInto( T& var, const string& key, const T& value ) const 00211 { 00212 // Get the value corresponding to key and store in var 00213 // Return true if key is found 00214 // Otherwise set var to given default 00215 mapci p = myContents.find(key); 00216 bool found = ( p != myContents.end() ); 00217 if( found ) 00218 var = string_as_T<T>( p->second ); 00219 else 00220 var = value; 00221 return found; 00222 } 00223 00224 00225 template<class T> 00226 void ConfigFile::add( string key, const T& value ) 00227 { 00228 // Add a key with given value 00229 string v = T_as_string( value ); 00230 trim(key); 00231 trim(v); 00232 myContents[key] = v; 00233 return; 00234 } 00235 } 00236 00237 #endif // CONFIGFILE_H 00238 00239 // Release notes: 00240 // v1.0 21 May 1999 00241 // + First release 00242 // + Template read() access only through non-member readConfigFile() 00243 // + ConfigurationFileBool is only built-in helper class 00244 // 00245 // v2.0 3 May 2002 00246 // + Shortened name from ConfigurationFile to ConfigFile 00247 // + Implemented template member functions 00248 // + Changed default comment separator from % to # 00249 // + Enabled reading of multiple-line values 00250 // 00251 // v2.1 24 May 2004 00252 // + Made template specializations inline to avoid compiler-dependent linkage 00253 // + Allowed comments within multiple-line values 00254 // + Enabled blank line termination for multiple-line values 00255 // + Added optional sentry to detect end of configuration file 00256 // + Rewrote messy trimWhitespace() function as elegant trim()