IBR-DTNSuite  0.8
ibrcommon/ibrcommon/data/ConfigFile.cpp
Go to the documentation of this file.
00001 // ConfigFile.cpp
00002 
00003 #include "ibrcommon/config.h"
00004 #include "ibrcommon/data/ConfigFile.h"
00005 
00006 namespace ibrcommon
00007 {
00008         ConfigFile::ConfigFile( string filename, string delimiter,
00009                                                         string comment, string sentry )
00010                 : myDelimiter(delimiter), myComment(comment), mySentry(sentry)
00011         {
00012                 // Construct a ConfigFile, getting keys and values from given file
00013 
00014                 std::ifstream in( filename.c_str() );
00015 
00016                 if( !in ) throw file_not_found( filename );
00017 
00018                 in >> (*this);
00019         }
00020 
00021 
00022         ConfigFile::ConfigFile()
00023                 : myDelimiter( string(1,'=') ), myComment( string(1,'#') )
00024         {
00025                 // Construct a ConfigFile without a file; empty
00026         }
00027 
00028 
00029         void ConfigFile::remove( const string& key )
00030         {
00031                 // Remove key and its value
00032                 myContents.erase( myContents.find( key ) );
00033                 return;
00034         }
00035 
00036 
00037         bool ConfigFile::keyExists( const string& key ) const
00038         {
00039                 // Indicate whether key is found
00040                 mapci p = myContents.find( key );
00041                 return ( p != myContents.end() );
00042         }
00043 
00044 
00045         /* static */
00046         void ConfigFile::trim( string& s )
00047         {
00048                 // Remove leading and trailing whitespace
00049                 static const char whitespace[] = " \n\t\v\r\f";
00050                 s.erase( 0, s.find_first_not_of(whitespace) );
00051                 s.erase( s.find_last_not_of(whitespace) + 1U );
00052         }
00053 
00054 
00055         std::ostream& operator<<( std::ostream& os, const ConfigFile& cf )
00056         {
00057                 // Save a ConfigFile to os
00058                 for( ConfigFile::mapci p = cf.myContents.begin();
00059                          p != cf.myContents.end();
00060                          ++p )
00061                 {
00062                         os << p->first << " " << cf.myDelimiter << " ";
00063                         os << p->second << std::endl;
00064                 }
00065                 return os;
00066         }
00067 
00068 
00069         std::istream& operator>>( std::istream& is, ConfigFile& cf )
00070         {
00071                 // Load a ConfigFile from is
00072                 // Read in keys and values, keeping internal whitespace
00073                 typedef string::size_type pos;
00074                 const string& delim  = cf.myDelimiter;  // separator
00075                 const string& comm   = cf.myComment;    // comment
00076                 const string& sentry = cf.mySentry;     // end of file sentry
00077                 const pos skip = delim.length();        // length of separator
00078 
00079                 string nextline = "";  // might need to read ahead to see where value ends
00080 
00081                 while( is || nextline.length() > 0 )
00082                 {
00083                         // Read an entire line at a time
00084                         string line;
00085                         if( nextline.length() > 0 )
00086                         {
00087                                 line = nextline;  // we read ahead; use it now
00088                                 nextline = "";
00089                         }
00090                         else
00091                         {
00092                                 std::getline( is, line );
00093                         }
00094 
00095                         // Ignore comments
00096                         line = line.substr( 0, line.find(comm) );
00097 
00098                         // Check for end of file sentry
00099                         if( sentry != "" && line.find(sentry) != string::npos ) return is;
00100 
00101                         // Parse the line if it contains a delimiter
00102                         pos delimPos = line.find( delim );
00103                         if( delimPos < string::npos )
00104                         {
00105                                 // Extract the key
00106                                 string key = line.substr( 0, delimPos );
00107                                 line.replace( 0, delimPos+skip, "" );
00108 
00109                                 // See if value continues on the next line
00110                                 // Stop at blank line, next line with a key, end of stream,
00111                                 // or end of file sentry
00112                                 bool terminate = false;
00113                                 while( !terminate && is )
00114                                 {
00115                                         std::getline( is, nextline );
00116                                         terminate = true;
00117 
00118                                         string nlcopy = nextline;
00119                                         ConfigFile::trim(nlcopy);
00120                                         if( nlcopy == "" ) continue;
00121 
00122                                         nextline = nextline.substr( 0, nextline.find(comm) );
00123                                         if( nextline.find(delim) != string::npos )
00124                                                 continue;
00125                                         if( sentry != "" && nextline.find(sentry) != string::npos )
00126                                                 continue;
00127 
00128                                         nlcopy = nextline;
00129                                         ConfigFile::trim(nlcopy);
00130                                         if( nlcopy != "" ) line += "\n";
00131                                         line += nextline;
00132                                         terminate = false;
00133                                 }
00134 
00135                                 // Store key and value
00136                                 ConfigFile::trim(key);
00137                                 ConfigFile::trim(line);
00138                                 cf.myContents[key] = line;  // overwrites if key is repeated
00139                         }
00140                 }
00141 
00142                 return is;
00143         }
00144 }