From 379e842080a5027d5f5fc7274b4f30b1c0d24e5e Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sat, 6 Sep 2014 14:55:05 -0700 Subject: [PATCH] Add BasicConfig simplified config interface --- src/ripple/module/core/Config.cpp | 106 ++++++++++++++++++++++++++++-- src/ripple/module/core/Config.h | 90 +++++++++++++++++++++++-- 2 files changed, 183 insertions(+), 13 deletions(-) diff --git a/src/ripple/module/core/Config.cpp b/src/ripple/module/core/Config.cpp index a13a564c80..76aadefd6a 100644 --- a/src/ripple/module/core/Config.cpp +++ b/src/ripple/module/core/Config.cpp @@ -20,6 +20,7 @@ #include #include #include +#include namespace ripple { @@ -205,6 +206,101 @@ parseAddresses (OutputSequence& out, InputIterator first, InputIterator last, } } +//------------------------------------------------------------------------------ +// +// Section +// +//------------------------------------------------------------------------------ + +void +Section::append (std::vector const& lines) +{ + // '=' + static boost::regex const re1 ( + "^" // start of line + "(?:\\s*)" // whitespace (optonal) + "([a-zA-Z][_a-zA-Z0-9]*)" // + "(?:\\s*)" // whitespace (optional) + "(?:=)" // '=' + "(?:\\s*)" // whitespace (optional) + "(.*\\S+)" // + "(?:\\s*)" // whitespace (optional) + , boost::regex_constants::optimize + ); + + lines_.reserve (lines_.size() + lines.size()); + for (auto const& line : lines) + { + boost::smatch match; + lines_.push_back (line); + if (boost::regex_match (line, match, re1)) + { + auto const result = map_.emplace ( + std::make_pair (match[1], match[2])); +#if 0 + if (! result.second) + { + // If we decide on how to merge values we can do it here. + } + beast::debug_ostream log; + //log << "\"" << match[1] << "\" = \"" << match[2] << "\""; +#endif + } + } +} + +bool +Section::exists (std::string const& name) const +{ + return map_.find (name) != map_.end(); +} + +std::pair +Section::find (std::string const& name) const +{ + auto const iter = map_.find (name); + if (iter == map_.end()) + return {{}, false}; + return {iter->second, true}; +} + +//------------------------------------------------------------------------------ +// +// BasicConfig +// +//------------------------------------------------------------------------------ + +bool +BasicConfig::exists (std::string const& name) const +{ + return map_.find (name) != map_.end(); +} + +Section const& +BasicConfig::section (std::string const& name) const +{ + static Section none; + auto const iter = map_.find (name); + if (iter == map_.end()) + return none; + return iter->second; +} + +void +BasicConfig::build (IniFileSections const& ifs) +{ + for (auto const& entry : ifs) + { + auto const result = map_.insert (std::make_pair ( + entry.first, Section{})); + result.first->second.append (entry.second); + } +} + +//------------------------------------------------------------------------------ +// +// Config (DEPRECATED) +// //------------------------------------------------------------------------------ Config::Config () @@ -322,7 +418,7 @@ void Config::setup (std::string const& strConf, bool bQuiet) CONFIG_FILE = CONFIG_DIR / strConfFile; DATA_DIR = CONFIG_DIR / strDbPath; - if (exists (CONFIG_FILE) + if (boost::filesystem::exists (CONFIG_FILE) // Can we figure out XDG dirs? || (!getenv ("HOME") && (!getenv ("XDG_CONFIG_HOME") || !getenv ("XDG_DATA_HOME")))) { @@ -392,6 +488,7 @@ void Config::load () } else { + std::string file_contents; file_contents.assign ((std::istreambuf_iterator (ifsConfig)), std::istreambuf_iterator ()); @@ -404,6 +501,8 @@ void Config::load () IniFileSections secConfig = parseIniFile (file_contents, true); std::string strTemp; + build (secConfig); + // XXX Leak IniFileSections::mapped_type* smtTmp; @@ -926,14 +1025,9 @@ Config::Role Config::getAdminRole (Json::Value const& params, beast::IP::Endpoin return role; } -//------------------------------------------------------------------------------ beast::File const& Config::getModuleDatabasePath () { return m_moduleDbPath; } -// -// -//------------------------------------------------------------------------------ - } // ripple diff --git a/src/ripple/module/core/Config.h b/src/ripple/module/core/Config.h index bef0c0bbce..9912976c01 100644 --- a/src/ripple/module/core/Config.h +++ b/src/ripple/module/core/Config.h @@ -25,10 +25,13 @@ #include #include #include +#include #include +#include #include #include #include +#include #include namespace ripple { @@ -59,24 +62,97 @@ parseKeyValueSection (IniFileSections& secSource, //------------------------------------------------------------------------------ +/** Holds a collection of configuration values. + A configuration file contains zero or more sections. +*/ +class Section +{ +private: + std::vector lines_; + std::map map_; + +public: + /** Create an empty section. */ + Section() = default; + + /** Append a set of lines to this section. + Parsable key/value pairs are also added to the map. + */ + void + append (std::vector const& lines); + + /** Returns `true` if a key with the given name exists. */ + bool + exists (std::string const& name) const; + + /** Retrieve a key/value pair. + @return A pair with bool `true` if the string was found. + */ + std::pair + find (std::string const& name) const; +}; + +//------------------------------------------------------------------------------ + /** Holds unparsed configuration information. The raw data sections are processed with intermediate parsers specific to each module instead of being all parsed in a central location. */ class BasicConfig { -public: - /** The entire, unprocessed content of the config file. - Normally clients should not need to look at this. - */ - std::string file_contents; +private: + std::map map_; - /** Preprocessed contents of each section. */ - //std::map +T +get (Section const& section, + std::string const& name, T const& defaultValue = T{}) +{ + auto const result = section.find (name); + if (! result.second) + return defaultValue; + try + { + return boost::lexical_cast (result.first); + } + catch(...) + { + } + return defaultValue; +} + +//------------------------------------------------------------------------------ + // VFALCO TODO Replace these with beast "unsigned long long" generators // VFALCO NOTE Apparently these are used elsewhere. Make them constants in the config // or in the Application