From: g0dil Date: Wed, 21 May 2008 21:41:58 +0000 (+0000) Subject: Utils: Document new utilities X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=9e7071473642404359c8b7a88c78fe02f00baf16;p=senf.git Utils: Document new utilities Console: Implement LinkNode git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@851 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Console/Config.cc b/Console/Config.cc index afb365f..3d2200b 100644 --- a/Console/Config.cc +++ b/Console/Config.cc @@ -82,11 +82,8 @@ prefix_ void senf::console::ConfigFile::policyCallback(DirectoryNode::ptr restri { if (dir.hasChild(name)) { GenericNode & item (dir.get(name)); - if (restrict && ! item.isChildOf(*restrict)) { - DirectoryNode * itemdir (dynamic_cast(&item)); - if (! itemdir || ! restrict->isChildOf(*itemdir)) - throw Executor::IgnoreCommandException(); - } + if (restrict && ! item.isChildOf(*restrict) && ! item.isDirectory()) + throw Executor::IgnoreCommandException(); if (parsed(item)) throw Executor::IgnoreCommandException(); } diff --git a/Console/Config.test.cc b/Console/Config.test.cc index 2215cce..df3383b 100644 --- a/Console/Config.test.cc +++ b/Console/Config.test.cc @@ -168,6 +168,40 @@ BOOST_AUTO_UNIT_TEST(configFileSkipGroup) } } +BOOST_AUTO_UNIT_TEST(configRestrictAndLink) +{ + TempFile cfgf ("test.cfg"); + cfgf << "dir1/fun1 10;\n" + << "link1 { dir3 { fun2; } fun1 5; }" + << TempFile::close; + + senf::console::ScopedDirectory<> dir1; + senf::console::root().add("dir1", dir1); + dir1.add("fun1",&fun1); + + senf::console::ScopedDirectory<> dir2; + dir1.add("dir2", dir2); + + dir2.mkdir("dir3").add("fun2", &fun2); + dir2.add("fun1", &fun1); + + senf::console::ScopedDirectory<> dir4; + senf::console::root().add("dir4", dir4); + dir4.link("link1", dir2); + + { + senf::console::ConfigFile cfg (cfgf.name(), dir4); + + var1 = 0; + var2 = false; + SENF_CHECK_NO_THROW( cfg.parse(dir2["dir3"]) ); + BOOST_CHECK_EQUAL( var1, 0 ); + BOOST_CHECK_EQUAL( var2, true ); + + BOOST_CHECK_THROW( cfg.parse(), senf::console::SyntaxErrorException ); + } +} + ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ diff --git a/Console/Executor.cc b/Console/Executor.cc index d40f69d..d5f56fb 100644 --- a/Console/Executor.cc +++ b/Console/Executor.cc @@ -28,7 +28,11 @@ // Custom includes #include +#include +#include #include "../Utils/senfassert.hh" +#include "../Utils/Range.hh" +#include "../Utils/String.hh" //#include "Executor.mpp" #define prefix_ @@ -57,6 +61,18 @@ prefix_ senf::console::DirectoryNode & senf::console::Executor::cwd() return * cwd_.back().lock(); } +prefix_ std::string senf::console::Executor::cwdPath() + const +{ + if (skipping()) + return ""; + return "/" + senf::stringJoin( + senf::make_transform_range( + boost::make_iterator_range(boost::next(cwd_.begin()), cwd_.end()), + boost::bind(&DirectoryNode::name, boost::bind(&DirectoryNode::weak_ptr::lock, _1))), + "/" ); +} + prefix_ void senf::console::Executor::execute(std::ostream & output, ParseCommandInfo const & command) { @@ -122,13 +138,13 @@ prefix_ void senf::console::Executor::execute(std::ostream & output, } } catch (InvalidPathException &) { - output << "invalid path" << std::endl; + throw SyntaxErrorException("invalid path"); } catch (InvalidDirectoryException &) { - output << "invalid directory" << std::endl; + throw SyntaxErrorException("invalid directory"); } catch (InvalidCommandException &) { - output << "invalid command" << std::endl; + throw SyntaxErrorException("invalid command"); } catch (IgnoreCommandException &) {} } diff --git a/Console/Executor.hh b/Console/Executor.hh index f771e3b..882792a 100644 --- a/Console/Executor.hh +++ b/Console/Executor.hh @@ -91,7 +91,8 @@ namespace console { /**< Output will be written to \a output. Same as execute(). */ DirectoryNode & cwd() const; ///< Current working directory - bool skipping() const; + std::string cwdPath() const; ///< Return pathname of current directory + bool skipping() const; ///< \c true, if currently skipping a directory group bool autocd() const; ///< Get current autocd status /**< if autocd is enabled, specifying a directory name as diff --git a/Console/Executor.test.cc b/Console/Executor.test.cc index 0e751f1..36f9dcf 100644 --- a/Console/Executor.test.cc +++ b/Console/Executor.test.cc @@ -62,7 +62,8 @@ BOOST_AUTO_UNIT_TEST(executor) parser.parse("cd dir1", &setCommand); executor(os, commands.back()); BOOST_CHECK_EQUAL( commands.back().builtin(), senf::console::ParseCommandInfo::BuiltinCD ); - BOOST_CHECK( &executor.cwd() == &senf::console::root()["dir1"] ); + BOOST_CHECK( executor.cwd() == senf::console::root()["dir1"] ); + BOOST_CHECK_EQUAL( executor.cwdPath(), "/dir1" ); BOOST_CHECK_EQUAL( os.str(), "" ); } @@ -78,10 +79,10 @@ BOOST_AUTO_UNIT_TEST(executor) { std::stringstream os; parser.parse("cd dir1", &setCommand); - executor(os, commands.back()); + BOOST_CHECK_THROW( executor(os, commands.back()), senf::console::SyntaxErrorException ); BOOST_CHECK_EQUAL( commands.back().builtin(), senf::console::ParseCommandInfo::BuiltinCD ); BOOST_CHECK( &executor.cwd() == &senf::console::root()["dir2"] ); - BOOST_CHECK_EQUAL( os.str(), "invalid directory\n" ); + BOOST_CHECK_EQUAL( os.str(), "" ); } { @@ -112,9 +113,9 @@ BOOST_AUTO_UNIT_TEST(executor) { std::stringstream os; parser.parse("ls dir3", &setCommand); - executor(os, commands.back()); + BOOST_CHECK_THROW( executor(os, commands.back()), senf::console::SyntaxErrorException ); BOOST_CHECK_EQUAL( commands.back().builtin(), senf::console::ParseCommandInfo::BuiltinLS ); - BOOST_CHECK_EQUAL( os.str(), "invalid directory\n" ); + BOOST_CHECK_EQUAL( os.str(), "" ); } { diff --git a/Console/Node.cc b/Console/Node.cc index 3e16667..42086bb 100644 --- a/Console/Node.cc +++ b/Console/Node.cc @@ -89,6 +89,16 @@ prefix_ bool senf::console::GenericNode::isChildOf(DirectoryNode & parent) } /////////////////////////////////////////////////////////////////////////// +// senf::console::LinkNode + +prefix_ void senf::console::LinkNode::v_help(std::ostream & os) + const +{ + os << "link to "; + follow().help(os); +} + +/////////////////////////////////////////////////////////////////////////// //senf::console::DirectoryNode prefix_ senf::console::GenericNode::ptr @@ -127,7 +137,7 @@ prefix_ void senf::console::DirectoryNode::add(GenericNode::ptr node) } prefix_ senf::console::GenericNode & -senf::console::DirectoryNode::get(std::string const & name) +senf::console::DirectoryNode::getLink(std::string const & name) const { ChildMap::const_iterator i (children_.find(name)); diff --git a/Console/Node.cci b/Console/Node.cci index 108902a..242881f 100644 --- a/Console/Node.cci +++ b/Console/Node.cci @@ -96,6 +96,45 @@ prefix_ bool senf::console::GenericNode::operator!=(GenericNode & other) return this != & other; } +prefix_ bool senf::console::GenericNode::isDirectory() + const +{ + return dynamic_cast(this); +} + +prefix_ bool senf::console::GenericNode::isLink() + const +{ + return dynamic_cast(this); +} + +prefix_ bool senf::console::GenericNode::isCommand() + const +{ + return dynamic_cast(this); +} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::LinkNode + +prefix_ senf::console::LinkNode::ptr senf::console::LinkNode::create(GenericNode & node) +{ + GenericNode::ptr p (node.thisptr()); + while ( p->isLink() ) + p = dynamic_cast(*p).follow().thisptr(); + return ptr(new LinkNode(*p)); +} + +prefix_ senf::console::GenericNode & senf::console::LinkNode::follow() + const +{ + return *node_; +} + +prefix_ senf::console::LinkNode::LinkNode(GenericNode & node) + : node_ (node.thisptr()) +{} + /////////////////////////////////////////////////////////////////////////// // senf::console::DirectoryNode @@ -111,6 +150,16 @@ prefix_ bool senf::console::DirectoryNode::hasChild(std::string const & name) return i != children_.end(); } +prefix_ senf::console::GenericNode & +senf::console::DirectoryNode::get(std::string const & name) + const +{ + GenericNode & node (getLink(name)); + return node.isLink() + ? dynamic_cast(node).follow() + : node; +} + prefix_ senf::console::DirectoryNode & senf::console::DirectoryNode::getDirectory(std::string const & name) const @@ -165,6 +214,11 @@ senf::console::DirectoryNode::completions(std::string const & s) children_.lower_bound(s + "\xff")); } +prefix_ void senf::console::DirectoryNode::link(std::string const & name, GenericNode & target) +{ + add(name, LinkNode::create(target)); +} + prefix_ senf::console::DirectoryNode::DirectoryNode() {} diff --git a/Console/Node.hh b/Console/Node.hh index ca57da1..939113b 100644 --- a/Console/Node.hh +++ b/Console/Node.hh @@ -215,6 +215,7 @@ namespace senf { namespace console { + class LinkNode; class DirectoryNode; class CommandNode; @@ -288,6 +289,10 @@ namespace console { bool operator!= (GenericNode & other) const; /// \c true, if this and \a other are different nodes + bool isDirectory() const; ///< \c true, if this is a drectory node + bool isLink() const; ///< \c true, if this is a link node + bool isCommand() const; ///< \c true, if this is a command node + protected: GenericNode(); @@ -310,6 +315,47 @@ namespace console { friend class DirectoryNode; }; + /** \brief Config/console tree link node + + A LinkNode references another node and provides an additional alias name for that node. A + LinkNode works like a mixture of UNIX symlinks and hardlinks: It is an explicit link like a + UNIX symlink but references another node directly (not via it's path) like a UNIX + hardlink. Therefore, a LinkNode works across chroot(). + */ + class LinkNode + : public GenericNode + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + typedef boost::shared_ptr ptr; + typedef boost::shared_ptr cptr; + typedef boost::weak_ptr weak_ptr; + + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + static ptr create(GenericNode & node); ///< Create new link node. + /**< You should normally use DirectoryNode::link() to + create a link node. */ + + ///@} + /////////////////////////////////////////////////////////////////////////// + + GenericNode & follow() const; ///< Access the referenced node + + protected: + + private: + explicit LinkNode(GenericNode & node); + + virtual void v_help(std::ostream &) const; + + GenericNode::ptr node_; + }; + class SimpleCommandNode; /** \brief Internal: Node creation helper traits @@ -445,6 +491,10 @@ namespace console { ///< Get child node /**< \throws UnknownNodeNameException if a child \a name does not exist */ + GenericNode & getLink(std::string const & name) const; + ///< Get child node without dereferencing links + /**< \throws UnknownNodeNameException if a child \a name + does not exist */ DirectoryNode & getDirectory(std::string const & name) const; ///< Get directory child node @@ -488,28 +538,12 @@ namespace console { ///< Return iterator range of completions for \a s /**< The returned range is sorted by child name. */ + void link(std::string const & name, GenericNode & target); + ///\} /////////////////////////////////////////////////////////////////////////// - template - GenericNode & traverse(ForwardRange const & range, bool autocomplete=false, - DirectoryNode & root = root()); - ///< Traverse node path starting at this node - /**< The ForwardRange::value_type must be - (convertible to) std::string. Each range element - constitutes a step along the node traversal. - - If the range starts with an empty element, the - traversal is started at the root() node, otherwise it - is started at \a this node. The traversal supports '.', - '..' and ignores further empty elements. - - If \a autocomplete is set to \c true, invalid path - components which can be uniquely completed will be - completed automatically while traversing the tree. */ - - DirectoryNode & doc(std::string const & doc); - ///< Set node documentation + DirectoryNode & doc(std::string const & doc); ///< Set node documentation ptr thisptr(); cptr thisptr() const; @@ -668,7 +702,7 @@ BOOST_TYPEOF_REGISTER_TYPE(senf::console::SimpleCommandNode) ///////////////////////////////hh.e//////////////////////////////////////// #include "Node.cci" -#include "Node.ct" +//#include "Node.ct" #include "Node.cti" #endif diff --git a/Console/Node.test.cc b/Console/Node.test.cc index 0e0668d..cab82e3 100644 --- a/Console/Node.test.cc +++ b/Console/Node.test.cc @@ -37,7 +37,7 @@ #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// -BOOST_AUTO_UNIT_TEST(gnericNode) +BOOST_AUTO_UNIT_TEST(genericNode) { senf::console::GenericNode & node ( senf::console::root().mkdir("dir1").mkdir("dir2").doc("help info")); @@ -107,19 +107,6 @@ BOOST_AUTO_UNIT_TEST(directoryNode) completions, completions+sizeof(completions)/sizeof(completions[0]) ); - char const * const path[] = { "..", "dir2", "dir3" }; - BOOST_CHECK( &senf::console::root()["dir1"].traverse( boost::make_iterator_range( - path, - path+sizeof(path)/sizeof(path[0])) ) - == &senf::console::root()["dir2"]["dir3"] ); - - char const * const incompletePath[] = { "d" }; - BOOST_CHECK( &senf::console::root()["dir2"].traverse( boost::make_iterator_range( - incompletePath, - incompletePath+sizeof(incompletePath)/sizeof(incompletePath[0])), - true ) - == &senf::console::root()["dir2"]["dir3"] ); - p->doc("test doc"); std::stringstream ss; p->help(ss); @@ -132,6 +119,17 @@ BOOST_AUTO_UNIT_TEST(directoryNode) BOOST_CHECK_EQUAL( senf::console::root().children().size(), 0u ); } +BOOST_AUTO_UNIT_TEST(linkNode) +{ + senf::console::root().mkdir("dir1"); + senf::console::root().link("link1", senf::console::root()["dir1"]); + + BOOST_CHECK( senf::console::root()["dir1"] == senf::console::root()["link1"] ); + + senf::console::root().remove("dir1"); + senf::console::root().remove("link1"); +} + namespace { struct Functor { void operator()(std::ostream & os, senf::console::ParseCommandInfo const &) { diff --git a/Console/ScopedDirectory.cci b/Console/ScopedDirectory.cci index c94e1c0..6f868b7 100644 --- a/Console/ScopedDirectory.cci +++ b/Console/ScopedDirectory.cci @@ -98,6 +98,12 @@ senf::console::ScopedDirectoryBase::mkdir(std::string const & name) return node().mkdir(name); } +prefix_ void senf::console::ScopedDirectoryBase::link(std::string const & name, + GenericNode & target) +{ + return node().link(name, target); +} + prefix_ senf::console::DirectoryNode::ChildrenRange senf::console::ScopedDirectoryBase::children() const diff --git a/Console/ScopedDirectory.hh b/Console/ScopedDirectory.hh index 89da74b..04a33ec 100644 --- a/Console/ScopedDirectory.hh +++ b/Console/ScopedDirectory.hh @@ -83,6 +83,7 @@ namespace console { CommandNode & operator()(std::string const & name) const; GenericNode & get(std::string const & name) const; DirectoryNode & mkdir(std::string const & name); + void link(std::string const & name, GenericNode & node); DirectoryNode::ChildrenRange children() const; DirectoryNode & doc(std::string const & doc); diff --git a/Console/Server.cci b/Console/Server.cci index b684439..78387d6 100644 --- a/Console/Server.cci +++ b/Console/Server.cci @@ -139,7 +139,7 @@ prefix_ std::string const & senf::console::Client::name() prefix_ std::string senf::console::Client::promptString() const { - return name_ + ":" + executor_.cwd().path() + "$ "; + return name_ + ":" + executor_.cwdPath() + "$ "; } prefix_ senf::console::Client & senf::console::Client::get(std::ostream & os) diff --git a/Utils/Backtrace.hh b/Utils/Backtrace.hh index 4861a3b..ccc1d97 100644 --- a/Utils/Backtrace.hh +++ b/Utils/Backtrace.hh @@ -33,8 +33,27 @@ ///////////////////////////////hh.p//////////////////////////////////////// namespace senf { + /** \defgroup backtraces Backtrace formatting and parsing + These functions help format and barse backtrace information as returned by the glibc + ::backtrace function. + */ + + /** \brief Formnat a given backtrace + + This functions will write \a backtrace formatted to \a os. This includes demangling symbol + names and interpreting some additional kernel symbols. + + \ingroup backtraces + */ void formatBacktrace(std::ostream & os, void ** backtrace, unsigned numEntries); + + /** \brief Write a backtrace to \a os + + backtrace() will write a backtrace of the current call stack to \a os. + + \ingroup backtraces + */ void backtrace(std::ostream & os, unsigned numEntries); } diff --git a/Utils/Mainpage.dox b/Utils/Mainpage.dox index cc20df8..3c0c53f 100644 --- a/Utils/Mainpage.dox +++ b/Utils/Mainpage.dox @@ -99,13 +99,27 @@ namespace senf { specification \ref utils_tagsMiscellaneous type tags + + stringJoin()Utility to join a string range into + a single string (with separator) + + make_transform_range()\c boost::make_transform_iterator() with support for + ranges + + \ref backtracesUtilities to parse and format backtrace information as provided + by the GNU libc - \section compatibility Compatibility + + \section testing Correctness and testing + + + +
\ref auto_unit_test.hhBoost auto unit test compatibility across Boost versions 1.33 and 1.34
\ref SENF_ASSERT()SENF specific assertion macro
\ref unittestAdditional unit test extension for Boost.Test
*/ diff --git a/Console/Node.ct b/Utils/Range.cti similarity index 57% copy from Console/Node.ct copy to Utils/Range.cti index c9516c0..0444e42 100644 --- a/Console/Node.ct +++ b/Utils/Range.cti @@ -21,34 +21,27 @@ // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \file - \brief Node non-inline template implementation */ + \brief Range inline template implementation */ -#include "Node.ih" +//#include "Range.ih" // Custom includes -#include -#define prefix_ -///////////////////////////////ct.p//////////////////////////////////////// +#define prefix_ inline +///////////////////////////////cti.p/////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////// -// senf::console::DirectoryNode - -template -prefix_ senf::console::GenericNode & -senf::console::DirectoryNode::traverse(ForwardRange const & range, bool autocomplete, - DirectoryNode & root) +template +prefix_ boost::iterator_range< + boost::transform_iterator< Fn, + typename boost::range_const_iterator::type > > +senf::make_transform_range(Range const & range, Fn const & fn) { - typedef typename boost::range_const_iterator::type const_iterator; - detail::NodeTraverser traverser (root, *this, autocomplete); - const_iterator i (boost::begin(range)); - const_iterator const i_end (boost::end(range)); - for (; i != i_end; ++i) - traverser( *i ); - return traverser.node(); + return boost::make_iterator_range( + boost::make_transform_iterator(boost::begin(range), fn), + boost::make_transform_iterator(boost::end(range), fn) ); } -///////////////////////////////ct.e//////////////////////////////////////// +///////////////////////////////cti.e/////////////////////////////////////// #undef prefix_ diff --git a/Console/Node.ct b/Utils/Range.hh similarity index 57% rename from Console/Node.ct rename to Utils/Range.hh index c9516c0..db6d63e 100644 --- a/Console/Node.ct +++ b/Utils/Range.hh @@ -21,35 +21,38 @@ // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \file - \brief Node non-inline template implementation */ + \brief Range public header */ -#include "Node.ih" +#ifndef HH_Range_ +#define HH_Range_ 1 // Custom includes -#include - -#define prefix_ -///////////////////////////////ct.p//////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////// -// senf::console::DirectoryNode - -template -prefix_ senf::console::GenericNode & -senf::console::DirectoryNode::traverse(ForwardRange const & range, bool autocomplete, - DirectoryNode & root) -{ - typedef typename boost::range_const_iterator::type const_iterator; - detail::NodeTraverser traverser (root, *this, autocomplete); - const_iterator i (boost::begin(range)); - const_iterator const i_end (boost::end(range)); - for (; i != i_end; ++i) - traverser( *i ); - return traverser.node(); +#include +#include + +//#include "Range.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { + + /** \brief Make a \c boost::iterator_range from \c boost::trasform_iterator + + This helper is like \c boost::make_transform_iterator, however for ranges instead of + iterators. + */ + template + boost::iterator_range< + boost::transform_iterator< Fn, + typename boost::range_const_iterator::type > > + make_transform_range(Range const & range, Fn const & fn); + } -///////////////////////////////ct.e//////////////////////////////////////// -#undef prefix_ +///////////////////////////////hh.e//////////////////////////////////////// +//#include "Range.cci" +//#include "Range.ct" +#include "Range.cti" +#endif // Local Variables: diff --git a/Utils/String.hh b/Utils/String.hh index 0b8028f..1bdf93e 100644 --- a/Utils/String.hh +++ b/Utils/String.hh @@ -34,6 +34,11 @@ namespace senf { + /** \brief Join string range with separator into single string + + This utility will build string by joining all elements of \a range into a single string + using \a sep as separator. The \a range may contain values of any streamable type. + */ template std::string stringJoin(ForwardReadableRange const & range, std::string sep); diff --git a/Utils/auto_unit_test.hh b/Utils/auto_unit_test.hh index a126692..b2e60ae 100644 --- a/Utils/auto_unit_test.hh +++ b/Utils/auto_unit_test.hh @@ -50,8 +50,44 @@ #include +/** \defgroup unittest Boost.Test extensions + + This module defines some additional extensions to Boost.Test + */ + +/** \brief Check for compile failure + + COMPILE_RAIL() is used to check, that a certain piece of code will produce a compile time + failure. + + \code + #ifdef COMPILE_CHECK + + COMPILE_FAIL(foo) + { + // fails to compile .... + int x = "foo"; + } + + COMPILE_FAIL(bar) + { ... } + + #endif + \endcode + + This check is performed by the extended unit-test builder in \c senfscons. + + \ingroup unittest + */ #define COMPILE_FAIL(n) void n() +/** \brief Show exception information + + \ref SENF_CHECK_NO_THROW() is an extension to \c BOOST_CHECK_NO_THROW() which will write out the + unabridged exception information when an exception is thrown in addition to signaling an error. + + \ingroup unittest + */ #define SENF_CHECK_NO_THROW(expr) \ BOOST_CHECK_NO_THROW( \ try { (void) expr ; } \ diff --git a/Utils/preprocessor.hh b/Utils/preprocessor.hh index 55a3fa8..0567d78 100644 --- a/Utils/preprocessor.hh +++ b/Utils/preprocessor.hh @@ -34,7 +34,7 @@ //#include "preprocessor.mpp" ///////////////////////////////hh.p//////////////////////////////////////// -/** \defgroup senfpp Preprocessor meta programming macros +/** \defgroup senfpp Preprocessor meta programming preprocessor.hh provides some additional helper macros based on the Boost.Preprocessor library. */