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


youbot_driver
Author(s): Jan Paulus
autogenerated on Mon Oct 6 2014 09:08:01