// properties.h #if !defined(basic_properties___H) #define basic_properties___H #include <map> #include "properties_base.h" #include <fstream> #include <stdexcept> #include <sstream> namespace Private { // reads a string from stream: // the string starts with double-quote (") and ends with double-quote // // escapes: double-quote is escaped like this (\") // backslash is escaped like this (\\) template< class char_type, class char_traits> void read_str_from_stream( std::basic_istream< char_type, char_traits> & in, std::basic_string< char_type, char_traits> & strDest) { // ignore spaces char_type ch = 0; while ( in.get( ch)) if ( !isspace( ch)) { in.putback( ch); break; } in >> ch; if ( ch != '"') { // error: string did not start with '"' in.setstate( std::ios_base::failbit); return; } // clear old string, and insert chars into it strDest.erase(); while ( in.get( ch)) { if ( ch == '"') // end of string found return; else if ( ch == '\\') { // see if it's an escaped quote char_type chNext = 0; in.get( chNext); if ( ( chNext != '"') && ( chNext != '\\') ) strDest += ch; strDest += chNext; } else strDest += ch; } // did not encounter ending '"' in.setstate( std::ios_base::failbit); } }; // default error policy for properties // (throw if a line is bad) template< class char_type> struct throw_on_bad_line { typedef std::basic_string< char_type> string_type; void on_bad_line( const string_type & strFileName, const string_type & strLine) { throw std::runtime_error( "invalid props file: " + strFileName); } }; // error policy for properties // (log error somewhere template< class char_type> struct logerror_on_bad_line { typedef std::basic_string< char_type> string_type; logerror_on_bad_line() : m_pLog( NULL) {} void set_log( std::basic_ostream< char_type> & log) { m_pLog = &log; } void on_bad_line( const string_type & strFileName, const string_type & strLine) { if ( m_pLog) *m_pLog << "invalid props file: " << strFileName << "(line=" << strLine << ")"; } private: std::basic_ostream< char_type> *m_pLog; }; /* contains application properties: that are constant throughout the application */ template< class char_type, class error_policy = throw_on_bad_line< char_type> > class basic_properties : public basic_properties_base< char_type>, protected error_policy { typedef std::basic_string< char_type> string_type; public: basic_properties( const std::string & strFileName) : m_strFileName( strFileName) { std::basic_ifstream< char_type> in( strFileName.c_str()); while ( in.good()) { string_type strLine; std::getline( in, strLine); // ... ignore empty lines if ( strLine.empty()) continue; std::basic_stringstream< char> line( strLine); char_type ch = 0; line.get( ch); if ( ch == '#') // comment continue; line.putback( ch); string_type strName; string_type strValue; Private::read_str_from_stream( line, strName); Private::read_str_from_stream( line, strValue); if ( !line.good()) on_bad_line( strFileName, strLine); m_collProps[ strName] = strValue; } } ~basic_properties() {} void internal_get( const string_type & strName, string_type & val) const { std::map< std::string, std::string>::const_iterator found = m_collProps.find( strName); if ( found != m_collProps.end()) val = found->second; else throw std::runtime_error( "property not found " + strName); } private: // the file to read the properties from std::string m_strFileName; // property name (key) -> property value (value) std::map< string_type, string_type> m_collProps; }; typedef basic_properties< char> properties; typedef basic_properties< wchar_t> wproperties; #endif |