blob: c10662dccd09e5472fcbd18e6baa45ac4af88594 [file] [log] [blame]
// 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;
}