Skip to content
Snippets Groups Projects
Commit aeb3e7e9 authored by g0dil's avatar g0dil
Browse files

Add 'rt' library to build (needed at least by gentoo)

Console: Restructure ConfigFile::parse and add chroot support
Console: Some ConfigFile documentation
parent b23c3f17
No related branches found
No related tags found
No related merge requests found
......@@ -35,27 +35,90 @@
///////////////////////////////////////////////////////////////////////////
// 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();
}
......
......@@ -34,33 +34,29 @@
///////////////////////////////////////////////////////////////////////////
// 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///////////////////////////////////////
......
......@@ -37,7 +37,22 @@
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
......@@ -47,18 +62,36 @@ namespace console {
///\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;
......@@ -66,11 +99,19 @@ namespace console {
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());
}}
......
......@@ -76,8 +76,18 @@ BOOST_AUTO_UNIT_TEST(configFile)
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 );
}
......@@ -98,9 +108,11 @@ BOOST_AUTO_UNIT_TEST(configFileRestrict)
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);
......@@ -111,6 +123,7 @@ BOOST_AUTO_UNIT_TEST(configFileRestrict)
SENF_CHECK_NO_THROW( cfg.parse() );
BOOST_CHECK_EQUAL( var1, 0 );
BOOST_CHECK_EQUAL( var2, true );
BOOST_CHECK( cfg.complete() );
}
}
......@@ -135,15 +148,17 @@ BOOST_AUTO_UNIT_TEST(configFileSkipGroup)
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;
......
......@@ -120,7 +120,7 @@ namespace console {
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. */
......
......@@ -39,6 +39,12 @@ prefix_ senf::console::DirectoryNode & senf::console::ScopedDirectoryBase::node(
return *node_;
}
prefix_ senf::console::ScopedDirectoryBase::operator DirectoryNode &()
const
{
return node();
}
prefix_ senf::console::GenericNode::ptr
senf::console::ScopedDirectoryBase::remove(std::string const & name)
{
......
......@@ -69,6 +69,7 @@ namespace console {
{
public:
DirectoryNode & node() const; ///< Access the proxied DirectoryNode
operator DirectoryNode & () const; ///< Access the proxied DirectoryNode
///////////////////////////////////////////////////////////////////////////
///\name Proxied members (see DirectoryNode)
......
......@@ -142,7 +142,7 @@ def configFilesOpts(target, source, env, for_signature):
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',
......
......@@ -8,7 +8,7 @@ from SCons.Script import *
# 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',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment