host/config/svconfig.cpp (542 lines of code) (raw):

#include <fstream> #include <string> #include <map> #include <new> #include <cctype> #include <utility> #include <sstream> #include <assert.h> #include "svtypes.h" #include "svconfig.h" #include "inmsafecapis.h" using namespace std; SVConfig* SVConfig::pInstance = 0; struct LineParser { enum ParseError { CONFIG_PARSE_OK, CONFIG_PARSE_INVALID_NAME, CONFIG_MISSING_VALUE, CONFIG_PARSE_INVALID_QUOTING, CONFIG_PARSE_INVALID_SECTION_NAME, CONFIG_PARSE_INVALID_SYNTAX }; LineParser( string line ); bool iskeychar( char ch ) const; ParseError rc; SVConfig::ParsedLine result; typedef void (LineParser::*State)( char ch ); State s; void whitespace1( char ch ); void name( char ch ); void whitespace2( char ch ); void whitespace3( char ch ); void value( char ch ); void whitespace4( char ch ); void quote( char ch ); void quote2( char ch ); void whitespace5( char ch ); void whitespace6( char ch ); void section( char ch ); void whitespace7( char ch ); void comment( char ch ); void invalid( char ch ); }; // // Convert a string to lowercase. // static void lowercase(string& s) { for (size_t i = 0, sz = s.size(); i < sz; i++) s[i] = tolower(s[i]); } SVConfig* SVConfig::GetInstance() { static SVConfig instance; if( NULL == pInstance ) { pInstance = &instance; } return pInstance; } SVConfig::SVConfig() { } SVConfig::~SVConfig() { Clear(); } SVERROR SVConfig::Parse(string const& configFile) { configFilePath = configFile; ifstream file(configFilePath.c_str()); if(!file) return SVE_FILE_NOT_FOUND; return ParseStream( file ); } SVERROR SVConfig::ParseStream( istream& o ) { SVERROR rc; Clear(); string curSection; string line; while (getline(o,line)) { LineParser parser( line ); if( LineParser::CONFIG_PARSE_OK != parser.rc ) { return( SVE_INVALID_FORMAT ); } else { if( parser.result.name != "" ) { rc = SetValue( curSection, parser.result.name, parser.result.value ); if( rc.failed() ) { return( rc ); } } else if( parser.result.sectionName != "" ) { string sectionName = parser.result.sectionName; curSection = CreateSection( sectionName ); } } } return( rc ); } SVERROR SVConfig::ParseString(std::string const& configStr) { stringstream stream( configStr ); return( ParseStream( stream ) ); } bool LineParser::iskeychar( char ch ) const { return( isalnum( ch ) || '_' == ch ); } LineParser::LineParser( std::string line ) { rc = CONFIG_PARSE_OK; result.quoteChar = 0; s = &LineParser::whitespace1; for( string::const_iterator i=line.begin(); i != line.end(); ++i ) { char ch = *i; (this->*s)( ch ); } // // If we're not in a terminal state, return an error // if( &LineParser::name == s || &LineParser::whitespace2 == s ) { rc = CONFIG_MISSING_VALUE; } else if( &LineParser::quote == s || &LineParser::quote2 == s ) { rc = CONFIG_PARSE_INVALID_QUOTING; } else if( &LineParser::whitespace6 == s || &LineParser::section == s || &LineParser::whitespace7 == s ) { rc = CONFIG_PARSE_INVALID_SYNTAX; } if( CONFIG_PARSE_OK == rc ) { assert( &LineParser::invalid != s ); } } // // Whitespace before name or section bracket // void LineParser::whitespace1( char ch ) { if( isspace( ch ) ) { result.spaceLeadingName += ch; } else if( '[' == ch ) { s = &LineParser::whitespace6; } else if( iskeychar( ch ) ) { result.name += ch; s = &LineParser::name; } else if( '#' == ch ) { s = &LineParser::comment; } else { rc = CONFIG_PARSE_INVALID_NAME; s = &LineParser::invalid; } } // // Whitespace after name, before equals // void LineParser::whitespace2( char ch ) { if( isspace( ch ) ) { result.spaceTrailingName += ch; } else if( '=' == ch ) { s = &LineParser::whitespace3; } else { rc = CONFIG_PARSE_INVALID_NAME; s = &LineParser::invalid; } } // // Whitespace after '=', before start of value // void LineParser::whitespace3( char ch ) { if( isspace( ch ) ) { result.spaceLeadingValue += ch; } else if( '"' == ch || '\'' == ch ) { result.quoteChar = ch; s = &LineParser::quote; } else { result.value += ch; s = &LineParser::value; } } // // Whitespace in value, before optional comment // void LineParser::whitespace4( char ch ) { if( isspace( ch ) ) { result.spaceTrailingValue += ch; } else if( '#' == ch ) { s = &LineParser::comment; } else { result.value += result.spaceTrailingValue; result.value += ch; s = &LineParser::value; } } // // Whitespace after end of quoted value // void LineParser::whitespace5( char ch ) { if( isspace( ch ) ) { result.spaceTrailingValue += ch; } else if( '#' == ch ) { s = &LineParser::comment; } else { rc = CONFIG_PARSE_INVALID_SYNTAX; s = &LineParser::invalid; } } // // Whitespace after '[' for section // void LineParser::whitespace6( char ch ) { if( isspace( ch ) ) { result.spaceLeadingValue += ch; } else if( iskeychar( ch ) ) { result.sectionName += ch; s = &LineParser::section; } else { rc = CONFIG_PARSE_INVALID_SECTION_NAME; s = &LineParser::invalid; } } // // Whitespace after section name, before ']' // void LineParser::whitespace7( char ch ) { if( isspace( ch ) ) { result.spaceTrailingName += ch; } else if( ']' == ch ) { s = &LineParser::whitespace5; } else { rc = CONFIG_PARSE_INVALID_SECTION_NAME; s = &LineParser::invalid; } } // // Get `name' // void LineParser::name( char ch ) { if( iskeychar( ch ) ) { result.name += ch; } else if( isspace( ch ) ) { s = &LineParser::whitespace2; } else if( '=' == ch ) { s = &LineParser::whitespace3; } else { rc = CONFIG_PARSE_INVALID_NAME; s = &LineParser::invalid; } } // // Get unquoted value // void LineParser::value( char ch ) { if( isspace( ch ) ) { result.spaceTrailingValue += ch; s = &LineParser::whitespace4; } else { result.value += ch; } } // // Get quoted string // void LineParser::quote( char ch ) { if( ch == result.quoteChar ) { s = &LineParser::whitespace5; } else if( '\\' == ch ) { s = &LineParser::quote2; } else { result.value += ch; } } // // Handle backslash escape characters // void LineParser::quote2( char ch ) { if( 't' == ch ) { result.value += '\t'; } else if( 'r' == ch ) { result.value += '\r'; } else if( 'n' == ch ) { result.value += '\n'; } else { result.value += ch; } s = &LineParser::quote; } // // Get section name // void LineParser::section( char ch ) { if( iskeychar( ch ) || '.' == ch ) { result.sectionName += ch; } else if( ']' == ch ) { s = &LineParser::whitespace5; } else if( isspace( ch ) ) { result.spaceTrailingName += ch; s = &LineParser::whitespace7; } else { rc = CONFIG_PARSE_INVALID_SECTION_NAME; s = &LineParser::invalid; } } // // Get comment // void LineParser::comment( char ch ) { result.comment += ch; } // // Invalid state just discards characters // void LineParser::invalid( char ch ) { } SVERROR SVConfig::GetValue(string const& entry, string& value) const { map<string,string>::const_iterator ci = config.find(entry); if (ci == config.end()) return SVE_FAIL; value = ci->second; return SVS_OK; } SVERROR SVConfig::UpdateConfigParameter(string const& key, string const& value) { config[key] = value; return SVS_OK; } SVERROR SVConfig::Write() { ofstream file(configFilePath.c_str()); if (!file) return SVE_FAIL; map<string,string>::const_iterator ci; string key; for (ci=config.begin(); ci != config.end(); ++ci) { key = ci->first; file << key << " = " << ci->second << '\n'; } file.flush(); file.close(); return SVS_OK; } int SVConfig::GetTotalNumberOfKeys() { return (int) config.size(); } SVERROR SVConfig::WriteKeyValuePairToFile(string const& key, string const& value) { ofstream svstream; svstream.open(configFilePath.c_str(),ios::out | ios::app ); svstream << '\n' << key << " = " << value; svstream.flush(); svstream.close(); return SVS_OK; } SVERROR SVConfig::GetConfigFileName(string& name) const { name = configFilePath; return SVS_OK; } void SVConfig::SetConfigFileName(const char* fileName) { configFilePath = fileName; } void SVConfig::Clear() { config.clear(); m_arraycount.clear(); m_isSection.clear(); m_lines.clear(); } void SVConfig::RenameSectionIntoArrayEntry( string oldSectionName ) { vector< pair<string,string> > updates; for( map<string,string>::iterator i = config.begin(); i != config.end(); ++i ) { string key = i->first; if( key.substr( 0, oldSectionName.length()+1 ) == oldSectionName + "." ) { string value = config[ key ]; updates.push_back( make_pair( key, value ) ); } } for( vector< pair<string,string> >::iterator j = updates.begin(); j != updates.end(); ++j ) { string key = j->first; config.erase( key ); key.replace( 0, oldSectionName.length(), oldSectionName + "[0]" ); config[ key ] = j->second; } } string SVConfig::CreateSection( std::string const& sectionName ) { string curSection; map<string,string>::const_iterator entry = config.find( sectionName ); if( config.end() == entry ) { map<string,int>::const_iterator arrayEntry = m_arraycount.find( sectionName ); if( m_arraycount.end() == arrayEntry ) { map<string,bool>::const_iterator sectionEntry = m_isSection.find( sectionName ); if( m_isSection.end() == sectionEntry ) { // // Key did not exist; create section // curSection = sectionName; //CreateSection( curSection ); m_isSection[ sectionName ] = true; // // Dotted section names necessarily imply their parent sections // string::size_type pos = 0; while( true ) { pos = sectionName.find_first_of( '.', pos ); if( string::npos == pos ) { break; } m_isSection[ sectionName.substr( 0, pos ) ] = true; pos ++; } } else { // // Rename existing section // m_isSection.erase( sectionName ); // delete old section name m_isSection[ sectionName+"[0]" ] = true; // add section name[0] RenameSectionIntoArrayEntry( sectionName ); // rename all old section variables to section[0] curSection = sectionName + "[1]"; //config[ curSection ] = parser.result.value; // set array value for name[1] m_arraycount[ sectionName ] = 2; // add array for name } } else { // // Add section to existing array // int arrayCount = arrayEntry->second; char szNumber[ 16 ]; inm_sprintf_s(szNumber, ARRAYSIZE(szNumber), "[%d]", arrayCount); curSection = sectionName + szNumber; m_isSection[ curSection ] = true; m_arraycount[ sectionName ] = arrayCount + 1; } } else { // // Rename existing value into array element // string value0 = entry->second; config.erase( sectionName ); config[ sectionName + "[0]" ] = value0; m_arraycount[ sectionName ] = 2; } return( curSection ); } SVERROR SVConfig::SetValue( std::string const& sectionName, std::string const& name, std::string const& value ) { SVERROR rc; string keyName = (sectionName == "") ? name : sectionName + "." + name; map<string,string>::const_iterator entry = config.find( keyName ); if( config.end() == entry ) { map<string,int>::const_iterator arrayEntry = m_arraycount.find( keyName ); if( m_arraycount.end() == arrayEntry ) { map<string,bool>::const_iterator sectionEntry = m_isSection.find( keyName ); if( m_isSection.end() == sectionEntry ) { // // Key did not exist; create simple name=value // config[ keyName ] = value; } else { // // Rename old section variables to section[ 0 ] // m_isSection.erase( keyName ); // delete old section name m_isSection[ keyName+"[0]" ] = true; // add section name[0] RenameSectionIntoArrayEntry( keyName ); // rename all old section variables to section[0] config[ keyName+"[1]" ] = value; // set array value for name[1] m_arraycount[ keyName ] = 2; // add array for name } } else { // // Key is an array; append to the existing array // int arrayCount = arrayEntry->second; char szNumber[ 16 ]; inm_sprintf_s(szNumber, ARRAYSIZE(szNumber), "[%d]", arrayCount); config[ keyName + szNumber ] = value; m_arraycount[ keyName ] = arrayCount + 1; } } else { // // Duplicate instance of keyName -> keyName is an array // string value0 = entry->second; config.erase( keyName ); config[ keyName + "[0]" ] = value0; config[ keyName + "[1]" ] = value; m_arraycount[ keyName ] = 2; } return( rc ); } int SVConfig::GetArraySize( std::string const& name ) { map<string,int>::const_iterator arrayEntry = m_arraycount.find( name ); return( m_arraycount.end() == arrayEntry ) ? 0 : arrayEntry->second; }