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