Skip to content
Snippets Groups Projects
Commit 3a9ea35e authored by g0dil's avatar g0dil
Browse files

Console: Factored out path traversal into generic traversal helper

parent 30c616e6
No related branches found
No related tags found
No related merge requests found
......@@ -32,6 +32,17 @@
#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////////////////////////////////////////
......
......@@ -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_;
......
......@@ -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));
......
......@@ -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_
......
// $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_
// 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:
......@@ -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
......
......@@ -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
......
......@@ -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();
......
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