I tried splitting up the sources to speed up some compiling... but it didn't help. I dunno that it's more readable this way. I'm checkpointing this just in case.
85 lines
1.9 KiB
C++
85 lines
1.9 KiB
C++
#include "ConfigFile.h"
|
|
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
|
|
namespace Config::Hydrogen ::detail:: ConfigFile_m
|
|
{
|
|
namespace
|
|
{
|
|
struct EoF {};
|
|
|
|
std::string
|
|
readLine( std::istream &input )
|
|
{
|
|
std::string rv;
|
|
std::getline( input, rv );
|
|
if( not input ) throw EoF{};
|
|
|
|
// SStrip trailing '#' comments...
|
|
const auto endComment= std::find( begin( rv ), end( rv ), '#' );
|
|
rv.erase( endComment, end( rv ) );
|
|
return rv;
|
|
}
|
|
|
|
std::string
|
|
trimWhitespace( std::string s )
|
|
{
|
|
// Trim from the front
|
|
std::reverse( begin( s ), end( s ) );
|
|
while( not s.empty() and s.back() == ' ' ) s.pop_back();
|
|
|
|
// Trim from the back
|
|
std::reverse( begin( s ), end( s ) );
|
|
while( not s.empty() and s.back() == ' ' ) s.pop_back();
|
|
|
|
return s;
|
|
}
|
|
|
|
auto
|
|
parseLine( const std::string &line )
|
|
{
|
|
const auto split= std::find( begin( line ), end( line ), '=' );
|
|
if( split == end( line ) ) throw std::runtime_error{ "Unable to parse configuration line: `" + line + "`" };
|
|
const auto key= trimWhitespace( { begin( line ), split } );
|
|
const auto value= trimWhitespace( { split + 1, end( line ) } );
|
|
|
|
return std::tuple{ key, value };
|
|
}
|
|
}
|
|
|
|
ConfigFile::ConfigFile( std::istream &&input, const std::map< std::string, std::string > &schema )
|
|
: config( schema )
|
|
{
|
|
while( input )
|
|
try
|
|
{
|
|
const std::string line= trimWhitespace( readLine( input ) );
|
|
if( line.empty() ) continue; // Skip blank lines.
|
|
|
|
const auto [ key, value ]= parseLine( line );
|
|
|
|
if( not schema.contains( key ) )
|
|
{
|
|
std::cerr << "Unrecognized key in config file: `" << key << "`" << std::endl;
|
|
continue;
|
|
}
|
|
|
|
config.at( key )= value;
|
|
}
|
|
catch( const EoF & ) { break; }
|
|
|
|
std::cerr << "Configuration parsed:" << std::endl;
|
|
for( const auto &[ key, value ]: config )
|
|
{
|
|
std::cerr << key << " = " << value << std::endl;
|
|
}
|
|
}
|
|
|
|
std::string
|
|
ConfigFile::get( const std::string &name ) const
|
|
{
|
|
return config.at( name );
|
|
}
|
|
}
|