ConfigFile.hpp

Go to the documentation of this file.
00001 // ConfigFile.hpp
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 //  Modified 04 February 2011 by
00044 //  Franz Ehrenhuber, Codronic GmbH
00045 //
00046 //  It's now possible to query sections in config files
00047 //  Default sections are defined like [sectionname],
00048 //  but it is possible to use different tags
00049 //  Section related adding/removing of entries is implemented.
00050 //  Changes have to be saved.
00051 //
00052 //  Examples:
00053 //  youbot::ConfigFile *cfgFile = new youbot::ConfigFile("youbot-manipulator", path);
00054 //  cfgFile->readInto( i1, "Joint_5", "UpperLimit_[encoderTicks]");
00055 //  if(cfgFile->keyExists("Joint_3", "CalibrationDirection"))
00056 //  {
00057 //    cout << "Key CalibrationDirection exists" << endl;
00058 //  }
00059 //  cfgFile->remove("Joint_1", "Test");
00060 //  cfgFile->add("Joint_1", "Test1", 77);
00061 //  cfgFile->save();
00062 //***************************************************************************
00063 
00064 #ifndef CONFIGFILE_HPP
00065 #define CONFIGFILE_HPP
00066 
00067 #include <string>
00068 #include <map>
00069 #include <vector>
00070 #include <algorithm>
00071 #include <iostream>
00072 #include <fstream>
00073 #include <sstream>
00074 #include "Exceptions.hpp"
00075 
00076 using std::string;
00077 
00078 namespace youbot {
00079 
00080 ///////////////////////////////////////////////////////////////////////////////
00081 /// Keep track of sortorder from original configfile
00082 ///////////////////////////////////////////////////////////////////////////////
00083   class SortTreeVector {
00084   protected:
00085     string myKey;
00086     vector<string> mySortVector;
00087 
00088   public:
00089 
00090     SortTreeVector() {
00091       myKey = "";
00092     };
00093 
00094     string getKey() {
00095       if (myKey.empty()) return "";
00096 
00097       if (myKey.size() > 0) {
00098         return myKey;
00099       }
00100 
00101       return "";
00102 
00103 
00104     }
00105 
00106     void setKey(const string& sKey) {
00107       myKey = sKey;
00108     }
00109 
00110     std::vector<string> getVector() const {
00111       return mySortVector;
00112     }
00113 
00114     void setVector(const std::vector<string>& vVector) {
00115       mySortVector = vVector;
00116     }
00117 
00118     ~SortTreeVector() {
00119     };
00120 
00121   };
00122 
00123   ///////////////////////////////////////////////////////////////////////////////
00124   /// Reads and writes a configuration file
00125   ///////////////////////////////////////////////////////////////////////////////
00126   class ConfigFile {
00127     // Data
00128   protected:
00129     string myDelimiter; // separator between key and value
00130     string myComment; // separator between value and comments
00131     string mySectionStartTag; // tag marks the beginning of a section header
00132     string mySectionEndTag; // tag marks the end of a section header
00133     string mySentry; // optional string to signal end of file
00134     string myFilepath; //Path to Configfile
00135     SortTreeVector *mySortVectorObj; // Keeps vector for sorting contents and its relation to the Section Key
00136 
00137     std::map<string, string> myContents; // extracted keys and values
00138     std::map<string, std::map<string, string> > mySectionRelatedContents; // A List of all sections with their extrated key/values
00139 
00140     std::vector<SortTreeVector> mySortVector; // keeps SortTreeVector objects for sorting on Sections an their contents
00141 
00142     typedef std::map<string, string>::iterator mapi;
00143     typedef std::map<string, string>::const_iterator mapci;
00144     typedef std::map<string, map<string, string> >::const_iterator mapciSect;
00145 
00146     // Methods
00147   public:
00148 
00149     ConfigFile(string filename,
00150             string filepath = "../config/",
00151             string delimiter = "=",
00152             string comment = "#",
00153             string sectionStartTag = "[",
00154             string sectionEndTag = "]",
00155             string sentry = "EndConfigFile");
00156     ConfigFile();
00157     
00158     ~ConfigFile(){};
00159 
00160     // Search for key and read value or optional default value
00161     template<class T> T read(const string& key, const T& value)const;
00162 
00163     //Overload to read key from section lines
00164     template<class T> T read(const string& key) const; // call as read<T>
00165 
00166     //Overload to read key from section lines
00167     template<class T> T read(const string& sectionKey, const string& key); // call as read<T>
00168 
00169 
00170     //Read key into ref variable
00171     template<class T> bool readInto(T& var, const string& key) const;
00172     //Overload to read key from section lines
00173     template<class T> bool readInto(T& var, const string& sectionKey, const string& key);
00174 
00175     template<class T>
00176     bool readInto(T& var, const string& key, const T& value) const;
00177 
00178     // Modify keys and values
00179     template<class T> void add(string key, const T& value);
00180 
00181     // Modify keys and values beyond a sectionkey
00182     template<class T> void add(string sectionKey, string key, const T& value);
00183 
00184 
00185     //Remove key from config file with no sections
00186     void remove(const string& key);
00187     //Remove one key from specified section
00188     void remove(const string& sectionKey, const string& key);
00189 
00190     //Save Changes to Configfile
00191     //should be invoked after removing/adding keys
00192     void save();
00193 
00194 
00195 
00196     // Check whether key exists in configuration
00197     bool keyExists(const string& key) const;
00198     // Overload to check key inside a section
00199     bool keyExists(const string& sectionKey, const string& key);
00200 
00201     //Check for existing section
00202     bool sectionExists(const string& sectionKey);
00203 
00204 
00205 
00206     // Check or change configuration syntax
00207 
00208     string getDelimiter() const {
00209       return myDelimiter;
00210     }
00211 
00212     string getComment() const {
00213       return myComment;
00214     }
00215 
00216     string getSentry() const {
00217       return mySentry;
00218     }
00219 
00220     string setDelimiter(const string& s) {
00221       string old = myDelimiter;
00222       myDelimiter = s;
00223       return old;
00224     }
00225 
00226     string setComment(const string& s) {
00227       string old = myComment;
00228       myComment = s;
00229       return old;
00230     }
00231 
00232     // Write or read configuration
00233     friend std::ostream & operator<<(std::ostream& os, ConfigFile& cf);
00234     friend std::istream & operator>>(std::istream& is, ConfigFile& cf);
00235 
00236   protected:
00237     template<class T> static string T_as_string(const T& t);
00238     template<class T> static T string_as_T(const string& s);
00239     static void trim(string& s);
00240 
00241   };
00242 
00243   /* static */
00244   template<class T>
00245   string ConfigFile::T_as_string(const T& t) {
00246     // Convert from a T to a string
00247     // Type T must support << operator
00248     std::ostringstream ost;
00249     ost << t;
00250     return ost.str();
00251   }
00252 
00253   /* static */
00254   template<class T>
00255   T ConfigFile::string_as_T(const string& s) {
00256     // Convert from a string to a T
00257     // Type T must support >> operator
00258     T t;
00259     std::istringstream ist(s);
00260     ist >> t;
00261     return t;
00262   }
00263 
00264   /* static */
00265   template<>
00266   inline string ConfigFile::string_as_T<string>(const string& s) {
00267     // Convert from a string to a string
00268     // In other words, do nothing
00269     return s;
00270   }
00271 
00272   /* static */
00273   template<>
00274   inline bool ConfigFile::string_as_T<bool>(const string& s) {
00275     // Convert from a string to a bool
00276     // Interpret "false", "F", "no", "n", "0" as false
00277     // Interpret "true", "T", "yes", "y", "1", "-1", or anything else as true
00278     bool b = true;
00279     string sup = s;
00280     for (string::iterator p = sup.begin(); p != sup.end(); ++p)
00281       *p = toupper(*p); // make string all caps
00282     if (sup == string("FALSE") || sup == string("F") ||
00283             sup == string("NO") || sup == string("N") ||
00284             sup == string("0") || sup == string("NONE"))
00285       b = false;
00286     return b;
00287   }
00288 
00289   template<class T>
00290   T ConfigFile::read(const string& key) const {
00291     mapci p = myContents.find(key);
00292     if (p == myContents.end()) throw KeyNotFoundException(key);
00293     return string_as_T<T > (p->second);
00294   }
00295 
00296   template<class T>
00297   T ConfigFile::read(const string& sectionKey, const string& key) {
00298     // Read the value corresponding to key
00299     mapciSect sp = mySectionRelatedContents.find(sectionKey);
00300     if (sp == mySectionRelatedContents.end()) throw KeyNotFoundException(sectionKey);
00301 
00302     myContents = sp->second;
00303     mapci p = myContents.find(key);
00304     if (p == myContents.end()) throw KeyNotFoundException(key);
00305     return string_as_T<T > (p->second);
00306   }
00307 
00308   template<class T>
00309   T ConfigFile::read(const string& key, const T& value) const {
00310     // Return the value corresponding to key or given default value
00311     // if key is not found
00312     mapci p = myContents.find(key);
00313     if (p == myContents.end()) return value;
00314     return string_as_T<T > (p->second);
00315   }
00316 
00317   template<class T>
00318   bool ConfigFile::readInto(T& var, const string& key) const {
00319     // Get the value corresponding to key and store in var
00320     // Return true if key is found
00321     // Otherwise leave var untouched
00322 
00323     mapci p = myContents.find(key);
00324     bool found = (p != myContents.end());
00325     if (found) {
00326       var = string_as_T<T > (p->second);
00327     } else {
00328       throw KeyNotFoundException(key);
00329     }
00330     return found;
00331   }
00332 
00333   template<class T>
00334   bool ConfigFile::readInto(T& var, const string& sectionKey, const string& key) {
00335     // Get the value corresponding to key and store in var
00336     // Return true if key is found
00337     // Otherwise leave var untouched
00338 
00339     mapciSect sp = mySectionRelatedContents.find(sectionKey);
00340     if (sp == mySectionRelatedContents.end()) throw KeyNotFoundException(sectionKey);
00341 
00342 
00343     myContents = sp->second;
00344 
00345     mapci p = myContents.find(key);
00346     bool found = (p != myContents.end());
00347     if (found) {
00348       var = string_as_T<T > (p->second);
00349     } else {
00350       throw KeyNotFoundException(key);
00351     }
00352     return found;
00353   }
00354 
00355   template<class T>
00356   void ConfigFile::add(string key, const T& value) {
00357     // Add a key with given value
00358     string v = T_as_string(value);
00359     trim(key);
00360     trim(v);
00361     //Check for dublicate keys
00362     mapi p = myContents.find(key);
00363     if (p != myContents.end()) {
00364       return;
00365     }
00366     myContents[key] = v;
00367     return;
00368   }
00369 
00370   template<class T>
00371   void ConfigFile::add(string sectionKey, string key, const T& value) {
00372 
00373 
00374     // Add a key with given value
00375     string v = T_as_string(value);
00376     trim(key);
00377     trim(v);
00378 
00379     mapciSect sp = mySectionRelatedContents.find(sectionKey);
00380 
00381     //Write SectionKey  with values if no section found
00382     if (sp == mySectionRelatedContents.end()) {
00383       SortTreeVector vsort;
00384       vector<string> vNewVal;
00385       map<string, string> newMap;
00386       newMap[key] = v;
00387       vsort.setKey(sectionKey);
00388       vNewVal.push_back(key);
00389       vsort.setVector(vNewVal);
00390       mySectionRelatedContents[sectionKey] = newMap;
00391       mySortVector.push_back(vsort);
00392       return;
00393     }
00394 
00395     myContents = sp->second;
00396 
00397     //Check for dublicate keys
00398     mapi p = myContents.find(key);
00399     if (p != myContents.end()) {
00400       return;
00401     }
00402 
00403     myContents[key] = v;
00404     mySectionRelatedContents[sectionKey] = myContents;
00405 
00406     for (unsigned int i = 0; i < mySortVector.size(); i++) {
00407 
00408       if (mySortVector[i].getKey() == sectionKey) {
00409         vector<string> sortVec = mySortVector[i].getVector();
00410         sortVec.push_back(key);
00411         mySortVector[i].setVector(sortVec);
00412 
00413 
00414       }
00415     }
00416 
00417 
00418     return;
00419   }
00420 
00421 
00422 } // namespace youbot
00423 
00424 #endif  // CONFIGFILE_HPP
00425 
00426 // Release notes:
00427 // v1.0  21 May 1999
00428 //   + First release
00429 //   + Template read() access only through non-member readConfigFile()
00430 //   + ConfigurationFileBool is only built-in helper class
00431 // 
00432 // v2.0  3 May 2002
00433 //   + Shortened name from ConfigurationFile to ConfigFile
00434 //   + Implemented template member functions
00435 //   + Changed default comment separator from % to #
00436 //   + Enabled reading of multiple-line values
00437 // 
00438 // v2.1  24 May 2004
00439 //   + Made template specializations inline to avoid compiler-dependent linkage
00440 //   + Allowed comments within multiple-line values
00441 //   + Enabled blank line termination for multiple-line values
00442 //   + Added optional sentry to detect end of configuration file
00443 //   + Rewrote messy trimWhitespace() function as elegant trim()
00444 //
00445 // v2.2 04 February 2011
00446 //  + Added Section support
00447 //  + Check for duplicate key in add-Method
00448 //  + Removed KeyNotFoundexception in remove-Method because it is
00449 //    more convenient not to interrupt if key does not exists.
00450 
Generated by  doxygen 1.6.3