wsdlpull 1.23
|
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 CONFIGFILE_H 00044 #define 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 class ConfigFile { 00055 // Data 00056 protected: 00057 string myDelimiter; // separator between key and value 00058 string myComment; // separator between value and comments 00059 string mySentry; // optional string to signal end of file 00060 std::map<string,string> myContents; // extracted keys and values 00061 00062 typedef std::map<string,string>::iterator mapi; 00063 typedef std::map<string,string>::const_iterator mapci; 00064 std::string file; 00065 bool listmode; 00066 00067 // Methods 00068 public: 00069 ConfigFile( string filename, 00070 bool isList=false, 00071 string delimiter = "=", 00072 string comment = "##", 00073 string sentry = "EndConfigFile" 00074 ); 00075 ConfigFile(); 00076 00077 // Search for key and read value or optional default value 00078 template<class T> T read( const string& key ) const; // call as read<T> 00079 template<class T> T read( const string& key, const T& value ) const; 00080 template<class T> bool readInto( T& var, const string& key ) const; 00081 template<class T> 00082 bool readInto( T& var, const string& key, const T& value ) const; 00083 00084 // Modify keys and values 00085 template<class T> void add( string key, const T& value ,bool store=false); 00086 template<class T> void add( const T& key ,bool store=false); //for simple list mode 00087 void remove( const string& key ); 00088 template<class T>void remove( const T& key );//simple list mode 00089 00090 // Check whether key exists in configuration 00091 bool keyExists( const string& key ) const; 00092 template<class T> bool keyExists(const T & key) const;//for list mode 00093 00094 // Check or change configuration syntax 00095 string getDelimiter() const { return myDelimiter; } 00096 string getComment() const { return myComment; } 00097 string getSentry() const { return mySentry; } 00098 string setDelimiter( const string& s ) 00099 { string old = myDelimiter; myDelimiter = s; return old; } 00100 string setComment( const string& s ) 00101 { string old = myComment; myComment = s; return old; } 00102 00103 // Write or read configuration 00104 friend std::ostream& operator<<( std::ostream& os, const ConfigFile& cf ); 00105 friend std::istream& operator>>( std::istream& is, ConfigFile& cf ); 00106 00107 void load(string filename,bool isList=false); 00108 void save(); 00109 00110 protected: 00111 template<class T> static string T_as_string( const T& t ); 00112 template<class T> static T string_as_T( const string& s ); 00113 static void trim( string& s ); 00114 00115 00116 // Exception types 00117 public: 00118 struct file_not_found { 00119 string filename; 00120 file_not_found( const string& filename_ = string() ) 00121 : filename(filename_) {} }; 00122 struct key_not_found { // thrown only by T read(key) variant of read() 00123 string key; 00124 key_not_found( const string& key_ = string() ) 00125 : key(key_) {} }; 00126 }; 00127 00128 00129 /* static */ 00130 template<class T> 00131 string ConfigFile::T_as_string( const T& t ) 00132 { 00133 // Convert from a T to a string 00134 // Type T must support << operator 00135 std::ostringstream ost; 00136 ost << t; 00137 return ost.str(); 00138 } 00139 00140 00141 /* static */ 00142 template<class T> 00143 T ConfigFile::string_as_T( const string& s ) 00144 { 00145 // Convert from a string to a T 00146 // Type T must support >> operator 00147 T t; 00148 std::istringstream ist(s); 00149 ist >> t; 00150 return t; 00151 } 00152 00153 00154 /* static */ 00155 template<> 00156 inline string ConfigFile::string_as_T<string>( const string& s ) 00157 { 00158 // Convert from a string to a string 00159 // In other words, do nothing 00160 return s; 00161 } 00162 00163 00164 /* static */ 00165 template<> 00166 inline bool ConfigFile::string_as_T<bool>( const string& s ) 00167 { 00168 // Convert from a string to a bool 00169 // Interpret "false", "F", "no", "n", "0" as false 00170 // Interpret "true", "T", "yes", "y", "1", "-1", or anything else as true 00171 bool b = true; 00172 string sup = s; 00173 for( string::iterator p = sup.begin(); p != sup.end(); ++p ) 00174 *p = toupper(*p); // make string all caps 00175 if( sup==string("FALSE") || sup==string("F") || 00176 sup==string("NO") || sup==string("N") || 00177 sup==string("0") || sup==string("NONE") ) 00178 b = false; 00179 return b; 00180 } 00181 00182 00183 template<class T> 00184 T ConfigFile::read( const string& key ) const 00185 { 00186 // Read the value corresponding to key 00187 mapci p = myContents.find(key); 00188 if( p == myContents.end() ) throw key_not_found(key); 00189 return string_as_T<T>( p->second ); 00190 } 00191 00192 00193 template<class T> 00194 T ConfigFile::read( const string& key, const T& value ) const 00195 { 00196 // Return the value corresponding to key or given default value 00197 // if key is not found 00198 mapci p = myContents.find(key); 00199 if( p == myContents.end() ) return value; 00200 return string_as_T<T>( p->second ); 00201 } 00202 00203 00204 template<class T> 00205 bool ConfigFile::readInto( T& var, const string& key ) const 00206 { 00207 // Get the value corresponding to key and store in var 00208 // Return true if key is found 00209 // Otherwise leave var untouched 00210 mapci p = myContents.find(key); 00211 bool found = ( p != myContents.end() ); 00212 if( found ) var = string_as_T<T>( p->second ); 00213 return found; 00214 } 00215 00216 00217 template<class T> 00218 bool ConfigFile::readInto( T& var, const string& key, const T& value ) const 00219 { 00220 // Get the value corresponding to key and store in var 00221 // Return true if key is found 00222 // Otherwise set var to given default 00223 mapci p = myContents.find(key); 00224 bool found = ( p != myContents.end() ); 00225 if( found ) 00226 var = string_as_T<T>( p->second ); 00227 else 00228 var = value; 00229 return found; 00230 } 00231 00232 00233 template<class T> 00234 void ConfigFile::add( string key, const T& value ,bool store) 00235 { 00236 // Add a key with given value 00237 string v = T_as_string( value ); 00238 trim(key); 00239 trim(v); 00240 myContents[key] = v; 00241 if (store) 00242 { 00243 //append the values in the file immediately 00244 std::ofstream os(file.c_str(),std::ios::app); 00245 os << key << " " << myDelimiter << " "; 00246 os << v << std::endl; 00247 os.close(); 00248 } 00249 return; 00250 } 00251 //for a list mode kind of config file 00252 template<class T> 00253 void ConfigFile::add( const T& key ,bool store) 00254 { 00255 if(keyExists(key)) 00256 return; 00257 string v = T_as_string( key ); 00258 trim(v); 00259 myContents[v] = " "; 00260 if(store) 00261 { 00262 std::ofstream os(file.c_str(),std::ios::app); 00263 os << v << std::endl; 00264 os.close(); 00265 } 00266 00267 } 00268 00269 template<class T> 00270 void ConfigFile::remove( const T& key ) 00271 { 00272 if(keyExists(key)) 00273 return; 00274 string v = T_as_string( key ); 00275 trim(v); 00276 myContents.erase( myContents.find( v ) ); 00277 save(); 00278 00279 } 00280 template<class T> 00281 bool ConfigFile::keyExists(const T & key) const 00282 { 00283 00284 string v = T_as_string( key ); 00285 mapci p = myContents.find( v ); 00286 return ( p != myContents.end() ); 00287 00288 } 00289 #endif // CONFIGFILE_H 00290 00291 // Release notes: 00292 // v1.0 21 May 1999 00293 // + First release 00294 // + Template read() access only through non-member readConfigFile() 00295 // + ConfigurationFileBool is only built-in helper class 00296 // 00297 // v2.0 3 May 2002 00298 // + Shortened name from ConfigurationFile to ConfigFile 00299 // + Implemented template member functions 00300 // + Changed default comment separator from % to # 00301 // + Enabled reading of multiple-line values 00302 // 00303 // v2.1 24 May 2004 00304 // + Made template specializations inline to avoid compiler-dependent linkage 00305 // + Allowed comments within multiple-line values 00306 // + Enabled blank line termination for multiple-line values 00307 // + Added optional sentry to detect end of configuration file 00308 // + Rewrote messy trimWhitespace() function as elegant trim()