Console: Factored out path traversal into generic traversal helper
g0dil [Sun, 23 Mar 2008 23:48:04 +0000 (23:48 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@759 270642c3-0616-0410-b53a-bc976706d245

Console/Executor.cc
Console/Executor.hh
Console/Node.cc
Console/Node.cci
Console/Node.ct [new file with mode: 0644]
Console/Node.hh
Console/Parse.ih
Console/Server.cc

index 43fc6d2..6070184 100644 (file)
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
+namespace {
+
+    struct TraverseTokens {
+        typedef std::string const & result_type;
+        result_type operator()(senf::console::ArgumentToken const & token) const {
+            return token.value();
+        }
+    };
+    
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::Executor
 
@@ -40,96 +51,85 @@ 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())
-        cwd_ = boost::static_pointer_cast<DirectoryNode>(
-            root().shared_from_this());
-
-    switch(command.builtin()) {
-    case ParseCommandInfo::NoBuiltin :
-        break;
+        cwd_ = root().thisptr();
 
-    case ParseCommandInfo::BuiltinCD :
-        if ( command.arguments() &&
-             ! chdir(command.arguments().begin()[0]) )
-            output << "invalid directory\n";
-        break;
-
-    case ParseCommandInfo::BuiltinLS :
-        for (DirectoryNode::child_iterator i (cwd().children().begin());
-             i != cwd().children().end(); ++i) {
-            output << i->first;
-            try {
-                (void) cwd()(i->first);
+    try {
+        switch(command.builtin()) {
+        case ParseCommandInfo::NoBuiltin :
+            break;
+            
+        case ParseCommandInfo::BuiltinCD :
+            if ( command.arguments() ) {
+                if (command.arguments().begin()->size() == 1 
+                    && command.arguments().begin()->begin()->value() == "-") {
+                    if (oldCwd_.expired()) {
+                        oldCwd_ = cwd_;
+                        cwd_ = root().thisptr();
+                    } else
+                        swap(cwd_, oldCwd_);
+                }
+                else {
+                    oldCwd_ = cwd_;
+                    cwd_ = traverseTo(command.arguments().begin()[0]).thisptr();
+                }
             }
-            catch (std::bad_cast &) {
-                output << "/";
+            break;
+            
+        case ParseCommandInfo::BuiltinLS : {
+            DirectoryNode const & dir (
+                command.arguments().empty() ? cwd() : traverseTo(command.arguments().begin()[0]));
+            for (DirectoryNode::child_iterator i (dir.children().begin());
+                 i != dir.children().end(); ++i) {
+                output << i->first;
+                if (boost::dynamic_pointer_cast<DirectoryNode>(i->second))
+                    output << "/";
+                output << "\n";
             }
-            output << "\n";
+            break;
         }
-        break;
 
-    case ParseCommandInfo::BuiltinPUSHD :
-        dirstack_.push_back(cwd_);
-        if ( command.arguments()
-             && ! chdir(command.arguments().begin()[0]) )
-            output << "invalid directory\n";
-        break;
-
-    case ParseCommandInfo::BuiltinPOPD :
-        if (! dirstack_.empty()) {
-            cwd_ = dirstack_.back();
-            dirstack_.pop_back();
+        case ParseCommandInfo::BuiltinPUSHD :
+            dirstack_.push_back(cwd_);
+            if ( command.arguments() )
+                cwd_ = traverseTo(command.arguments().begin()[0]).thisptr();
+            break;
+            
+        case ParseCommandInfo::BuiltinPOPD :
+            if (! dirstack_.empty()) {
+                cwd_ = dirstack_.back();
+                dirstack_.pop_back();
+            }
+            break;
+            
+        case ParseCommandInfo::BuiltinEXIT :
+            throw ExitException();
         }
-        break;
-
-    case ParseCommandInfo::BuiltinEXIT :
-        throw ExitException();
+    }
+    catch (InvalidDirectoryException &) {
+        output << "invalid directory" << std::endl;
     }
     return true;
 }
 
-prefix_ bool senf::console::Executor::chdir(ParseCommandInfo::argument_value_type const & path)
+prefix_ senf::console::DirectoryNode &
+senf::console::Executor::traverseTo(ParseCommandInfo::argument_value_type const & path)
 {
-    if (path.size() == 1 && path.begin()->value() == "-") {
-        if (oldCwd_.expired()) {
-            oldCwd_ = cwd_;
-            cwd_ = boost::static_pointer_cast<DirectoryNode>(
-                root().shared_from_this());
-        } else
-            swap(cwd_, oldCwd_);
+    try {
+        return dynamic_cast<DirectoryNode&>(
+            cwd().traverse(
+                boost::make_iterator_range(
+                    boost::make_transform_iterator(path.begin(), TraverseTokens()),
+                    boost::make_transform_iterator(path.end(), TraverseTokens()))));
     }
-    else {
-        try {
-            DirectoryNode::ptr dir (cwd_.lock());
-            ParseCommandInfo::token_iterator i (path.begin());
-            ParseCommandInfo::token_iterator const i_end (path.end());
-            if (i != i_end && i->value().empty()) {
-                dir = boost::static_pointer_cast<DirectoryNode>(
-                    root().shared_from_this());
-                ++ i;
-            }
-            for (; i != i_end; ++i) {
-                if (i->value() == "..") {
-                    dir = dir->parent(); 
-                    if (! dir)
-                        dir = boost::static_pointer_cast<DirectoryNode>(
-                            root().shared_from_this());
-                }
-                else if (! i->value().empty() && i->value() != ".")
-                    dir = boost::static_pointer_cast<DirectoryNode>(
-                        (*dir)[i->value()].shared_from_this());
-            }
-            oldCwd_ = cwd_;
-            cwd_ = dir;
-        }
-        catch (std::bad_cast &) {
-            return false;
-        }
-        catch (UnknownNodeNameException &) {
-            return false;
-        }
+    catch (std::bad_cast &) {
+        throw InvalidDirectoryException();
+    }
+    catch (UnknownNodeNameException &) {
+        throw InvalidDirectoryException();
     }
-    return true;
 }
         
 ///////////////////////////////cc.e////////////////////////////////////////
index bc3ce99..658cc99 100644 (file)
@@ -68,7 +68,9 @@ namespace console {
     protected:
 
     private:
-        bool chdir(ParseCommandInfo::argument_value_type const & path);
+        DirectoryNode & traverseTo(ParseCommandInfo::argument_value_type const & path);
+
+        struct InvalidDirectoryException {};
 
         DirectoryNode::weak_ptr cwd_;
         DirectoryNode::weak_ptr oldCwd_;
index 90518b0..382804f 100644 (file)
@@ -75,7 +75,7 @@ prefix_ void senf::console::DirectoryNode::add(GenericNode::ptr node, bool uniqu
 }
 
 prefix_ senf::console::GenericNode &
-senf::console::DirectoryNode::lookup(std::string const & name)
+senf::console::DirectoryNode::get(std::string const & name)
     const
 {
     ChildMap::const_iterator i (children_.find(name));
index 2881e56..f4fbc11 100644 (file)
@@ -45,7 +45,9 @@ prefix_ std::string const & senf::console::GenericNode::name()
 
 prefix_ senf::console::GenericNode::GenericNode(std::string const & name)
     : name_ (name), parent_ (0)
-{}
+{
+    ///\fixme Provide a default name if 'name' is empty ?
+}
 
 prefix_ void senf::console::GenericNode::name(std::string const & name)
 {
@@ -64,6 +66,17 @@ prefix_ boost::shared_ptr<senf::console::DirectoryNode> senf::console::GenericNo
         parent_ ? parent_->shared_from_this() : ptr() );
 }
 
+prefix_ senf::console::GenericNode::ptr senf::console::GenericNode::thisptr()
+{
+    return shared_from_this();
+}
+
+prefix_ senf::console::GenericNode::cptr senf::console::GenericNode::thisptr()
+    const
+{
+    return shared_from_this();
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::DirectoryNode
 
@@ -79,14 +92,14 @@ prefix_ senf::console::DirectoryNode &
 senf::console::DirectoryNode::operator[](std::string const & name)
     const
 {
-    return dynamic_cast<DirectoryNode&>(lookup(name));
+    return dynamic_cast<DirectoryNode&>(get(name));
 }
 
 prefix_ senf::console::CommandNode &
 senf::console::DirectoryNode::operator()(std::string const & name)
     const
 {
-    return dynamic_cast<CommandNode&>(lookup(name));
+    return dynamic_cast<CommandNode&>(get(name));
 }
 
 prefix_ senf::console::DirectoryNode &
@@ -106,6 +119,17 @@ prefix_ senf::console::DirectoryNode::DirectoryNode(std::string const & name)
     : GenericNode(name)
 {}
 
+prefix_ senf::console::DirectoryNode::ptr senf::console::DirectoryNode::thisptr()
+{
+    return boost::static_pointer_cast<DirectoryNode>(shared_from_this());
+}
+
+prefix_ senf::console::DirectoryNode::cptr senf::console::DirectoryNode::thisptr()
+    const
+{
+    return boost::static_pointer_cast<DirectoryNode const>(shared_from_this());
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::CommandNode
 
@@ -113,6 +137,17 @@ 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());
+}
+
+prefix_ senf::console::CommandNode::cptr senf::console::CommandNode::thisptr()
+    const
+{
+    return boost::static_pointer_cast<CommandNode const>(shared_from_this());
+}
+
 ///////////////////////////////cci.e///////////////////////////////////////
 #undef prefix_
 
diff --git a/Console/Node.ct b/Console/Node.ct
new file mode 100644 (file)
index 0000000..0a5a9c0
--- /dev/null
@@ -0,0 +1,84 @@
+// $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 non-inline template implementation  */
+
+//#include "Node.ih"
+
+// Custom includes
+#include <boost/range.hpp>
+
+#define prefix_
+///////////////////////////////ct.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::DirectoryNode
+
+template <class ForwardRange>
+prefix_ senf::console::GenericNode &
+senf::console::DirectoryNode::traverse(ForwardRange const & range)
+{
+    typedef typename boost::range_const_iterator<ForwardRange>::type const_iterator;
+    DirectoryNode::ptr dir (thisptr());
+    const_iterator i (boost::begin(range));
+    const_iterator const i_end (boost::end(range));
+    if (i != i_end && i->empty()) {
+        dir = root().thisptr();
+        ++ i;
+    }
+    while (i != i_end) {
+        const_iterator next_i (i);
+        ++ next_i;
+        if (*i == "..") {
+            dir = dir->parent();
+            if (! dir)
+                dir = root().thisptr();
+        }
+        else if (! i->empty()  && *i != ".") {
+            if (next_i == i_end)
+                return dir->get(*i);
+            else {
+                // Why does g++ give an error on this line ???? :
+                // dir = dynamic_cast<DirectoryNode&>( dir->get(*i) ).thisptr();
+                DirectoryNode & d (dynamic_cast<DirectoryNode&>( dir->get(*i) ));
+                dir = d.thisptr();
+            }
+        }
+        i = next_i;
+    }
+    return *dir;
+}
+
+///////////////////////////////ct.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 c2c8be5..79e5c1b 100644 (file)
@@ -54,6 +54,7 @@ namespace console {
         // Types
 
         typedef boost::shared_ptr<GenericNode> ptr;
+        typedef boost::shared_ptr<GenericNode const> cptr;
         typedef boost::weak_ptr<GenericNode> weak_ptr;
 
         ///////////////////////////////////////////////////////////////////////////
@@ -66,6 +67,9 @@ namespace console {
 
         std::string path() const;
 
+        ptr thisptr();
+        cptr thisptr() const;
+
     protected:
         explicit GenericNode(std::string const & name);
 
@@ -92,6 +96,7 @@ namespace console {
         // Types
 
         typedef boost::shared_ptr<DirectoryNode> ptr;
+        typedef boost::shared_ptr<DirectoryNode const> cptr;
         typedef boost::weak_ptr<DirectoryNode> weak_ptr;
 
         typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
@@ -103,17 +108,23 @@ namespace console {
 
         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);
         
         ChildrenRange children() const;
 
+        template <class ForwardRange>
+        GenericNode & traverse(ForwardRange const & range);
+
+        ptr thisptr();
+        cptr thisptr() const;
+
     protected:
         explicit DirectoryNode(std::string const & name);
 
     private:
         void add(GenericNode::ptr node, bool uniquify);
-        GenericNode & lookup(std::string const & name) const;
 
         ChildMap children_;
 
@@ -135,10 +146,14 @@ namespace console {
         // Types
 
         typedef boost::shared_ptr<CommandNode> ptr;
+        typedef boost::shared_ptr<CommandNode const> cptr;
         typedef boost::weak_ptr<CommandNode> weak_ptr;
 
         ///////////////////////////////////////////////////////////////////////////
 
+        ptr thisptr();
+        cptr thisptr() const;
+
     protected:
         explicit CommandNode(std::string const & name);
 
@@ -152,7 +167,7 @@ namespace console {
 
 ///////////////////////////////hh.e////////////////////////////////////////
 #include "Node.cci"
-//#include "Node.ct"
+#include "Node.ct"
 //#include "Node.cti"
 #endif
 
index 2f7c80d..9f7edf9 100644 (file)
@@ -280,9 +280,8 @@ namespace detail {
 
                 abspath
                     =    ch_p('/')                [ push_back_a(self.context.path, "") ]
-                      >> ! (    (   word          [ push_back_a(self.context.path) ] 
-                                  % ch_p('/') )
-                             >> ( ! ch_p('/')     [ push_back_a(self.context.path,"") ] ) )
+                      >> ( relpath
+                         | eps_p                  [ push_back_a(self.context.path, "") ] )
                     ;
 
                 balanced_tokens 
index 569a7cf..83f35b2 100644 (file)
@@ -126,10 +126,10 @@ prefix_ void senf::console::Client::clientData(ReadHelper<ClientHandle>::ptr hel
         return;
     }
 
-#   warning 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
+    ///\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();