Skip to content
Snippets Groups Projects
Commit 8ee4c7f7 authored by g0dil's avatar g0dil
Browse files

Console: Replace Executor cwd handling with explicit path handling

parent 5ee27130
No related branches found
No related tags found
No related merge requests found
......@@ -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();
}
}
......
......@@ -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_
......
// $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_
// 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:
......@@ -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
......
......@@ -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
......
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment