From: g0dil Date: Tue, 20 May 2008 15:38:06 +0000 (+0000) Subject: Console: Replace Executor cwd handling with explicit path handling X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=d3607ce23b75abc46b387fccabe591c989f5daf0;p=senf.git Console: Replace Executor cwd handling with explicit path handling git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@850 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Console/Executor.cc b/Console/Executor.cc index fc0327d..d40f69d 100644 --- a/Console/Executor.cc +++ b/Console/Executor.cc @@ -27,6 +27,8 @@ //#include "Executor.ih" // Custom includes +#include +#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(&node) ); - if ( dir ) { - if (autocd_ && command.tokens().empty()) { - oldCwd_ = cwd_; - cwd_ = dir->thisptr(); - } else - throw InvalidCommandException(); - } else { - dynamic_cast(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(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(&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(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(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( 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(); } } diff --git a/Console/Executor.cci b/Console/Executor.cci index ab91c30..81df7ed 100644 --- a/Console/Executor.cci +++ b/Console/Executor.cci @@ -34,9 +34,11 @@ // 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 index 4123d85..0000000 --- a/Console/Executor.ct +++ /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 -// -// 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 -prefix_ senf::console::GenericNode & -senf::console::Executor::traverse(DirectoryNode & dir, ForwardRange const & range) -{ - typedef typename boost::range_const_iterator::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(traverser.node()), *i ); - traverser( *i ); - } - return traverser.node(); -} - -///////////////////////////////ct.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/Executor.hh b/Console/Executor.hh index 5f1cc46..f771e3b 100644 --- a/Console/Executor.hh +++ b/Console/Executor.hh @@ -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 Path; + + void exec(std::ostream & output, ParseCommandInfo const & command); - template - 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 DirStack; + mutable Path cwd_; + Path oldCwd_; + + typedef std::vector DirStack; DirStack dirstack_; bool autocd_; bool autocomplete_; - - bool skipping_; }; - }} ///////////////////////////////hh.e//////////////////////////////////////// #include "Executor.cci" -#include "Executor.ct" +//#include "Executor.ct" //#include "Executor.cti" #endif diff --git a/Console/Parse.cci b/Console/Parse.cci index 74b54f3..0482101 100644 --- a/Console/Parse.cci +++ b/Console/Parse.cci @@ -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 diff --git a/Console/Parse.hh b/Console/Parse.hh index a40bd74..8c38dae 100644 --- a/Console/Parse.hh +++ b/Console/Parse.hh @@ -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