Console: Implement ObjectDirectory proxy
g0dil [Wed, 26 Mar 2008 00:02:20 +0000 (00:02 +0000)]
Console: Implement simple online help
Console: Remove uniquify flag
Console: Implement node-active check
Console: Implement node removal
Console: Move 'name' argument consistently to 'add' command
Console: Implement SimpleCommandNode (command with manual argument parsing)
Console: Implement 'add' family of members based on extensible creation helpers

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@765 270642c3-0616-0410-b53a-bc976706d245

15 files changed:
Console/Executor.cc
Console/Node.cc
Console/Node.cci
Console/Node.cti [new file with mode: 0644]
Console/Node.hh
Console/ObjectDirectory.cti [new file with mode: 0644]
Console/ObjectDirectory.hh [new file with mode: 0644]
Console/ObjectDirectory.test.cc [new file with mode: 0644]
Console/Parse.cc
Console/Parse.hh
Console/Parse.ih
Console/Parse.test.cc
Console/Server.cc
Console/Server.hh
Console/testServer.cc

index 7e16765..b808a09 100644 (file)
@@ -51,9 +51,7 @@ prefix_ bool senf::console::Executor::operator()(ParseCommandInfo const & comman
 {
     SENF_LOG(( "Executing: " << command ));
 
-    ///\fixme Whenever checking cwd_.expired(), we also need to check, wether
-    /// the node is still connected to the root.
-    if (cwd_.expired())
+    if (cwd_.expired() || ! cwd().active())
         cwd_ = root().thisptr();
 
     try {
@@ -66,7 +64,7 @@ prefix_ bool senf::console::Executor::operator()(ParseCommandInfo const & comman
             if ( command.arguments() ) {
                 if (command.arguments().begin()->size() == 1 
                     && command.arguments().begin()->begin()->value() == "-") {
-                    if (oldCwd_.expired()) {
+                    if (oldCwd_.expired() || ! oldCwd_.lock()->active()) {
                         oldCwd_ = cwd_;
                         cwd_ = root().thisptr();
                     } else
@@ -107,6 +105,23 @@ prefix_ bool senf::console::Executor::operator()(ParseCommandInfo const & comman
             
         case ParseCommandInfo::BuiltinEXIT :
             throw ExitException();
+
+        case ParseCommandInfo::BuiltinHELP :
+            try {
+                GenericNode & node (
+                    command.arguments() 
+                    ? cwd().traverse(
+                        boost::make_iterator_range(
+                            boost::make_transform_iterator(command.arguments().begin()[0].begin(), TraverseTokens()),
+                            boost::make_transform_iterator(command.arguments().begin()[0].end(), TraverseTokens())))
+                    : cwd() );
+                node.help(output);
+                output << std::flush;
+            }
+            catch (UnknownNodeNameException &) {
+                output << "invalid path" << std::endl;
+            }
+            break;
         }
     }
     catch (InvalidDirectoryException &) {
index 382804f..f21ab66 100644 (file)
@@ -34,7 +34,7 @@
 
 prefix_ senf::console::DirectoryNode & senf::console::root()
 {
-    static DirectoryNode::ptr rootNode(new DirectoryNode(""));
+    static DirectoryNode::ptr rootNode(new DirectoryNode());
     return *rootNode;
 }
 
@@ -53,15 +53,33 @@ prefix_ std::string senf::console::GenericNode::path()
     return path.empty() ? "/" : path;
 }
 
+prefix_ bool senf::console::GenericNode::active()
+    const
+{
+    cptr node (thisptr());
+    while (node->parent())
+        node = node->parent();
+    return node == root().thisptr();
+}
+
 ///////////////////////////////////////////////////////////////////////////
 //senf::console::DirectoryNode
 
-prefix_ void senf::console::DirectoryNode::add(GenericNode::ptr node, bool uniquify)
+prefix_ senf::console::GenericNode::ptr
+senf::console::DirectoryNode::remove(std::string const & name)
+{
+    ChildMap::iterator i (children_.find(name));
+    if (i == children_.end()) 
+        throw UnknownNodeNameException() << ": '" << name << "'";
+    GenericNode::ptr node (i->second);
+    children_.erase(i);
+    return node;
+}
+
+prefix_ void senf::console::DirectoryNode::add(GenericNode::ptr node)
 {
     BOOST_ASSERT( ! node->parent() );
     if (children_.find(node->name()) != children_.end()) {
-        if (! uniquify)
-            throw DuplicateNodeNameException() << ": '" << node->name() << "'";
         unsigned suffix (0);
         std::string newName;
         do {
@@ -84,6 +102,21 @@ senf::console::DirectoryNode::get(std::string const & name)
     return *(i->second);
 }
 
+prefix_ void senf::console::DirectoryNode::v_help(std::ostream & output)
+    const
+{
+    output << doc_ << "\n";
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::SimpleCommandNode
+
+prefix_ void senf::console::SimpleCommandNode::v_help(std::ostream & output)
+    const
+{
+    output << doc_ << "\n";
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 //#include "Node.mpp"
index f4fbc11..915d954 100644 (file)
@@ -43,11 +43,9 @@ prefix_ std::string const & senf::console::GenericNode::name()
     return name_;
 }
 
-prefix_ senf::console::GenericNode::GenericNode(std::string const & name)
-    : name_ (name), parent_ (0)
-{
-    ///\fixme Provide a default name if 'name' is empty ?
-}
+prefix_ senf::console::GenericNode::GenericNode()
+    : parent_ (0)
+{}
 
 prefix_ void senf::console::GenericNode::name(std::string const & name)
 {
@@ -66,6 +64,18 @@ prefix_ boost::shared_ptr<senf::console::DirectoryNode> senf::console::GenericNo
         parent_ ? parent_->shared_from_this() : ptr() );
 }
 
+prefix_ senf::console::GenericNode::ptr senf::console::GenericNode::unlink()
+{
+    SENF_ASSERT( parent() );
+    return parent()->remove(name());
+}
+
+prefix_ void senf::console::GenericNode::help(std::ostream & output)
+    const
+{
+    v_help(output);
+}
+
 prefix_ senf::console::GenericNode::ptr senf::console::GenericNode::thisptr()
 {
     return shared_from_this();
@@ -80,12 +90,10 @@ prefix_ senf::console::GenericNode::cptr senf::console::GenericNode::thisptr()
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::DirectoryNode
 
-prefix_ senf::console::GenericNode &
-senf::console::DirectoryNode::add(std::auto_ptr<GenericNode> node, bool uniquify)
+prefix_ std::auto_ptr<senf::console::DirectoryNode>
+senf::console::DirectoryNode::create()
 {
-    GenericNode::ptr p (node.release());
-    add(p, uniquify);
-    return *p;
+    return std::auto_ptr<DirectoryNode>(new DirectoryNode());
 }
 
 prefix_ senf::console::DirectoryNode &
@@ -105,8 +113,8 @@ senf::console::DirectoryNode::operator()(std::string const & name)
 prefix_ senf::console::DirectoryNode &
 senf::console::DirectoryNode::mkdir(std::string const & name)
 {
-    return static_cast<DirectoryNode &>(
-        add(std::auto_ptr<GenericNode>(new DirectoryNode(name))));
+    std::auto_ptr<DirectoryNode> node (create());
+    return add(name, node);
 }
 
 prefix_ senf::console::DirectoryNode::ChildrenRange senf::console::DirectoryNode::children()
@@ -115,10 +123,16 @@ prefix_ senf::console::DirectoryNode::ChildrenRange senf::console::DirectoryNode
     return boost::make_iterator_range(children_.begin(), children_.end());
 }
 
-prefix_ senf::console::DirectoryNode::DirectoryNode(std::string const & name)
-    : GenericNode(name)
+prefix_ senf::console::DirectoryNode::DirectoryNode()
 {}
 
+prefix_ senf::console::DirectoryNode &
+senf::console::DirectoryNode::doc(std::string const & doc)
+{
+    doc_ = doc;
+    return *this;
+}
+
 prefix_ senf::console::DirectoryNode::ptr senf::console::DirectoryNode::thisptr()
 {
     return boost::static_pointer_cast<DirectoryNode>(shared_from_this());
@@ -133,10 +147,6 @@ prefix_ senf::console::DirectoryNode::cptr senf::console::DirectoryNode::thisptr
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::CommandNode
 
-prefix_ senf::console::CommandNode::CommandNode(std::string const & name)
-    : GenericNode(name)
-{}
-
 prefix_ senf::console::CommandNode::ptr senf::console::CommandNode::thisptr()
 {
     return boost::static_pointer_cast<CommandNode>(shared_from_this());
@@ -148,6 +158,35 @@ prefix_ senf::console::CommandNode::cptr senf::console::CommandNode::thisptr()
     return boost::static_pointer_cast<CommandNode const>(shared_from_this());
 }
 
+prefix_ senf::console::CommandNode::CommandNode()
+{}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::SimpleCommandNode
+
+prefix_ void senf::console::SimpleCommandNode::operator()(std::ostream & output,
+                                                          Arguments const & arguments)
+{
+    fn_(output, arguments);
+}
+
+prefix_ senf::console::SimpleCommandNode::SimpleCommandNode(Function const & fn)
+    : fn_ (fn)
+{}
+
+prefix_ std::auto_ptr<senf::console::SimpleCommandNode>
+senf::console::SimpleCommandNode::create(Function const & fn)
+{
+    return std::auto_ptr<SimpleCommandNode>(new SimpleCommandNode(fn));
+}
+
+prefix_ senf::console::SimpleCommandNode &
+senf::console::SimpleCommandNode::doc(std::string const & doc)
+{
+    doc_ = doc;
+    return *this;
+}
+
 ///////////////////////////////cci.e///////////////////////////////////////
 #undef prefix_
 
diff --git a/Console/Node.cti b/Console/Node.cti
new file mode 100644 (file)
index 0000000..c56f014
--- /dev/null
@@ -0,0 +1,97 @@
+// $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 Node inline template implementation */
+
+//#include "Node.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::NodeCreateTraits<Object>::Creator
+
+template <class Object>
+prefix_ typename senf::console::NodeCreateTraits<Object>::NodeType &
+senf::console::NodeCreateTraits<Object>::Creator::create(DirectoryNode & node,
+                                                         std::string const & name,
+                                                         Object const & ob)
+{
+    return senf_console_add_node(node, name, ob, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::DirectoryNode
+
+template <class NodeType>
+prefix_ NodeType & senf::console::DirectoryNode::add(std::string const & name,
+                                                     std::auto_ptr<NodeType> node)
+{
+    GenericNode::ptr p (node);
+    p->name(name);
+    add(p);
+    return static_cast<NodeType &>(*p);
+}
+
+template <class NodeType>
+prefix_ NodeType & senf::console::DirectoryNode::add(std::string const & name,
+                                                     boost::shared_ptr<NodeType> node)
+{
+    SENF_ASSERT( ! node->parent() );
+    node->name(name);
+    add(node);
+    return *node;
+}
+
+template <class Object>
+prefix_ typename senf::console::NodeCreateTraits<Object>::NodeType &
+senf::console::DirectoryNode::add(std::string const & name, Object const & ob)
+{
+    return NodeCreateTraits<Object>::Creator::create(*this, name, ob);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::SimpleCommandNode
+
+template <class Function>
+prefix_ senf::console::SimpleCommandNode & senf::console::
+senf_console_add_node(DirectoryNode & node, std::string const & name, Function const & fn, ...)
+{
+    return node.add(name, SimpleCommandNode::create(fn));
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// 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:
index d081ffd..10ac02e 100644 (file)
 #include <boost/enable_shared_from_this.hpp>
 #include <boost/utility.hpp>
 #include <boost/range/iterator_range.hpp>
+#include <boost/typeof/typeof.hpp>
+#include <boost/type_traits/remove_reference.hpp>
 #include "../Utils/Exception.hh"
+#include "../Utils/mpl.hh"
 #include "Parse.hh"
 
 //#include "Node.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
 
+#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
+
 namespace senf {
 namespace console {
 
@@ -64,21 +69,28 @@ namespace console {
 
         std::string const & name() const;
         boost::shared_ptr<DirectoryNode> parent() const;
-        bool managed() const;
 
         std::string path() const;
 
+        ptr unlink();
+
+        bool active() const;
+
+        void help(std::ostream & output) const;
+
         ptr thisptr();
         cptr thisptr() const;
 
     protected:
-        explicit GenericNode(std::string const & name);
+        GenericNode();
 
         void name(std::string const & name);
         static void name(GenericNode & node, std::string const & name);
         void parent(DirectoryNode * parent);
 
     private:
+        virtual void v_help(std::ostream & output) const = 0;
+
         std::string name_;
         DirectoryNode * parent_;
 
@@ -86,7 +98,27 @@ namespace console {
         friend class DirectoryNode;
     };
 
+    class SimpleCommandNode;
+
+    template <class Object>
+    struct NodeCreateTraits
+    {
+        typedef BOOST_TYPEOF_TPL( senf_console_add_node( 
+                                      * static_cast<DirectoryNode *>(0),
+                                      * static_cast<std::string const *>(0),
+                                      * static_cast<Object const *>(0),
+                                      0) ) result_type;
+
+        typedef typename boost::remove_reference<result_type>::type NodeType;
+
+        struct Creator {
+            static NodeType & create(DirectoryNode & node, std::string const & name, 
+                                     Object const & ob);
+        };
+    };
+
     /** \brief
+        ///\fixme Provide a default name for added nodes if 'name' is empty ?
       */
     class DirectoryNode : public GenericNode
     {
@@ -104,8 +136,27 @@ namespace console {
         typedef ChildMap::const_iterator child_iterator;
 
         ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///\{
+
+        static std::auto_ptr<DirectoryNode> create();
+
+        ///\}
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Children
+        ///\{
+
+        template <class NodeType>
+        NodeType & add(std::string const & name, std::auto_ptr<NodeType> node);
+
+        template <class NodeType>
+        NodeType & add(std::string const & name, boost::shared_ptr<NodeType> node);
 
-        GenericNode & add(std::auto_ptr<GenericNode> node, bool uniquify = true);
+        template <class Object>
+        typename NodeCreateTraits<Object>::NodeType & add (std::string const & name, 
+                                                           Object const & ob);
+
+        GenericNode::ptr remove(std::string const & name);
 
         DirectoryNode & operator[](std::string const & name) const;
         CommandNode & operator()(std::string const & name) const;
@@ -115,29 +166,44 @@ namespace console {
         
         ChildrenRange children() const;
 
+        ///\}
+        ///////////////////////////////////////////////////////////////////////////
+
         template <class ForwardRange>
         GenericNode & traverse(ForwardRange const & range);
 
+        DirectoryNode & doc(std::string const & doc);
+
         ptr thisptr();
         cptr thisptr() const;
 
     protected:
-        explicit DirectoryNode(std::string const & name);
+        DirectoryNode();
 
     private:
-        void add(GenericNode::ptr node, bool uniquify);
+        void add(GenericNode::ptr node);
+        virtual void v_help(std::ostream & output) const;
 
         ChildMap children_;
+        std::string doc_;
 
         friend DirectoryNode & root();
     };
 
-    struct DuplicateNodeNameException : public senf::Exception
-    { DuplicateNodeNameException() : senf::Exception("Duplicate node name") {}};
+    BOOST_TYPEOF_REGISTER_TYPE(DirectoryNode);
 
     struct UnknownNodeNameException : public senf::Exception
     { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
 
+    // We need this specialization since we cannot passe auto_ptr via const & !!
+    template <class Type>
+    struct NodeCreateTraits< std::auto_ptr<Type> >
+    {};
+
+    template <class Type>
+    struct NodeCreateTraits< boost::shared_ptr<Type> >
+    {};
+
     /** \brief
       */
     class CommandNode : public GenericNode
@@ -150,21 +216,58 @@ namespace console {
         typedef boost::shared_ptr<CommandNode const> cptr;
         typedef boost::weak_ptr<CommandNode> weak_ptr;
 
+        typedef ParseCommandInfo::ArgumentsRange Arguments;
+
+        ///////////////////////////////////////////////////////////////////////////
+
+        virtual void operator()(std::ostream & output, Arguments const & arguments) = 0;
+
+        ptr thisptr();
+        cptr thisptr() const;
+
+    protected:
+        CommandNode();
+
+    private:
+    };
+
+    /** \brief
+      */
+    class SimpleCommandNode : public CommandNode
+    {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        typedef boost::function<void (std::ostream &, Arguments const &)> Function;
+
         ///////////////////////////////////////////////////////////////////////////
 
-        virtual void operator()(std::ostream & output, 
-                                ParseCommandInfo::ArgumentsRange const & arguments) = 0;
+        virtual void operator()(std::ostream & output, Arguments const & arguments);
 
         ptr thisptr();
         cptr thisptr() const;
 
+        static std::auto_ptr<SimpleCommandNode> create(Function const & fn);
+
+        SimpleCommandNode & doc(std::string const & doc);
+
     protected:
-        explicit CommandNode(std::string const & name);
+        SimpleCommandNode(Function const & fn);
 
     private:
+        virtual void v_help(std::ostream & output) const;
 
+        Function fn_;
+        std::string doc_;
     };
 
+    template <class Function>
+    SimpleCommandNode & senf_console_add_node(DirectoryNode & node, std::string const & name, 
+                                              Function const & fn, ...);
+
+    BOOST_TYPEOF_REGISTER_TYPE(SimpleCommandNode);
+
     DirectoryNode & root();
 
 }}
@@ -172,7 +275,7 @@ namespace console {
 ///////////////////////////////hh.e////////////////////////////////////////
 #include "Node.cci"
 #include "Node.ct"
-//#include "Node.cti"
+#include "Node.cti"
 #endif
 
 \f
diff --git a/Console/ObjectDirectory.cti b/Console/ObjectDirectory.cti
new file mode 100644 (file)
index 0000000..3fb3a62
--- /dev/null
@@ -0,0 +1,113 @@
+// $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 ObjectDirectory inline template implementation */
+
+//#include "ObjectDirectory.ih"
+
+// Custom includes
+#include <boost/bind.hpp>
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::OwnerNodeCreateTraits<Owner,Object>::Creator
+
+template <class Owner, class Object>
+prefix_ typename senf::console::OwnerNodeCreateTraits<Owner,Object>::NodeType &
+senf::console::OwnerNodeCreateTraits<Owner,Object>::Creator::create(DirectoryNode & node,
+                                                                    Owner & owner,
+                                                                    std::string const & name,
+                                                                    Object const & ob)
+{
+    return senf_console_add_node(node, owner, name, ob);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::ObjectDirectory<Owner>
+
+template <class Owner>
+prefix_ senf::console::ObjectDirectory<Owner>::ObjectDirectory(Owner * owner)
+    : node_ (DirectoryNode::create().release()), owner_ (owner)
+{}
+
+template <class Owner>
+prefix_ senf::console::ObjectDirectory<Owner>::~ObjectDirectory()
+{
+    node_->unlink();
+}
+
+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::DirectoryNode & senf::console::ObjectDirectory<Owner>::node()
+    const
+{
+    return *node_;
+}
+
+template <class Owner, class Function>
+prefix_ senf::console::SimpleCommandNode & senf::console::
+senf_console_add_node(DirectoryNode & node, Owner & , std::string const & name,
+                      Function const & fn)
+{
+    return node.add(name,fn);
+}
+
+template <class Owner>
+prefix_ senf::console::SimpleCommandNode & senf::console::
+senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
+                      void (Owner::*fn)(std::ostream & output, 
+                                        CommandNode::Arguments const & arguments))
+{
+    return node.add(name, boost::bind(fn,boost::ref(owner),_1,_2));
+}
+
+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 *)
+{
+    return dir.add(name, node.node().thisptr());
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// 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.hh b/Console/ObjectDirectory.hh
new file mode 100644 (file)
index 0000000..ccecf8d
--- /dev/null
@@ -0,0 +1,127 @@
+// $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 ObjectDirectory public header */
+
+#ifndef HH_ObjectDirectory_
+#define HH_ObjectDirectory_ 1
+
+// Custom includes
+#include <boost/utility.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include "Node.hh"
+
+//#include "ObjectDirectory.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace console {
+
+    template <class Owner, class Object>
+    struct OwnerNodeCreateTraits
+    {
+        typedef BOOST_TYPEOF_TPL( senf_console_add_node( 
+                                      * static_cast<DirectoryNode *>(0),
+                                      * static_cast<Owner *>(0),
+                                      * static_cast<std::string const *>(0),
+                                      * static_cast<Object const *>(0)) ) result_type;
+
+        typedef typename boost::remove_reference<result_type>::type NodeType;
+
+        struct Creator {
+            static NodeType & create(DirectoryNode & node, Owner & owner, 
+                                     std::string const & name, Object const & ob);
+        };
+    };
+    
+    struct ObjectDirectoryBase {};
+
+    /** \brief
+      */
+    template <class Owner>
+    class ObjectDirectory : public ObjectDirectoryBase
+    {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+        
+        typedef Owner owner;
+
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///@{
+
+        ObjectDirectory(Owner * owner);
+        ~ObjectDirectory();
+
+        ///@}
+        ///////////////////////////////////////////////////////////////////////////
+
+        template <class Object>
+        typename OwnerNodeCreateTraits<Owner, Object>::NodeType & add(std::string const & name,
+                                                                      Object const & ob);
+
+        DirectoryNode & node() const;
+
+    protected:
+
+    private:
+        static SimpleCommandNode & create(DirectoryNode & node, Owner * owner, 
+                                          std::string const & name, 
+                                          SimpleCommandNode::Function const & fn);
+
+        DirectoryNode::ptr node_;
+        Owner * owner_;
+    };
+
+    template <class Owner, class Function>
+    SimpleCommandNode & senf_console_add_node(
+        DirectoryNode & node, Owner & owner, std::string const & name, Function const & fn);
+
+    template <class Owner>
+    SimpleCommandNode & senf_console_add_node(
+        DirectoryNode & node, Owner & owner, std::string const & name, 
+        void (Owner::*fn)(std::ostream & output, CommandNode::Arguments const & arguments));
+
+    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);
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "ObjectDirectory.cci"
+//#include "ObjectDirectory.ct"
+#include "ObjectDirectory.cti"
+#endif
+
+\f
+// 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/ObjectDirectory.test.cc
new file mode 100644 (file)
index 0000000..1c5ac82
--- /dev/null
@@ -0,0 +1,53 @@
+// $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 ObjectDirectory.test unit tests */
+
+//#include "ObjectDirectory.test.hh"
+//#include "ObjectDirectory.test.ih"
+
+// Custom includes
+#include "ObjectDirectory.hh"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+BOOST_AUTO_UNIT_TEST(ownerDirectory)
+{}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// 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:
index a631f0f..bf49f31 100644 (file)
@@ -133,6 +133,12 @@ namespace detail {
               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinEXIT);
               ParserAccess::finalize(info_); cb_(info_); }
 
+        void builtin_help(std::vector<std::string> & path)
+            { ParserAccess::init(info_);
+              ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinHELP);
+              setBuiltinPathArg(path);
+              ParserAccess::finalize(info_); cb_(info_); }
+
         void setBuiltinPathArg(std::vector<std::string> & path)
             {
                 ParserAccess::startArgument(info_);
@@ -181,7 +187,7 @@ prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
     if (info.builtin() == ParseCommandInfo::NoBuiltin) 
         stream << senf::stringJoin(info.commandPath(), "/");
     else {
-        char const * builtins[] = { "", "cd", "ls", "pushd", "popd", "exit" };
+        char const * builtins[] = { "", "cd", "ls", "pushd", "popd", "exit", "help" };
         stream << "builtin-" << builtins[info.builtin()];
     }
         
index a4e452c..36cde7c 100644 (file)
@@ -89,7 +89,8 @@ namespace console {
                               BuiltinLS, 
                               BuiltinPUSHD, 
                               BuiltinPOPD,
-                              BuiltinEXIT };
+                              BuiltinEXIT,
+                              BuiltinHELP };
 
         BuiltinCommand builtin() const;
         CommandPathRange commandPath() const;
index 9f7edf9..02930e6 100644 (file)
@@ -208,11 +208,16 @@ namespace detail {
                       >> path
                       >> eps_p                    [ self.dispatch(&PD::builtin_cd,
                                                                   boost::ref(self.context.path)) ]
-                    |    keyword_p("ls") 
+                    |    keyword_p("ls")
                       >> ! path
                       >> eps_p                    [ self.dispatch(&PD::builtin_ls,
                                                                   boost::ref(self.context.path)) ]
                     |    keyword_p("exit")        [ self.dispatch(&PD::builtin_exit) ]
+                    
+                    |    keyword_p("help")
+                      >> ! path
+                      >> eps_p                    [ self.dispatch(&PD::builtin_help,
+                                                                  boost::ref(self.context.path)) ]
                     ;
 
                 block
index 3f83d57..8c03817 100644 (file)
@@ -78,6 +78,8 @@ namespace
             { os_ << "builtin_cd( " << senf::stringJoin(path, "/") << " )\n"; }
         void builtin_exit()
             { os_ << "builtin_exit()\n"; }
+        void builtin_help(std::vector<std::string> const & path)
+            { os_ << "builtin_help( " << senf::stringJoin(path, "/") << " )\n"; }
     };
 }
 
index 72fd25c..4e37e68 100644 (file)
@@ -126,11 +126,6 @@ prefix_ void senf::console::Client::clientData(ReadHelper<ClientHandle>::ptr hel
         return;
     }
 
-    ///\fixme Fix Client::clientData implementation
-    /// Remove the 'dup' needed here so we don't close the same fd twice (see Client constructor)
-    /// Make output non-blocking
-    /// Don't register a new ReadHelper every round
-
     std::string data (tail_ + helper->data());
     tail_ = helper->tail();
     boost::trim(data); // Gets rid of superfluous  \r or \n characters
index bfce303..c8d2c7f 100644 (file)
@@ -51,6 +51,7 @@ namespace console {
     class Client;
 
     /** \brief
+        ///\fixme Use special non-blocking streambuf
       */
     class Server
         : boost::noncopyable
@@ -94,6 +95,11 @@ namespace console {
     };
     
     /** \brief
+
+        \fixme Fix Client::clientData implementation
+            Remove the 'dup' needed here so we don't close the same fd twice (see Client constructor)
+            Make output non-blocking
+            Don't register a new ReadHelper every round
      */
     class Client
         : public senf::intrusive_refcount
index b55ca1b..f0d500e 100644 (file)
@@ -30,6 +30,7 @@
 #include <iostream>
 #include "Server.hh"
 #include "Node.hh"
+#include "ObjectDirectory.hh"
 #include "../Scheduler/Scheduler.hh"
 #include "../Utils/Logger/SenfLog.hh"
 
 ///////////////////////////////cc.p////////////////////////////////////////
 
 namespace {
-    struct MyCommand : public senf::console::CommandNode
+    
+    void fn(std::ostream & output, 
+            senf::console::CommandNode::Arguments const & arguments) {
+        senf::console::CommandNode::Arguments::iterator i (arguments.begin());
+        senf::console::CommandNode::Arguments::iterator i_end (arguments.end());
+        for (; i != i_end; ++i) {
+            senf::console::CommandNode::Arguments::value_type::iterator j (i->begin());
+            senf::console::CommandNode::Arguments::value_type::iterator j_end (i->end());
+            for (; j != j_end; ++j) 
+                output << j->value() << ' ';
+        }
+        output << "\n";
+    }
+
+    struct TestObject
     {
-        MyCommand(std::string name) : senf::console::CommandNode(name) {}
-        void operator()(std::ostream & output, 
-                        senf::console::ParseCommandInfo::ArgumentsRange const & arguments) {
-            senf::console::ParseCommandInfo::argument_iterator i (arguments.begin());
-            senf::console::ParseCommandInfo::argument_iterator i_end (arguments.end());
-            for (; i != i_end; ++i) {
-                senf::console::ParseCommandInfo::token_iterator j (i->begin());
-                senf::console::ParseCommandInfo::token_iterator j_end (i->end());
-                for (; j != j_end; ++j) 
-                    output << j->value() << ' ';
-            }
-            output << "\n";
+        senf::console::ObjectDirectory<TestObject> dir;
+
+        TestObject() : dir(this) {
+            dir.add("blub", &TestObject::blub)
+                .doc("Example of a member function");
+        }
+        
+        void blub(std::ostream & output, senf::console::CommandNode::Arguments const & args) {
+            output << "blub\n";
         }
     };
+
 }
 
 int main(int, char const **)
 {
     senf::log::ConsoleTarget::instance().route< senf::SenfLog, senf::log::NOTICE >();
 
-    senf::console::root().mkdir("network").mkdir("eth0");
+    senf::console::root().doc("This is the console test application");
+    senf::console::root().mkdir("network")
+        .doc("Network related settings");
+    senf::console::root()["network"].mkdir("eth0")
+        .doc("Ethernet device eth0");
     senf::console::root().mkdir("server");
+    senf::console::root()["network"].add("route", &fn)
+        .doc("Example of a directly registered function");
 
-    senf::console::root()["network"].add(
-        std::auto_ptr<senf::console::GenericNode>(new MyCommand("route")));
+    TestObject test;
+    senf::console::root().add("testob", test.dir)
+        .doc("Example of an instance directory");
 
     senf::console::Server::start( senf::INet4SocketAddress("127.0.0.1:23232") )
         .name("testServer");