157 lines
3.0 KiB
C++
157 lines
3.0 KiB
C++
|
|
#include "IniFile.h"
|
|
|
|
//
|
|
// TrimChars
|
|
//
|
|
// trim whitespace, or any, chars from both ends
|
|
//
|
|
template <typename S>
|
|
std::string TrimChars( const std::string& str, const S space )
|
|
{
|
|
const size_t start = str.find_first_not_of( space );
|
|
|
|
if ( str.npos == start )
|
|
return "";
|
|
|
|
return str.substr( start, str.find_last_not_of( space ) - start + 1 );
|
|
}
|
|
|
|
//
|
|
// IniSection :: Set
|
|
//
|
|
// set key's value if it doesn't match the default
|
|
// otherwise remove the key from the section if it exists
|
|
//
|
|
void IniSection::Set( const std::string& key, const std::string& val, const std::string& def )
|
|
{
|
|
if ( val != def )
|
|
operator[](key) = val;
|
|
else
|
|
{
|
|
iterator f = find(key);
|
|
if ( f != end() )
|
|
erase( f );
|
|
}
|
|
}
|
|
|
|
//
|
|
// IniSection :: Get
|
|
//
|
|
// return a key's value if it exists
|
|
// otherwise return the default
|
|
//
|
|
std::string IniSection::Get( const std::string& key, const std::string& def )
|
|
{
|
|
const const_iterator f = find(key);
|
|
if ( f != end() )
|
|
if ( false == f->second.empty() )
|
|
return f->second;
|
|
return def;
|
|
}
|
|
|
|
//
|
|
// IniFile :: Save
|
|
//
|
|
// save a file
|
|
//
|
|
void IniFile::Save( std::ostream& file )
|
|
{
|
|
const_iterator i = begin(),
|
|
e = end();
|
|
for ( ; i != e; ++i )
|
|
{
|
|
// skip a line at new sections
|
|
file << "\n[" << i->first << "]\n";
|
|
Section::const_iterator si = i->second.begin(),
|
|
se = i->second.end();
|
|
for ( ; si != se; ++si )
|
|
{
|
|
file << si->first << " = ";
|
|
// if value has quotes or whitespace, surround it with quotes
|
|
if (si->second.find_first_of("\"\t ") != std::string::npos)
|
|
file << '"' << si->second << '"';
|
|
else
|
|
file << si->second;
|
|
file << '\n';
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// IniFile :: Load
|
|
//
|
|
// load a file
|
|
//
|
|
void IniFile::Load( std::istream& file )
|
|
{
|
|
const char* const space = "\t\r ";
|
|
std::string line;
|
|
// start off with an empty section
|
|
Section* section = &(*this)[""];
|
|
while ( std::getline( file, line ).good() ) // read a line
|
|
{
|
|
line = TrimChars(line,space);
|
|
if ( line.size() )
|
|
{
|
|
switch ( line[0] )
|
|
{
|
|
// comment
|
|
case '#' :
|
|
case ';' :
|
|
break;
|
|
// section
|
|
case '[' :
|
|
// kinda odd trimming
|
|
section = &(*this)[ TrimChars(line,"][\t\r ") ];
|
|
break;
|
|
// key/value
|
|
default :
|
|
{
|
|
std::istringstream ss(line);
|
|
std::string key; std::getline( ss, key, '=' );
|
|
std::string val; std::getline( ss, val );
|
|
val = TrimChars(val,space);
|
|
// handle quote surrounded values
|
|
if (val.length() > 1)
|
|
if ('"' == val[0])
|
|
val = val.substr(1, val.length()-2);
|
|
|
|
(*section)[ TrimChars(key,space) ] = val;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// IniFile :: Clean
|
|
//
|
|
// remove empty key/values and sections
|
|
// after trying to access ini sections/values, they are automatically allocated
|
|
// this deletes the empty stuff
|
|
//
|
|
void IniFile::Clean()
|
|
{
|
|
iterator i = begin(),
|
|
e = end();
|
|
for ( ; i != e; )
|
|
{
|
|
Section::iterator si = i->second.begin(),
|
|
se = i->second.end();
|
|
for ( ; si != se; )
|
|
{
|
|
if ( si->second.empty() )
|
|
i->second.erase( si++ );
|
|
else
|
|
++si;
|
|
}
|
|
if ( i->second.empty() )
|
|
erase( i++ );
|
|
else
|
|
++i;
|
|
}
|
|
}
|