#include "ConfigFile.h" #include #include 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 ); } }