diff --git a/Console/Node.cc b/Console/Node.cc index 5e1e42786e51370b34db4a9a730d41dfc98305ba..1cd8d40bf7d71bb9ec7fc88a29413dff187035f9 100644 --- a/Console/Node.cc +++ b/Console/Node.cc @@ -116,6 +116,15 @@ prefix_ void senf::console::DirectoryNode::v_help(std::ostream & output) output << doc_ << "\n"; } +/////////////////////////////////////////////////////////////////////////// +// senf::console::SyntaxErrorException + +prefix_ char const * senf::console::SyntaxErrorException::what() + const throw() +{ + return message().empty() ? "syntax error" : message().c_str(); +} + /////////////////////////////////////////////////////////////////////////// // senf::console::SimpleCommandNode @@ -125,6 +134,13 @@ prefix_ void senf::console::SimpleCommandNode::v_help(std::ostream & output) output << doc_ << "\n"; } +prefix_ void senf::console::SimpleCommandNode::v_execute(std::ostream & output, + Arguments const & arguments) + const +{ + fn_(output, arguments); +} + ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ //#include "Node.mpp" diff --git a/Console/Node.cci b/Console/Node.cci index 43954f3b761abfbe353b8f2cc1fa648c436139bd..5f824bd69d30a0c970857696dd46531e1e38ca56 100644 --- a/Console/Node.cci +++ b/Console/Node.cci @@ -139,6 +139,13 @@ prefix_ senf::console::DirectoryNode::cptr senf::console::DirectoryNode::thisptr return boost::static_pointer_cast<DirectoryNode const>(shared_from_this()); } +/////////////////////////////////////////////////////////////////////////// +// senf::console::SyntaxErrorException + +prefix_ senf::console::SyntaxErrorException::SyntaxErrorException(std::string const & msg) + : Exception(msg) +{} + /////////////////////////////////////////////////////////////////////////// // senf::console::CommandNode @@ -156,15 +163,16 @@ prefix_ senf::console::CommandNode::cptr senf::console::CommandNode::thisptr() prefix_ senf::console::CommandNode::CommandNode() {} -/////////////////////////////////////////////////////////////////////////// -// senf::console::SimpleCommandNode - -prefix_ void senf::console::SimpleCommandNode::operator()(std::ostream & output, - Arguments const & arguments) +prefix_ void senf::console::CommandNode::operator()(std::ostream & output, + Arguments const & arguments) + const { - fn_(output, arguments); + v_execute(output, arguments); } +/////////////////////////////////////////////////////////////////////////// +// senf::console::SimpleCommandNode + prefix_ senf::console::SimpleCommandNode::SimpleCommandNode(Function const & fn) : fn_ (fn) {} @@ -182,6 +190,17 @@ senf::console::SimpleCommandNode::doc(std::string const & doc) return *this; } +prefix_ senf::console::SimpleCommandNode::ptr senf::console::SimpleCommandNode::thisptr() +{ + return boost::static_pointer_cast<SimpleCommandNode>(shared_from_this()); +} + +prefix_ senf::console::SimpleCommandNode::cptr senf::console::SimpleCommandNode::thisptr() + const +{ + return boost::static_pointer_cast<SimpleCommandNode const>(shared_from_this()); +} + ///////////////////////////////cci.e/////////////////////////////////////// #undef prefix_ diff --git a/Console/Node.hh b/Console/Node.hh index 0bed22b224f33fd47747bf919897b4ce480aeaf3..961a1b8bc38867a7a14fae0cf1bb14a6f5c030d9 100644 --- a/Console/Node.hh +++ b/Console/Node.hh @@ -49,7 +49,7 @@ public: // Declare a directory node (proxy) for use by this class. This must be public so we can add // it to the node tree later. - senf::console::ObjectDirectory<SomeClass> dir; + senf::console::ScopedDirectory<SomeClass> dir; SomeClass() : dir(this) { @@ -178,11 +178,11 @@ Most objects will register several commands. So it makes sense for these objects to manage their own directory. Since directories are however allocated on the heap, they cannot be directly - added to a class. To facilitate this usage, the senf::console::ObjectDirectory is used. This + added to a class. To facilitate this usage, the senf::console::ScopedDirectory is used. This class provides a senf::console::DirectoryNode facade. Internally, it automatically creates a senf::console::DirectoryNode to which all calls are forwarded. - The senf::console::ObjectDirectory member should be declared public. This allows the user of the + The senf::console::ScopedDirectory member should be declared public. This allows the user of the class to add the node to the tree. */ @@ -324,8 +324,8 @@ namespace console { mkdir() or add(). Special add() members however allow externally allocated node objects. Nodes may be added to the tree only once, otherwise chaos will ensue. Since nodes are always - managed dynamically, there is a special ObjectDirectory proxy template which provides a - DirectoryNode facade. ObjectDirectory is used if a class wants to manage it's own directory + managed dynamically, there is a special ScopedDirectory proxy template which provides a + DirectoryNode facade. ScopedDirectory is used if a class wants to manage it's own directory as a data member. Every node is assigned a (new) name when it is added to a directory. If the directory @@ -357,7 +357,7 @@ namespace console { static ptr create(); ///< Create node object. /**< You should normally use either mkdir() or - ObjectDirectory instead of create() */ + ScopedDirectory instead of create() */ ///\} /////////////////////////////////////////////////////////////////////////// @@ -479,6 +479,13 @@ namespace console { {}; #endif + struct SyntaxErrorException : public senf::Exception + { + explicit SyntaxErrorException(std::string const & msg = ""); + + virtual char const * what() const throw(); + }; + /** \brief Config/console tree command node The CommandNode is the base-class for the tree leaf nodes. Concrete command node @@ -504,8 +511,8 @@ namespace console { /////////////////////////////////////////////////////////////////////////// - virtual void operator()(std::ostream & output, Arguments const & arguments) = 0; - ///< Called to execute the command + void operator()(std::ostream & output, Arguments const & arguments) const; + ///< Execute the command /**< \param[in] output stream where result messages may be written to \param[in] arguments command arguments. This is a @@ -517,6 +524,16 @@ namespace console { protected: CommandNode(); +#ifndef DOXYGEN + private: +#endif + virtual void v_execute(std::ostream & output, Arguments const & arguments) const = 0; + ///< Called to execute the command + /**< \param[in] output stream where result messages may be + written to + \param[in] arguments command arguments. This is a + range of ranges of ArgumentToken instances. */ + private: }; @@ -551,8 +568,6 @@ namespace console { ///\} /////////////////////////////////////////////////////////////////////////// - virtual void operator()(std::ostream & output, Arguments const & arguments); - ptr thisptr(); cptr thisptr() const; @@ -563,6 +578,8 @@ namespace console { private: virtual void v_help(std::ostream & output) const; + virtual void v_execute(std::ostream & output, Arguments const & arguments) const; + Function fn_; std::string doc_; diff --git a/Console/OverloadedCommand.cc b/Console/OverloadedCommand.cc new file mode 100644 index 0000000000000000000000000000000000000000..30e7fbb3b0bd772fb7c6aeebb3d08d320234d474 --- /dev/null +++ b/Console/OverloadedCommand.cc @@ -0,0 +1,98 @@ +// $Id$ +// +// Copyright (C) 2008 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund <g0dil@berlios.de> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief OverloadedCommand non-inline non-template implementation */ + +#include "OverloadedCommand.hh" +//#include "OverloadedCommand.ih" + +// Custom includes + +//#include "OverloadedCommand.mpp" +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::console::OverloadedCommandNode + +prefix_ void senf::console::OverloadedCommandNode::v_help(std::ostream & os) + const +{ + os << doc_; + Overloads::const_iterator i (overloads_.begin()); + Overloads::const_iterator const i_end (overloads_.end()); + for (; i != i_end; ++i) { + os << "\n\n"; + (*i)->help(os); + } +} + +prefix_ void senf::console::OverloadedCommandNode::v_execute(std::ostream & output, + Arguments const & arguments) + const +{ + Overloads::const_iterator i (overloads_.begin()); + Overloads::const_iterator const i_end (overloads_.end()); + SyntaxErrorException err; + for (; i != i_end; ++i) { + try { + (**i)(output, arguments); + return; + } + catch (SyntaxErrorException & ex) { + err = ex; + }; + } + throw err; +} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::SimpleCommandOverload + +prefix_ void senf::console::SimpleCommandOverload::v_help(std::ostream & os) + const +{ + os << doc_; +} + +prefix_ void senf::console::SimpleCommandOverload::v_execute(std::ostream & os, + Arguments const & arguments) + const +{ + fn_(os, arguments); +} + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ +//#include "OverloadedCommand.mpp" + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Console/OverloadedCommand.cci b/Console/OverloadedCommand.cci new file mode 100644 index 0000000000000000000000000000000000000000..21add3bb7c5ad72a6482ce2bb76a29bf48a413fa --- /dev/null +++ b/Console/OverloadedCommand.cci @@ -0,0 +1,126 @@ +// $Id$ +// +// Copyright (C) 2008 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund <g0dil@berlios.de> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief OverloadedCommand inline non-template implementation */ + +//#include "OverloadedCommand.ih" + +// Custom includes + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::console::CommandOverload + +prefix_ senf::console::CommandOverload::~CommandOverload() +{} + +prefix_ void senf::console::CommandOverload::operator()(std::ostream & os, + Arguments const & arguments) +{ + v_execute(os, arguments); +} + +prefix_ void senf::console::CommandOverload::help(std::ostream & os) +{ + v_help(os); +} + +prefix_ senf::console::OverloadedCommandNode & senf::console::CommandOverload::node() +{ + SENF_ASSERT( node_ ); + return *node_; +} + +prefix_ senf::console::CommandOverload::CommandOverload() + : node_(0) +{} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::OverloadedCommandNode + +prefix_ senf::console::OverloadedCommandNode::ptr senf::console::OverloadedCommandNode::create() +{ + return ptr(new OverloadedCommandNode()); +} + +prefix_ void senf::console::OverloadedCommandNode::add(CommandOverload::ptr overload) +{ + overloads_.push_back(overload); +} + +prefix_ senf::console::OverloadedCommandNode::ptr senf::console::OverloadedCommandNode::thisptr() +{ + return boost::static_pointer_cast<OverloadedCommandNode>(shared_from_this()); +} + +prefix_ senf::console::OverloadedCommandNode::cptr senf::console::OverloadedCommandNode::thisptr() + const +{ + return boost::static_pointer_cast<OverloadedCommandNode const>(shared_from_this()); +} + +prefix_ senf::console::OverloadedCommandNode & +senf::console::OverloadedCommandNode::doc(std::string const & doc) +{ + doc_ = doc; + return *this; +} + +prefix_ senf::console::OverloadedCommandNode::OverloadedCommandNode() +{} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::SimpleCommandOverload + +prefix_ senf::console::SimpleCommandOverload::ptr +senf::console::SimpleCommandOverload::create(Function fn) +{ + return ptr(new SimpleCommandOverload(fn)); +} + +prefix_ senf::console::SimpleCommandOverload & +senf::console::SimpleCommandOverload::doc(std::string const & doc) +{ + doc_ = doc; + return *this; +} + +prefix_ senf::console::SimpleCommandOverload::SimpleCommandOverload(Function fn) + : fn_ (fn) +{} + +///////////////////////////////cci.e/////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Console/OverloadedCommand.hh b/Console/OverloadedCommand.hh new file mode 100644 index 0000000000000000000000000000000000000000..a255eb588ed16239caa5c55f607d43efb0eadedd --- /dev/null +++ b/Console/OverloadedCommand.hh @@ -0,0 +1,182 @@ +// $Id$ +// +// Copyright (C) 2008 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund <g0dil@berlios.de> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief OverloadedCommand public header */ + +#ifndef HH_OverloadedCommand_ +#define HH_OverloadedCommand_ 1 + +// Custom includes +#include "Node.hh" +#include <boost/intrusive_ptr.hpp> +#include "../Utils/intrusive_refcount.hh" + +//#include "OverloadedCommand.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { +namespace console { + + class OverloadedCommandNode; + + /** \brief + */ + class CommandOverload + : public senf::intrusive_refcount + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + typedef boost::intrusive_ptr<CommandOverload> ptr; + typedef CommandNode::Arguments Arguments; + + /////////////////////////////////////////////////////////////////////////// + + virtual ~CommandOverload(); + + void operator()(std::ostream & os, Arguments const & arguments); + void help(std::ostream & os); + + OverloadedCommandNode & node(); + + protected: + CommandOverload(); + +#ifndef DOXYGEN + private: +#endif + virtual void v_help(std::ostream & os) const = 0; + virtual void v_execute(std::ostream & os, Arguments const & arguments) const = 0; + + private: + OverloadedCommandNode * node_; + + friend class OverloadedCommandNode; + }; + + /** \brief Command node which allows multiple registered callbacks + + OverloadedCommand is like SimpleCommand but allows to register multiple commands to a single + node. This works by calling each command in the list consecutively until no 'SyntaxError' + exception is thrown. + + \warning For this to work, the commands <b>must</b> do all syntax checking before doing any + operation + + \ingroup node_tree + */ + class OverloadedCommandNode + : public CommandNode + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + typedef boost::shared_ptr<OverloadedCommandNode> ptr; + typedef boost::shared_ptr<OverloadedCommandNode const> cptr; + typedef boost::weak_ptr<OverloadedCommandNode> weak_ptr; + + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + static ptr create(); + + ///@} + /////////////////////////////////////////////////////////////////////////// + + void add(CommandOverload::ptr overload); + + ptr thisptr(); + cptr thisptr() const; + + OverloadedCommandNode & doc(std::string const & doc); + + protected: + + private: + OverloadedCommandNode(); + + virtual void v_help(std::ostream & output) const; + virtual void v_execute(std::ostream & output, Arguments const & arguments) const; + + typedef std::vector<CommandOverload::ptr> Overloads; + + Overloads overloads_; + std::string doc_; + }; + + /** \brief + */ + class SimpleCommandOverload + : public CommandOverload + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + typedef boost::intrusive_ptr<SimpleCommandOverload> ptr; + typedef boost::function<void (std::ostream &, Arguments const &)> Function; + + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + static SimpleCommandOverload::ptr create(Function fn); + + ///@} + /////////////////////////////////////////////////////////////////////////// + + SimpleCommandOverload & doc(std::string const & doc); + + protected: + + private: + SimpleCommandOverload(Function fn); + + virtual void v_help(std::ostream & os) const; + virtual void v_execute(std::ostream & os, Arguments const & arguments) const; + + Function fn_; + std::string doc_; + }; + +}} + +///////////////////////////////hh.e//////////////////////////////////////// +#include "OverloadedCommand.cci" +//#include "OverloadedCommand.ct" +//#include "OverloadedCommand.cti" +#endif + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Console/ObjectDirectory.test.cc b/Console/OverloadedCommand.test.cc similarity index 52% rename from Console/ObjectDirectory.test.cc rename to Console/OverloadedCommand.test.cc index a8e99af897cec2f0f7c9d121f4e4b2f28175a372..287920176471e009c008443cfa2df2f2b163c4c6 100644 --- a/Console/ObjectDirectory.test.cc +++ b/Console/OverloadedCommand.test.cc @@ -21,14 +21,14 @@ // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \file - \brief ObjectDirectory.test unit tests */ + \brief OverloadedCommand.test unit tests */ -//#include "ObjectDirectory.test.hh" -//#include "ObjectDirectory.test.ih" +//#include "OverloadedCommand.test.hh" +//#include "OverloadedCommand.test.ih" // Custom includes #include <sstream> -#include "ObjectDirectory.hh" +#include "OverloadedCommand.hh" #include <boost/test/auto_unit_test.hpp> #include <boost/test/test_tools.hpp> @@ -37,31 +37,41 @@ ///////////////////////////////cc.p//////////////////////////////////////// namespace { - struct TestObject { - typedef TestObject Self; - - senf::console::ObjectDirectory<Self> dir; - TestObject() : dir(this) { - dir.add("member", &Self::member); - } - - void member(std::ostream & os, senf::console::CommandNode::Arguments const &) { - os << "member"; - } - }; -} -BOOST_AUTO_UNIT_TEST(objectDirectory) -{ + void fn1(std::ostream &, senf::console::CommandOverload::Arguments const &) + { + throw senf::console::SyntaxErrorException("fn1 error"); + } + + void fn2(std::ostream &, senf::console::CommandOverload::Arguments const &) + { + throw senf::console::SyntaxErrorException("fn2 error"); + } + + void fn3(std::ostream & os, senf::console::CommandOverload::Arguments const &) { - TestObject ob; - senf::console::root().add("ob",ob.dir); - std::stringstream ss; - senf::console::ParseCommandInfo info; - senf::console::root()["ob"]("member")(ss, info.arguments()); - BOOST_CHECK_EQUAL( ss.str(), "member" ); + os << "fn3\n"; } - BOOST_CHECK_THROW( senf::console::root()["ob"], senf::console::UnknownNodeNameException ); + +} + +BOOST_AUTO_UNIT_TEST(overladedCommand) +{ + senf::console::OverloadedCommandNode & cmd ( + senf::console::root().add("overload", senf::console::OverloadedCommandNode::create())); + cmd.add(senf::console::SimpleCommandOverload::create(&fn1)); + cmd.add(senf::console::SimpleCommandOverload::create(&fn2)); + + senf::console::ParseCommandInfo info; + std::stringstream ss; + BOOST_CHECK_THROW( senf::console::root()("overload")(ss, info.arguments()), + senf::console::SyntaxErrorException ); + + cmd.add(senf::console::SimpleCommandOverload::create(&fn3)); + BOOST_CHECK_NO_THROW( senf::console::root()("overload")(ss, info.arguments()) ); + BOOST_CHECK_EQUAL( ss.str(), "fn3\n" ); + + cmd.unlink(); } ///////////////////////////////cc.e//////////////////////////////////////// diff --git a/Console/ScopedDirectory.cci b/Console/ScopedDirectory.cci new file mode 100644 index 0000000000000000000000000000000000000000..b6acd78818742b812f25771c3b43d40ce99d75ca --- /dev/null +++ b/Console/ScopedDirectory.cci @@ -0,0 +1,109 @@ +// $Id$ +// +// Copyright (C) 2008 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund <g0dil@berlios.de> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief ScopedDirectory inline non-template implementation */ + +//#include "ScopedDirectory.ih" + +// Custom includes + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::console::ScopedDirectoryBase + +prefix_ senf::console::DirectoryNode & senf::console::ScopedDirectoryBase::node() + const +{ + return *node_; +} + +prefix_ senf::console::GenericNode::ptr +senf::console::ScopedDirectoryBase::remove(std::string const & name) +{ + return node().remove(name); +} + +prefix_ senf::console::DirectoryNode & +senf::console::ScopedDirectoryBase::operator[](std::string const & name) + const +{ + return node()[name]; +} + +prefix_ senf::console::CommandNode & +senf::console::ScopedDirectoryBase::operator()(std::string const & name) + const +{ + return node()(name); +} + +prefix_ senf::console::GenericNode & +senf::console::ScopedDirectoryBase::get(std::string const & name) + const +{ + return node().get(name); +} + +prefix_ senf::console::DirectoryNode & +senf::console::ScopedDirectoryBase::mkdir(std::string const & name) +{ + return node().mkdir(name); +} + +prefix_ senf::console::DirectoryNode::ChildrenRange +senf::console::ScopedDirectoryBase::children() + const +{ + return node().children(); +} + +prefix_ senf::console::DirectoryNode & +senf::console::ScopedDirectoryBase::doc(std::string const & doc) +{ + return node().doc(doc); +} + +prefix_ senf::console::ScopedDirectoryBase::ScopedDirectoryBase() + : node_ (DirectoryNode::create()) +{} + +prefix_ senf::console::ScopedDirectoryBase::~ScopedDirectoryBase() +{ + node_->unlink(); +} + +///////////////////////////////cci.e/////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Console/ObjectDirectory.cti b/Console/ScopedDirectory.cti similarity index 64% rename from Console/ObjectDirectory.cti rename to Console/ScopedDirectory.cti index c3f3e0d57103e52fe1ea6dde962491e2845ba626..87ce190bbef11fda9b59468fc1c1a1945eae9eec 100644 --- a/Console/ObjectDirectory.cti +++ b/Console/ScopedDirectory.cti @@ -21,9 +21,9 @@ // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \file - \brief ObjectDirectory inline template implementation */ + \brief ScopedDirectory inline template implementation */ -//#include "ObjectDirectory.ih" +//#include "ScopedDirectory.ih" // Custom includes #include <boost/bind.hpp> @@ -45,85 +45,21 @@ senf::console::OwnerNodeCreateTraits<Owner,Object>::Creator::create(DirectoryNod } /////////////////////////////////////////////////////////////////////////// -// senf::console::ObjectDirectory<Owner> +// senf::console::ScopedDirectory<Owner> template <class Owner> -prefix_ senf::console::ObjectDirectory<Owner>::ObjectDirectory(Owner * owner) - : node_ (DirectoryNode::create()), owner_ (owner) -{} - -template <class Owner> -prefix_ senf::console::ObjectDirectory<Owner>::~ObjectDirectory() +prefix_ senf::console::ScopedDirectory<Owner>::ScopedDirectory(Owner * owner) + : owner_ (owner) { - node_->unlink(); + SENF_ASSERT(owner_); } template <class Owner> template <class Object> prefix_ typename senf::console::OwnerNodeCreateTraits<Owner, Object>::NodeType & -senf::console::ObjectDirectory<Owner>::add(std::string const & name, Object const & ob) -{ - return OwnerNodeCreateTraits<Owner, Object>::Creator::create(*node_, *owner_, name, ob); -} - -template <class Owner> -prefix_ senf::console::GenericNode::ptr -senf::console::ObjectDirectory<Owner>::remove(std::string const & name) -{ - return node().remove(name); -} - -template <class Owner> -prefix_ senf::console::DirectoryNode & -senf::console::ObjectDirectory<Owner>::operator[](std::string const & name) - const -{ - return node()[name]; -} - -template <class Owner> -prefix_ senf::console::CommandNode & -senf::console::ObjectDirectory<Owner>::operator()(std::string const & name) - const -{ - return node()(name); -} - -template <class Owner> -prefix_ senf::console::GenericNode & -senf::console::ObjectDirectory<Owner>::get(std::string const & name) - const -{ - return node().get(name); -} - -template <class Owner> -prefix_ senf::console::DirectoryNode & -senf::console::ObjectDirectory<Owner>::mkdir(std::string const & name) -{ - return node().mkdir(name); -} - -template <class Owner> -prefix_ senf::console::DirectoryNode::ChildrenRange -senf::console::ObjectDirectory<Owner>::children() - const -{ - return node().children(); -} - -template <class Owner> -prefix_ senf::console::DirectoryNode & -senf::console::ObjectDirectory<Owner>::doc(std::string const & doc) +senf::console::ScopedDirectory<Owner>::add(std::string const & name, Object const & ob) { - return node.doc(doc); -} - -template <class Owner> -prefix_ senf::console::DirectoryNode & senf::console::ObjectDirectory<Owner>::node() - const -{ - return *node_; + return OwnerNodeCreateTraits<Owner, Object>::Creator::create(node(), *owner_, name, ob); } template <class Owner, class Function> @@ -146,11 +82,21 @@ senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & n template <class Node> prefix_ senf::console::DirectoryNode & senf::console:: senf_console_add_node(DirectoryNode & dir, std::string const & name, Node const & node, int, - typename boost::enable_if< boost::is_convertible<Node*, ObjectDirectoryBase*> >::type *) + typename boost::enable_if< boost::is_convertible<Node*, ScopedDirectoryBase*> >::type *) { return dir.add(name, node.node().thisptr()); } +/////////////////////////////////////////////////////////////////////////// +// senf::console::ScopedDirectory<void> + +template <class Object> +prefix_ typename senf::console::NodeCreateTraits<Object>::NodeType & +senf::console::ScopedDirectory<void>::add(std::string const & name, Object const & ob) +{ + return node().add(name, ob); +} + ///////////////////////////////cti.e/////////////////////////////////////// #undef prefix_ diff --git a/Console/ObjectDirectory.hh b/Console/ScopedDirectory.hh similarity index 83% rename from Console/ObjectDirectory.hh rename to Console/ScopedDirectory.hh index 1845a065edfcc8e7f87745bae5f4735e7618c36b..cec50dbb9136d8bfc4ff710dc3cba63930b14700 100644 --- a/Console/ObjectDirectory.hh +++ b/Console/ScopedDirectory.hh @@ -21,26 +21,26 @@ // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \file - \brief ObjectDirectory public header */ + \brief ScopedDirectory public header */ -#ifndef HH_ObjectDirectory_ -#define HH_ObjectDirectory_ 1 +#ifndef HH_ScopedDirectory_ +#define HH_ScopedDirectory_ 1 // Custom includes #include <boost/utility.hpp> #include <boost/type_traits/is_convertible.hpp> #include "Node.hh" -//#include "ObjectDirectory.mpp" +//#include "ScopedDirectory.mpp" ///////////////////////////////hh.p//////////////////////////////////////// namespace senf { namespace console { - /** \brief Internal: Node creation helper traits (ObjectDirectory proxy) + /** \brief Internal: Node creation helper traits (ScopedDirectory proxy) This class is used like NodeCreateTraits to customize the child node creation. This trait - class is used however by the ObjectDirectory proxy. + class is used however by the ScopedDirectory proxy. */ template <class Owner, class Object> struct OwnerNodeCreateTraits @@ -60,13 +60,38 @@ namespace console { }; }; - /** \brief Internal: Marker base class for all ObjectDirectory proxies + /** \brief Internal: Marker base class for all ScopedDirectory proxies */ - struct ObjectDirectoryBase {}; + class ScopedDirectoryBase + { + public: + DirectoryNode & node() const; ///< Access the proxied DirectoryNode + + /////////////////////////////////////////////////////////////////////////// + ///\name Proxied members (see DirectoryNode) + ///\{ + + GenericNode::ptr remove(std::string const & name); + DirectoryNode & operator[](std::string const & name) const; + CommandNode & operator()(std::string const & name) const; + GenericNode & get(std::string const & name) const; + DirectoryNode & mkdir(std::string const & name); + DirectoryNode::ChildrenRange children() const; + DirectoryNode & doc(std::string const & doc); + + ///\} + + protected: + ScopedDirectoryBase(); + ~ScopedDirectoryBase(); + + private: + DirectoryNode::ptr node_; + }; /** \brief DirectoryNode member proxy - ObjectDirectory is used whenever a class wants to manage it's own directory. The class + ScopedDirectory is used whenever a class wants to manage it's own directory. The class allows to declare the directory as a public member object. This allows the user of the class to register the directory in the command tree. By using the proxy, the node is automatically detached from the tree (and thereby destroyed) when the object (and thereby the proxy) is @@ -76,7 +101,7 @@ namespace console { class MyClass { public: - ObjectDirectory<MyClass> configDir; + ScopedDirectory<MyClass> configDir; MyClass() : configDir(this) { @@ -85,9 +110,9 @@ namespace console { }; \endcode - The ObjectDirectory proxy implements 'add()' to add new children to the proxied + The ScopedDirectory proxy implements 'add()' to add new children to the proxied DirectoryNode. All add() variants supported by DirectoryNode are supported by - ObjectDirectory. + ScopedDirectory. \idea This proxy could be made obsolete by allowing to allocate node objects statically. This could be achieved by moving back to an intrusive_ptr implementation for @@ -98,8 +123,8 @@ namespace console { \ingroup node_tree */ - template <class Owner> - class ObjectDirectory : public ObjectDirectoryBase + template <class Owner=void> + class ScopedDirectory : public ScopedDirectoryBase { public: /////////////////////////////////////////////////////////////////////////// @@ -111,8 +136,7 @@ namespace console { ///\name Structors and default members ///@{ - ObjectDirectory(Owner * owner); - ~ObjectDirectory(); + ScopedDirectory(Owner * owner); ///@} /////////////////////////////////////////////////////////////////////////// @@ -127,29 +151,21 @@ namespace console { implementation just forwards the call to the proxied directory node. */ - DirectoryNode & node() const; ///< Access the proxied DirectoryNode - - /////////////////////////////////////////////////////////////////////////// - ///\name Proxied members (see DirectoryNode) - ///\{ - - GenericNode::ptr remove(std::string const & name); - DirectoryNode & operator[](std::string const & name) const; - CommandNode & operator()(std::string const & name) const; - GenericNode & get(std::string const & name) const; - DirectoryNode & mkdir(std::string const & name); - DirectoryNode::ChildrenRange children() const; - DirectoryNode & doc(std::string const & doc); - - ///\} - protected: private: - DirectoryNode::ptr node_; Owner * owner_; }; + template <> + class ScopedDirectory<void> : public ScopedDirectoryBase + { + public: + template <class Object> + typename NodeCreateTraits<Object>::NodeType & add(std::string const & name, + Object const & ob); + }; + #ifndef DOXYGEN template <class Owner, class Function> SimpleCommandNode & senf_console_add_node( @@ -163,15 +179,15 @@ namespace console { template <class Node> DirectoryNode & senf_console_add_node( DirectoryNode & dir, std::string const & name, Node const & node, int, - typename boost::enable_if< boost::is_convertible<Node*, ObjectDirectoryBase*> >::type * = 0); + typename boost::enable_if< boost::is_convertible<Node*, ScopedDirectoryBase*> >::type * = 0); #endif }} ///////////////////////////////hh.e//////////////////////////////////////// -//#include "ObjectDirectory.cci" -//#include "ObjectDirectory.ct" -#include "ObjectDirectory.cti" +#include "ScopedDirectory.cci" +//#include "ScopedDirectory.ct" +#include "ScopedDirectory.cti" #endif diff --git a/Console/ScopedDirectory.test.cc b/Console/ScopedDirectory.test.cc new file mode 100644 index 0000000000000000000000000000000000000000..4a3ce75a7e2d90969da0ff7e613169d6aa6cb82e --- /dev/null +++ b/Console/ScopedDirectory.test.cc @@ -0,0 +1,135 @@ +// $Id$ +// +// Copyright (C) 2008 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund <g0dil@berlios.de> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief ScopedDirectory.test unit tests */ + +//#include "ScopedDirectory.test.hh" +//#include "ScopedDirectory.test.ih" + +// Custom includes +#include <sstream> +#include "ScopedDirectory.hh" +#include <boost/iterator/transform_iterator.hpp> + +#include <boost/test/auto_unit_test.hpp> +#include <boost/test/test_tools.hpp> + +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + +namespace { + struct TestObject { + typedef TestObject Self; + + senf::console::ScopedDirectory<Self> dir; + TestObject() : dir(this) { + dir.add("member", &Self::member); + } + + void member(std::ostream & os, senf::console::CommandNode::Arguments const &) { + os << "member"; + } + }; +} + +BOOST_AUTO_UNIT_TEST(scopedDirectory) +{ + { + TestObject ob; + senf::console::root().add("ob",ob.dir); + std::stringstream ss; + senf::console::ParseCommandInfo info; + senf::console::root()["ob"]("member")(ss, info.arguments()); + BOOST_CHECK_EQUAL( ss.str(), "member" ); + } + BOOST_CHECK_THROW( senf::console::root()["ob"], senf::console::UnknownNodeNameException ); +} + +namespace { + void callback(std::ostream & os, senf::console::CommandNode::Arguments const &) { + os << "cb"; + } +} + +BOOST_AUTO_UNIT_TEST(scopedDirectoryVoid) +{ + { + senf::console::ScopedDirectory<> dir; + senf::console::root().add("dir", dir); + dir.add("cb", &callback); + std::stringstream ss; + senf::console::ParseCommandInfo info; + senf::console::root()["dir"]("cb")(ss, info.arguments()); + BOOST_CHECK_EQUAL( ss.str(), "cb" ); + } + BOOST_CHECK_THROW( senf::console::root()["dir"], + senf::console::UnknownNodeNameException ); +} + +namespace { + template <class T> + struct select1st { + typedef T result_type; + template <class U> result_type operator()(U const & u) const { return u.first; } + }; +} + +BOOST_AUTO_UNIT_TEST(scopedDirectoryBase) +{ + { + senf::console::ScopedDirectory<> dir; + senf::console::root().add("dir", dir); + dir.mkdir("foo"); + dir.add("cb", &callback); + BOOST_CHECK( &dir["foo"] == &dir.get("foo") ); + BOOST_CHECK( &dir("cb") == &dir.get("cb") ); + + char const * const children[] = { "cb", "foo" }; + BOOST_CHECK_EQUAL_COLLECTIONS( + boost::make_transform_iterator(dir.children().begin(), + select1st<std::string const &>()), + boost::make_transform_iterator(dir.children().end(), + select1st<std::string const &>()), + children, + children+sizeof(children)/sizeof(children[0]) ); + + dir.doc("dir"); + std::stringstream ss; + dir.node().help(ss); + BOOST_CHECK_EQUAL( ss.str(), "dir\n" ); + } +} + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Console/testServer.cc b/Console/testServer.cc index dc40117616d8a223858a0be0843bff929c1054cd..b7d5124497d45962bec51c872a4693533a816de2 100644 --- a/Console/testServer.cc +++ b/Console/testServer.cc @@ -30,7 +30,7 @@ #include <iostream> #include "Server.hh" #include "Node.hh" -#include "ObjectDirectory.hh" +#include "ScopedDirectory.hh" #include "../Scheduler/Scheduler.hh" #include "../Utils/Logger/SenfLog.hh" @@ -55,7 +55,7 @@ namespace { struct TestObject { - senf::console::ObjectDirectory<TestObject> dir; + senf::console::ScopedDirectory<TestObject> dir; TestObject() : dir(this) { dir.add("blub", &TestObject::blub) diff --git a/HowTos/NewPacket/Mainpage.dox b/HowTos/NewPacket/Mainpage.dox index bd659ab69a26f8e082a2d7359d8e8b467eb18484..e519e91c9dc21711ea3d89a03b4e83b840257091 100644 --- a/HowTos/NewPacket/Mainpage.dox +++ b/HowTos/NewPacket/Mainpage.dox @@ -805,9 +805,6 @@ (senf::VoidPacketParser) (GREPacketParser_OptFields) ); - typedef version__t version_t; - version_t::value_type version() const { return version_(); } - bool valid() const { return version() == 0 && reserved0_5bits_() == 0; } typedef GREPacketParser_OptFields::checksum_t checksum_t; diff --git a/doclib/senf.css b/doclib/senf.css index fe51388ec50d5b567439a9b6bd0a471ed6c62b18..1783cc14e9b22ec00f72f6b3a554398b9cc33ffe 100644 --- a/doclib/senf.css +++ b/doclib/senf.css @@ -513,7 +513,7 @@ p.commalist { } #autotoc { - width: 20em; + width: 30em; background-color: #F5F5F5; border: 1px solid #CCC; padding: 0 1em;