// ConfigFile.cpp | |
#include "ConfigFile.h" | |
using std::string; | |
ConfigFile::ConfigFile( string filename, string delimiter, | |
string comment, string sentry ) | |
: myDelimiter(delimiter), myComment(comment), mySentry(sentry) | |
{ | |
// Construct a ConfigFile, getting keys and values from given file | |
std::ifstream in( filename.c_str() ); | |
if( !in ) throw file_not_found( filename ); | |
in >> (*this); | |
} | |
ConfigFile::ConfigFile() | |
: myDelimiter( string(1,'=') ), myComment( string(1,'#') ) | |
{ | |
// Construct a ConfigFile without a file; empty | |
} | |
void ConfigFile::remove( const string& key ) | |
{ | |
// Remove key and its value | |
myContents.erase( myContents.find( key ) ); | |
return; | |
} | |
bool ConfigFile::keyExists( const string& key ) const | |
{ | |
// Indicate whether key is found | |
mapci p = myContents.find( key ); | |
return ( p != myContents.end() ); | |
} | |
/* static */ | |
void ConfigFile::trim( string& s ) | |
{ | |
// Remove leading and trailing whitespace | |
static const char whitespace[] = " \n\t\v\r\f"; | |
s.erase( 0, s.find_first_not_of(whitespace) ); | |
s.erase( s.find_last_not_of(whitespace) + 1U ); | |
} | |
std::ostream& operator<<( std::ostream& os, const ConfigFile& cf ) | |
{ | |
// Save a ConfigFile to os | |
for( ConfigFile::mapci p = cf.myContents.begin(); | |
p != cf.myContents.end(); | |
++p ) | |
{ | |
os << p->first << " " << cf.myDelimiter << " "; | |
os << p->second << std::endl; | |
} | |
return os; | |
} | |
std::istream& operator>>( std::istream& is, ConfigFile& cf ) | |
{ | |
// Load a ConfigFile from is | |
// Read in keys and values, keeping internal whitespace | |
typedef string::size_type pos; | |
const string& delim = cf.myDelimiter; // separator | |
const string& comm = cf.myComment; // comment | |
const string& sentry = cf.mySentry; // end of file sentry | |
const pos skip = delim.length(); // length of separator | |
string nextline = ""; // might need to read ahead to see where value ends | |
while( is || nextline.length() > 0 ) | |
{ | |
// Read an entire line at a time | |
string line; | |
if( nextline.length() > 0 ) | |
{ | |
line = nextline; // we read ahead; use it now | |
nextline = ""; | |
} | |
else | |
{ | |
std::getline( is, line ); | |
} | |
// Ignore comments | |
line = line.substr( 0, line.find(comm) ); | |
// Check for end of file sentry | |
if( sentry != "" && line.find(sentry) != string::npos ) return is; | |
// Parse the line if it contains a delimiter | |
pos delimPos = line.find( delim ); | |
if( delimPos < string::npos ) | |
{ | |
// Extract the key | |
string key = line.substr( 0, delimPos ); | |
line.replace( 0, delimPos+skip, "" ); | |
// See if value continues on the next line | |
// Stop at blank line, next line with a key, end of stream, | |
// or end of file sentry | |
bool terminate = false; | |
while( !terminate && is ) | |
{ | |
std::getline( is, nextline ); | |
terminate = true; | |
string nlcopy = nextline; | |
ConfigFile::trim(nlcopy); | |
if( nlcopy == "" ) continue; | |
nextline = nextline.substr( 0, nextline.find(comm) ); | |
if( nextline.find(delim) != string::npos ) | |
continue; | |
if( sentry != "" && nextline.find(sentry) != string::npos ) | |
continue; | |
nlcopy = nextline; | |
ConfigFile::trim(nlcopy); | |
if( nlcopy != "" ) line += "\n"; | |
line += nextline; | |
terminate = false; | |
} | |
// Store key and value | |
ConfigFile::trim(key); | |
ConfigFile::trim(line); | |
cf.myContents[key] = line; // overwrites if key is repeated | |
} | |
} | |
return is; | |
} |