///////////////////////////////////////////////////////////////////////////
// senf::console::ConfigFile
-prefix_ void senf::console::ConfigFile::parse()
+#ifndef DOXYGEN
+
+namespace {
+ struct BindPolicy
+ {
+ BindPolicy(senf::console::Executor & e, senf::console::Executor::SecurityPolicy p)
+ : e_ (e)
+ { e_.policy(p); }
+
+ ~BindPolicy()
+ { e_.policy(senf::console::Executor::SecurityPolicy()); }
+
+ senf::console::Executor & e_;
+ };
+}
+
+#endif
+
+prefix_ void senf::console::ConfigFile::parse(DirectoryNode & restrict)
{
+ DirectoryNode::ptr r (restrict.thisptr());
+ BindPolicy bp ( executor_,
+ boost::bind(&ConfigFile::policyCallback, this, r, _1, _2) );
if (! parser_.parseFile(filename_, boost::bind<void>( boost::ref(executor_),
boost::ref(std::cerr),
_1 )) )
throw SyntaxErrorException();
+ insertParsedNode(r);
}
-prefix_ void senf::console::ConfigFile::parse(DirectoryNode & restrict)
+prefix_ bool senf::console::ConfigFile::parsed(GenericNode & node)
+ const
+{
+ ParsedNodes::const_iterator i (parsedNodes_.begin());
+ ParsedNodes::const_iterator const i_end (parsedNodes_.end());
+ for (; i != i_end; ++i)
+ if ( ! i->expired() && node.isChildOf(*(i->lock())) )
+ return true;
+ return false;
+}
+
+prefix_ void senf::console::ConfigFile::policyCallback(DirectoryNode::ptr restrict,
+ DirectoryNode & dir,
+ std::string const & name)
+{
+ if (dir.hasChild(name)) {
+ GenericNode & item (dir.get(name));
+ if (restrict && ! item.isChildOf(*restrict)) {
+ DirectoryNode * itemdir (dynamic_cast<DirectoryNode*>(&item));
+ if (! itemdir || ! restrict->isChildOf(*itemdir))
+ throw Executor::IgnoreCommandException();
+ }
+ if (parsed(item))
+ throw Executor::IgnoreCommandException();
+ }
+ else if (restrict && ! dir.isChildOf(*restrict))
+ throw Executor::IgnoreCommandException();
+}
+
+namespace {
+ struct RemoveNodesFn
+ {
+ RemoveNodesFn(senf::console::DirectoryNode::ptr newNode) : newNode_ (newNode) {}
+
+ bool operator()(senf::console::DirectoryNode::weak_ptr node) const
+ { return node.expired() || node.lock()->isChildOf(*newNode_); }
+
+ senf::console::DirectoryNode::ptr newNode_;
+ };
+}
+
+prefix_ void senf::console::ConfigFile::insertParsedNode(DirectoryNode::ptr node)
{
- restrict_ = restrict.thisptr();
- parse();
- parsedNodes_.push_back(restrict_);
- restrict_.reset();
+ parsedNodes_.erase(
+ std::remove_if(parsedNodes_.begin(), parsedNodes_.end(), RemoveNodesFn(node)),
+ parsedNodes_.end());
+ parsedNodes_.push_back(node);
}
///////////////////////////////////////////////////////////////////////////
-prefix_ void senf::console::readConfig(std::string const & filename)
+prefix_ void senf::console::readConfig(std::string const & filename, DirectoryNode & root)
{
- ConfigFile cfg (filename);
+ ConfigFile cfg (filename, root);
cfg.parse();
}
///////////////////////////////////////////////////////////////////////////
// senf::console::ConfigFile
-prefix_ senf::console::ConfigFile::ConfigFile(std::string const & filename)
+prefix_ senf::console::ConfigFile::ConfigFile(std::string const & filename,
+ DirectoryNode & root)
: filename_ (filename)
{
- executor_.policy(senf::membind(&ConfigFile::policyCallback, this));
+ executor_.chroot(root);
}
-prefix_ void senf::console::ConfigFile::policyCallback(DirectoryNode & dir,
- std::string const & name)
+prefix_ void senf::console::ConfigFile::parse()
{
- if (dir.hasChild(name)) {
- GenericNode & item (dir.get(name));
- if (restrict_ && ! item.isChildOf(*restrict_)) {
- DirectoryNode * itemdir (dynamic_cast<DirectoryNode*>(&item));
- if (! itemdir || ! restrict_->isChildOf(*itemdir))
- throw Executor::IgnoreCommandException();
- }
- ParsedNodes::const_iterator i (parsedNodes_.begin());
- ParsedNodes::const_iterator const i_end (parsedNodes_.end());
- for (; i != i_end; ++i) {
- if ( ! i->expired() && item.isChildOf(*(i->lock())) )
- throw Executor::IgnoreCommandException();
- }
- }
- else {
- if (restrict_ && ! dir.isChildOf(*restrict_))
- throw Executor::IgnoreCommandException();
- }
+ parse(executor_.chroot());
+}
+
+prefix_ bool senf::console::ConfigFile::complete()
+ const
+{
+ return parsedNodes_.size() == 1
+ && ! parsedNodes_[0].expired()
+ && *parsedNodes_[0].lock() == executor_.chroot();
+}
+
+prefix_ void senf::console::ConfigFile::reset()
+{
+ parsedNodes_.clear();
}
///////////////////////////////cci.e///////////////////////////////////////
namespace senf {
namespace console {
- /** \brief
+ /** \brief Console node tree based config file parser
+
+ A ConfigFile instance allows flexible parsing of a config file against the console node
+ tree. If you just want to parse a file completely, the senf::console::readConfig() function
+ will do that. ConfigFile however allows to incrementally parse only a subdirectory of the
+ complete configuration file.
+ \code
+ senf::console::ConfigFile cf ("/my/config/file")
+
+ // Parse only statements under the directory of some object. The object 'ob'
+ // must have been registered somewhere in the node tree
+ cf.parse(ob.dir);
+
+ // Parse rest of the config file
+ cf.parse();
+ \endcode
*/
class ConfigFile
: boost::noncopyable
///\name Structors and default members
///@{
- explicit ConfigFile(std::string const & filename);
+ explicit ConfigFile(std::string const & filename, DirectoryNode & root = root());
+ ///< Create ConfigFile object for \a filename
+ /**< The \a filename configuration file will be parsed using
+ parse() calls. All configuration statements will be
+ interpreted relative to \a root as root node. */
///@}
///////////////////////////////////////////////////////////////////////////
- void parse();
- void parse(DirectoryNode & restrict);
+ void parse(); ///< Parse config file
+ /**< All nodes already parsed are skipped */
+ void parse(DirectoryNode & restrict); ///< Parse config file under \a restrict
+ /**< Only nodes which are children of \a restrict are
+ parsed. */
+
+ bool complete() const; ///< \c true, if all nodes have been parsed
+ bool parsed(GenericNode & node) const; ///< \c true. if \a node has been parsed
+
+ void reset(); ///< Reset node parse info state
+ /**< After a call to reset(), all information about already
+ parsed nodes is cleared. Calling parse() will parse the
+ complete config file again. */
protected:
private:
- void policyCallback(DirectoryNode & dir, std::string const & item);
+ void policyCallback(DirectoryNode::ptr restrict, DirectoryNode & dir,
+ std::string const & item);
+
+ void insertParsedNode(DirectoryNode::ptr node);
typedef std::vector<DirectoryNode::weak_ptr> ParsedNodes;
CommandParser parser_;
Executor executor_;
- DirectoryNode::ptr restrict_;
ParsedNodes parsedNodes_;
};
- void readConfig(std::string const & filename);
+ /** \brief Read configuration file
+
+ The configuration file \a filename will be loaded, interpreting all node's relative to \a
+ root as root node.
+
+ This function uses a local ConfigFile object to perform the parsing.
+
+ \related ConfigFile
+ */
+ void readConfig(std::string const & filename, DirectoryNode & root = root());
}}
dir1.add("fun1",&fun1);
{
- var1 = 0;
senf::console::ConfigFile cfg (cfgf.name());
+
+ var1 = 0;
+ SENF_CHECK_NO_THROW( cfg.parse() )
+ BOOST_CHECK_EQUAL( var1, 10 );
+
+ var1 = 0;
+ SENF_CHECK_NO_THROW( cfg.parse() )
+ BOOST_CHECK_EQUAL( var1, 0 );
+
+ var1 = 0;
+ cfg.reset();
SENF_CHECK_NO_THROW( cfg.parse() )
BOOST_CHECK_EQUAL( var1, 10 );
}
var1 = 0;
var2 = false;
senf::console::ConfigFile cfg (cfgf.name());
- SENF_CHECK_NO_THROW( cfg.parse(dir1.node()) );
+ SENF_CHECK_NO_THROW( cfg.parse(dir1) );
BOOST_CHECK_EQUAL( var1, 10 );
BOOST_CHECK_EQUAL( var2, false );
+ BOOST_CHECK( cfg.parsed(dir1) );
+ BOOST_CHECK( ! cfg.complete() );
senf::console::ScopedDirectory<> dir2;
senf::console::root().add("dir2", dir2);
SENF_CHECK_NO_THROW( cfg.parse() );
BOOST_CHECK_EQUAL( var1, 0 );
BOOST_CHECK_EQUAL( var2, true );
+ BOOST_CHECK( cfg.complete() );
}
}
var1 = 0;
var2 = false;
senf::console::ConfigFile cfg (cfgf.name());
- SENF_CHECK_NO_THROW( cfg.parse(dir1.node()) );
+ SENF_CHECK_NO_THROW( cfg.parse(dir1) );
BOOST_CHECK_EQUAL( var1, 10 );
BOOST_CHECK_EQUAL( var2, false );
+ BOOST_CHECK( cfg.parsed(dir1) );
var1 = 0;
var2 = false;
SENF_CHECK_NO_THROW( cfg.parse(dir2["dir3"]) );
BOOST_CHECK_EQUAL( var1, 0 );
BOOST_CHECK_EQUAL( var2, true );
+ BOOST_CHECK( ! cfg.parsed(dir2) );
var1 = 0;
var2 = false;
are accessible via the executor. This value defaults to
senf::console::root(). */
- Executor & policy(SecurityPolicy policy); ///< Set security policy
+ Executor & policy(SecurityPolicy policy = SecurityPolicy()); ///< Set security policy
/**< The security policy is called before traversing a node
to validate that access. */
return *node_;
}
+prefix_ senf::console::ScopedDirectoryBase::operator DirectoryNode &()
+ const
+{
+ return node();
+}
+
prefix_ senf::console::GenericNode::ptr
senf::console::ScopedDirectoryBase::remove(std::string const & name)
{
{
public:
DirectoryNode & node() const; ///< Access the proxied DirectoryNode
+ operator DirectoryNode & () const; ///< Access the proxied DirectoryNode
///////////////////////////////////////////////////////////////////////////
///\name Proxied members (see DirectoryNode)
env.Append(
CPPPATH = [ '#/include' ],
- LIBS = [ 'readline', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB' ],
+ LIBS = [ 'readline', 'rt', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB' ],
TEST_EXTRA_LIBS = [ '$BOOSTFSLIB' ],
DOXY_XREF_TYPES = [ 'bug', 'fixme', 'todo', 'idea' ],
DOXY_HTML_XSL = '#/doclib/html-munge.xsl',
# c) check for a local SENF, set options accordingly and update that SENF if needed
def SetupForSENF(env):
- env.Append( LIBS = [ 'senf', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB' ],
+ env.Append( LIBS = [ 'senf', 'readline', 'rt', '$BOOSTREGEXLIB', '$BOOSTIOSTREAMSLIB' ],
BOOSTREGEXLIB = 'boost_regex',
BOOSTIOSTREAMSLIB = 'boost_iostreams',
CXXFLAGS = [ '-Wno-long-long',