Console: Replace Executor cwd handling with explicit path handling
g0dil [Tue, 20 May 2008 15:38:06 +0000 (15:38 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@850 270642c3-0616-0410-b53a-bc976706d245

Console/Executor.cc
Console/Executor.cci
Console/Executor.ct [deleted file]
Console/Executor.hh
Console/Parse.cci
Console/Parse.hh

index fc0327d..d40f69d 100644 (file)
@@ -27,6 +27,8 @@
 //#include "Executor.ih"
 
 // Custom includes
+#include <boost/utility.hpp>
+#include "../Utils/senfassert.hh"
 
 //#include "Executor.mpp"
 #define prefix_
@@ -46,51 +48,37 @@ namespace {
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::Executor
 
+prefix_ senf::console::DirectoryNode & senf::console::Executor::cwd()
+    const
+{
+    SENF_ASSERT( ! cwd_.empty() );
+    while (cwd_.size()>1 && (cwd_.back().expired() || ! cwd_.back().lock()->active()))
+        cwd_.pop_back();
+    return * cwd_.back().lock();
+}
+
 prefix_ void senf::console::Executor::execute(std::ostream & output,
                                               ParseCommandInfo const & command)
 {
     SENF_LOG(( "Executing: " << command ));
 
-    if (cwd_.expired() || ! cwd().active())
-        cwd_ = root_;
+    if (! skipping())
+        (void) cwd(); // Prune the cwd path of expired entries
 
     try {
         switch(command.builtin()) {
-        case ParseCommandInfo::NoBuiltin : {
-            if (skipping_)
-                break;
-            GenericNode & node ( traverseNode(command.commandPath()) );
-            DirectoryNode * dir ( dynamic_cast<DirectoryNode*>(&node) );
-            if ( dir ) {
-                if (autocd_ && command.tokens().empty()) {
-                    oldCwd_ = cwd_;
-                    cwd_ = dir->thisptr();
-                } else
-                    throw InvalidCommandException();
-            } else {
-                dynamic_cast<CommandNode &>(node)(output, command);
-            }
+        case ParseCommandInfo::NoBuiltin : 
+            if (skipping())
+                return;
+            exec(output, command);
             break;
-        }
 
         case ParseCommandInfo::BuiltinCD :
-            if (skipping_)
+            if (skipping())
                 break;
             try {
-                if ( command.arguments() ) {
-                    if (command.arguments().begin()->size() == 1 
-                        && command.arguments().begin()->begin()->value() == "-") {
-                        if (oldCwd_.expired() || ! oldCwd_.lock()->active()) {
-                            oldCwd_ = cwd_;
-                            cwd_ = root_;
-                        } else
-                            swap(cwd_, oldCwd_);
-                    }
-                    else {
-                        oldCwd_ = cwd_;
-                    cwd_ = traverseDirectory(*command.arguments().begin()).thisptr();
-                    }
-                }
+                // The parser ensures, we have exactly one argument
+                cd(*command.arguments().begin());
             }
             catch (IgnoreCommandException &) {
                 throw SyntaxErrorException(
@@ -98,57 +86,37 @@ prefix_ void senf::console::Executor::execute(std::ostream & output,
             }
             break;
             
-        case ParseCommandInfo::BuiltinLS : {
-            if (skipping_)
+        case ParseCommandInfo::BuiltinLS :
+            if (skipping())
                 break;
-            DirectoryNode const & dir ( command.arguments()
-                                        ? traverseDirectory(*command.arguments().begin())
-                                        : cwd() );
-            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";
-            }
+            // The parser ensures, we have either one or no argument
+            ls( output,
+                command.tokens().empty() ? command.tokens() : *command.arguments().begin() );
             break;
-        }
 
         case ParseCommandInfo::BuiltinPUSHD :
-            dirstack_.push_back(DirEntry(cwd_, skipping_));
-            if ( ! skipping_ && command.arguments() ) {
-                try {
-                    cwd_ = traverseDirectory(*command.arguments().begin()).thisptr();
-                }
-                catch (IgnoreCommandException &) {
-                    cwd_.reset();
-                    skipping_ = true;
-                }
-            }
+            // The parser ensures, we have exactly one argument
+            pushd( *command.arguments().begin() );
             break;
             
         case ParseCommandInfo::BuiltinPOPD :
-            if (! dirstack_.empty()) {
-                cwd_ = dirstack_.back().dir;
-                skipping_ = dirstack_.back().skip;
-                dirstack_.pop_back();
-            }
+            // The parser ensures, we have no arguments
+            popd();
             break;
             
         case ParseCommandInfo::BuiltinEXIT :
-            if (skipping_)
+            if (skipping())
                 break;
-            throw ExitException();
+            // The parser ensures, we have no arguments
+            exit();
+            break;
 
         case ParseCommandInfo::BuiltinHELP :
-            if (skipping_)
+            if (skipping())
                 break;
-            GenericNode const & node (command.arguments() 
-                                      ? traverseNode(*command.arguments().begin())
-                                      : cwd());
-            output << prettyName(typeid(node)) << " at " << node.path() << "\n\n";
-            node.help(output);
-            output << std::flush;
+            // The parser ensures, we have either one or no arguments
+            help( output,
+                  command.tokens().empty() ? command.tokens() : *command.arguments().begin() );
             break;
 
         }
@@ -165,34 +133,148 @@ prefix_ void senf::console::Executor::execute(std::ostream & output,
     catch (IgnoreCommandException &) {}
 }
 
+prefix_ void senf::console::Executor::exec(std::ostream & output,
+                                           ParseCommandInfo const & command)
+{
+    GenericNode & node ( traverseNode(command.commandPath()) );
+    DirectoryNode * dir ( dynamic_cast<DirectoryNode*>(&node) );
+    if ( dir ) {
+        if (autocd_ && command.tokens().empty()) {
+            cd( boost::make_iterator_range(
+                    command.commandPath().begin(),
+                    command.commandPath().end()) );
+        } else
+            throw InvalidCommandException();
+    } else {
+        dynamic_cast<CommandNode &>(node)(output, command);
+    }
+}
+
+
+prefix_ void senf::console::Executor::cd(ParseCommandInfo::TokensRange dir)
+{
+    if (dir.size() == 1 && *dir.begin() == WordToken("-")) {
+        cwd_.swap(oldCwd_);
+        (void) cwd(); // Prune any expired items
+    }
+    else {
+        // We need to use a temporary so an error somewhere while traversing the dir does not cause
+        // the current directory to change.
+        Path newDir (cwd_);
+        traverseDirectory(dir, newDir);
+        oldCwd_.swap(cwd_);
+        cwd_.swap(newDir);
+    }
+}
+
+prefix_ void senf::console::Executor::ls(std::ostream & output,
+                                         ParseCommandInfo::TokensRange path)
+{
+    Path dir (cwd_);
+    traverseDirectory(path, dir);
+    DirectoryNode & node (*dir.back().lock());
+    DirectoryNode::child_iterator i (node.children().begin());
+    DirectoryNode::child_iterator const i_end (node.children().end());
+    for (; i != i_end; ++i) {
+        output << i->first;
+        if (boost::dynamic_pointer_cast<DirectoryNode>(i->second))
+            output << "/";
+        output << "\n";
+    }
+}
+
+prefix_ void senf::console::Executor::pushd(ParseCommandInfo::TokensRange dir)
+{
+    Path newDir (cwd_);
+    if (! skipping()) {
+        try {
+            traverseDirectory(dir, newDir);
+        }
+        catch (IgnoreCommandException &) {
+            newDir.clear();
+        }
+    }
+    dirstack_.push_back(Path());
+    dirstack_.back().swap(cwd_);
+    cwd_.swap(newDir);
+}
+
+prefix_ void senf::console::Executor::popd()
+{
+    if (! dirstack_.empty()) {
+        cwd_.swap(dirstack_.back());
+        dirstack_.pop_back();
+    }
+}
+
+prefix_ void senf::console::Executor::exit()
+{
+    throw ExitException();
+}
+
+prefix_ void senf::console::Executor::help(std::ostream & output,
+                                           ParseCommandInfo::TokensRange path)
+{
+    GenericNode const & node (traverseNode(path));
+    output << prettyName(typeid(node)) << " at " << node.path() << "\n\n";
+    node.help(output);
+    output << std::flush;
+}
+
 prefix_ senf::console::GenericNode &
 senf::console::Executor::traverseNode(ParseCommandInfo::TokensRange const & path)
 {
+    if (path.empty())
+        return *cwd_.back().lock();
     try {
-        return traverse(
-            cwd(),
-            boost::make_iterator_range(
-                boost::make_transform_iterator(path.begin(), TraverseTokens()),
-                boost::make_transform_iterator(path.end(), TraverseTokens())) );
-    }
-    catch (std::bad_cast &) {
-        throw InvalidPathException();
+        Path dir (cwd_);
+        traverseDirectory(boost::make_iterator_range(
+                              path.begin(),
+                              boost::prior(path.end())),
+                          dir);
+        DirectoryNode & base (*dir.back().lock());
+        std::string const & name (boost::prior(path.end())->value());
+        if (policy_)
+            policy_( base, name );
+        return dir.back().lock()->get(name);
     }
     catch (UnknownNodeNameException &) {
         throw InvalidPathException();
     }
 }
 
-prefix_ senf::console::DirectoryNode &
-senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange const & path)
+prefix_ void
+senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange const & path,
+                                           Path & dir)
 {
     try {
-        return dynamic_cast<DirectoryNode&>( traverseNode(path) );
+        ParseCommandInfo::TokensRange::const_iterator i (path.begin());
+        ParseCommandInfo::TokensRange::const_iterator const i_end (path.end());
+        for (; i != i_end; ++i) {
+            if (*i == NoneToken()) {
+                if (i == path.begin()) {
+                    dir.clear();
+                    dir.push_back(root_);
+                }
+            }
+            else if (*i == WordToken("..")) {
+                if (dir.size() > 1)
+                    dir.pop_back();
+            }
+            else if (*i ==  WordToken("."))
+                ;
+            else {
+                DirectoryNode & base (*dir.back().lock());
+                if (policy_)
+                    policy_( base, i->value() );
+                dir.push_back(base[i->value()].thisptr());
+            }
+        }
     }
     catch (std::bad_cast &) {
         throw InvalidDirectoryException();
     }
-    catch (InvalidPathException &) {
+    catch (UnknownNodeNameException &) {
         throw InvalidDirectoryException();
     }
 }
index ab91c30..81df7ed 100644 (file)
 // senf::console::Executor
 
 prefix_ senf::console::Executor::Executor()
-    : root_(senf::console::root().thisptr()), cwd_ (root_), oldCwd_ (cwd_),
-      autocd_ (false), autocomplete_ (false), skipping_ (false)
-{}
+    : root_(senf::console::root().thisptr()), cwd_ (), oldCwd_ (),
+      autocd_ (false), autocomplete_ (false)
+{
+    cwd_.push_back(root_);
+}
 
 prefix_ void senf::console::Executor::operator()(std::ostream & output,
                                                  ParseCommandInfo const & command)
@@ -44,12 +46,6 @@ prefix_ void senf::console::Executor::operator()(std::ostream & output,
     return execute(output, command);
 }
 
-prefix_ senf::console::DirectoryNode & senf::console::Executor::cwd()
-    const
-{
-    return cwd_.expired() ? root() : *cwd_.lock();
-}
-
 prefix_ bool senf::console::Executor::autocd()
     const
 {
@@ -83,8 +79,9 @@ prefix_ senf::console::DirectoryNode & senf::console::Executor::chroot()
 prefix_ senf::console::Executor & senf::console::Executor::chroot(DirectoryNode & node)
 {
     root_ = node.thisptr();
-    cwd_ = root_;
-    oldCwd_ = root_;
+    cwd_.clear();
+    cwd_.push_back(root_);
+    oldCwd_ = cwd_;
     return *this;
 }
 
@@ -94,6 +91,12 @@ prefix_ senf::console::Executor & senf::console::Executor::policy(SecurityPolicy
     return *this;
 }
 
+prefix_ bool senf::console::Executor::skipping()
+    const
+{
+    return cwd_.empty();
+}
+
 ///////////////////////////////cci.e///////////////////////////////////////
 #undef prefix_
 
diff --git a/Console/Executor.ct b/Console/Executor.ct
deleted file mode 100644 (file)
index 4123d85..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-// $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 Executor non-inline template implementation  */
-
-//#include "Executor.ih"
-
-// Custom includes
-
-#define prefix_
-///////////////////////////////ct.p////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// senf::console::Executor
-
-template <class ForwardRange>
-prefix_ senf::console::GenericNode &
-senf::console::Executor::traverse(DirectoryNode & dir, ForwardRange const & range)
-{
-    typedef typename boost::range_const_iterator<ForwardRange>::type const_iterator;
-    detail::NodeTraverser traverser (*root_, dir, autocomplete_);
-    const_iterator i (boost::begin(range));
-    const_iterator const i_end (boost::end(range));
-    for (; i != i_end; ++i) {
-        if ( policy_ && (*i) != std::string("") && (*i) != std::string(".") )
-            policy_( dynamic_cast<DirectoryNode &>(traverser.node()), *i );
-        traverser( *i );
-    }
-    return traverser.node();
-}
-
-///////////////////////////////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 5f1cc46..f771e3b 100644 (file)
@@ -91,6 +91,7 @@ namespace console {
                                         /**< Output will be written to \a output. 
                                              Same as execute(). */
         DirectoryNode & cwd() const;    ///< Current working directory
+        bool skipping() const;
 
         bool autocd() const;            ///< Get current autocd status
                                         /**< if autocd is enabled, specifying a directory name as
@@ -127,11 +128,20 @@ namespace console {
     protected:
 
     private:
-        GenericNode & traverseNode(ParseCommandInfo::TokensRange const & path);
-        DirectoryNode & traverseDirectory(ParseCommandInfo::TokensRange const & path);
+        typedef std::vector<DirectoryNode::weak_ptr> Path;
+
+        void exec(std::ostream & output, ParseCommandInfo const & command);
 
-        template <class ForwardRange>
-        GenericNode & traverse(DirectoryNode & dir, ForwardRange const & range);
+        void cd(ParseCommandInfo::TokensRange dir);
+        void ls(std::ostream & output, ParseCommandInfo::TokensRange dir);
+        void pushd(ParseCommandInfo::TokensRange dir);
+        void popd();
+        void exit();
+        void help(std::ostream & output, ParseCommandInfo::TokensRange path);
+
+        GenericNode & traverseNode(ParseCommandInfo::TokensRange const & path);
+        void traverseDirectory(ParseCommandInfo::TokensRange const & path,
+                               Path & dir);
 
         struct InvalidPathException {};
         struct InvalidDirectoryException {};
@@ -139,28 +149,21 @@ namespace console {
         
         DirectoryNode::ptr root_;
         SecurityPolicy policy_;
-        DirectoryNode::weak_ptr cwd_;
-        DirectoryNode::weak_ptr oldCwd_;
-        struct DirEntry {
-            DirEntry(DirectoryNode::weak_ptr dir_, bool skip_) : dir(dir_), skip(skip_) {}
-            DirectoryNode::weak_ptr dir;
-            bool skip;
-        };
-        typedef std::vector<DirEntry> DirStack;
+        mutable Path cwd_;
+        Path oldCwd_;
+
+        typedef std::vector<Path> DirStack;
         DirStack dirstack_;
 
         bool autocd_;
         bool autocomplete_;
-        
-        bool skipping_;
     };
 
-
 }}
 
 ///////////////////////////////hh.e////////////////////////////////////////
 #include "Executor.cci"
-#include "Executor.ct"
+//#include "Executor.ct"
 //#include "Executor.cti"
 #endif
 
index 74b54f3..0482101 100644 (file)
@@ -73,6 +73,61 @@ prefix_ senf::console::Token::Token(TokenType type, std::string token)
     : type_(type), token_ (token)
 {}
 
+prefix_ senf::console::Token senf::console::NoneToken()
+{
+    return Token(Token::None,"");
+}
+
+prefix_ senf::console::Token senf::console::PathSeparatorToken()
+{
+    return Token(Token::PathSeparator,"/");
+}
+
+prefix_ senf::console::Token senf::console::ArgumentGroupOpenToken()
+{
+    return Token(Token::ArgumentGroupOpen,"(");
+}
+
+prefix_ senf::console::Token senf::console::ArgumentGroupCloseToken()
+{
+    return Token(Token::ArgumentGroupClose,")");
+}
+
+prefix_ senf::console::Token senf::console::DirectoryGroupOpenToken()
+{
+    return Token(Token::DirectoryGroupOpen,"{");
+}
+
+prefix_ senf::console::Token senf::console::DirectoryGroupCloseToken()
+{
+    return Token(Token::DirectoryGroupClose,"}");
+}
+
+prefix_ senf::console::Token senf::console::CommandTerminatorToken()
+{
+    return Token(Token::CommandTerminator,";");
+}
+
+prefix_ senf::console::Token senf::console::OtherPunctuationToken(std::string const & value)
+{
+    return Token(Token::OtherPunctuation, value);
+}
+
+prefix_ senf::console::Token senf::console::BasicStringToken(std::string const & value)
+{
+    return Token(Token::BasicString, value);
+}
+
+prefix_ senf::console::Token senf::console::HexStringToken(std::string const & value)
+{
+    return Token(Token::HexString, value);
+}
+
+prefix_ senf::console::Token senf::console::WordToken(std::string const & value)
+{
+    return Token(Token::Word, value);
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::ParseCommandInfo
 
index a40bd74..8c38dae 100644 (file)
@@ -274,6 +274,19 @@ namespace console {
 
     std::ostream & operator<<(std::ostream & os, Token const & token);
 
+    
+    Token NoneToken();
+    Token PathSeparatorToken();
+    Token ArgumentGroupOpenToken();
+    Token ArgumentGroupCloseToken();
+    Token DirectoryGroupOpenToken();
+    Token DirectoryGroupCloseToken();
+    Token CommandTerminatorToken();
+    Token OtherPunctuationToken(std::string const & value);
+    Token BasicStringToken(std::string const & value);
+    Token HexStringToken(std::string const & value);
+    Token WordToken(std::string const & value);
+
     /** \brief Single parsed console command
 
         Every command parsed is returned in a ParseCommandInfo instance. This information is purely