From: g0dil Date: Sun, 23 Mar 2008 23:48:04 +0000 (+0000) Subject: Console: Factored out path traversal into generic traversal helper X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=70905bebad1f8c394fceb3a5d2a493eeecf3bd13;p=senf.git Console: Factored out path traversal into generic traversal helper git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@759 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Console/Executor.cc b/Console/Executor.cc index 43fc6d2..6070184 100644 --- a/Console/Executor.cc +++ b/Console/Executor.cc @@ -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( - 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(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( - root().shared_from_this()); - } else - swap(cwd_, oldCwd_); + try { + return dynamic_cast( + 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( - root().shared_from_this()); - ++ i; - } - for (; i != i_end; ++i) { - if (i->value() == "..") { - dir = dir->parent(); - if (! dir) - dir = boost::static_pointer_cast( - root().shared_from_this()); - } - else if (! i->value().empty() && i->value() != ".") - dir = boost::static_pointer_cast( - (*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//////////////////////////////////////// diff --git a/Console/Executor.hh b/Console/Executor.hh index bc3ce99..658cc99 100644 --- a/Console/Executor.hh +++ b/Console/Executor.hh @@ -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_; diff --git a/Console/Node.cc b/Console/Node.cc index 90518b0..382804f 100644 --- a/Console/Node.cc +++ b/Console/Node.cc @@ -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)); diff --git a/Console/Node.cci b/Console/Node.cci index 2881e56..f4fbc11 100644 --- a/Console/Node.cci +++ b/Console/Node.cci @@ -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::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(lookup(name)); + return dynamic_cast(get(name)); } prefix_ senf::console::CommandNode & senf::console::DirectoryNode::operator()(std::string const & name) const { - return dynamic_cast(lookup(name)); + return dynamic_cast(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(shared_from_this()); +} + +prefix_ senf::console::DirectoryNode::cptr senf::console::DirectoryNode::thisptr() + const +{ + return boost::static_pointer_cast(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(shared_from_this()); +} + +prefix_ senf::console::CommandNode::cptr senf::console::CommandNode::thisptr() + const +{ + return boost::static_pointer_cast(shared_from_this()); +} + ///////////////////////////////cci.e/////////////////////////////////////// #undef prefix_ diff --git a/Console/Node.ct b/Console/Node.ct new file mode 100644 index 0000000..0a5a9c0 --- /dev/null +++ b/Console/Node.ct @@ -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 +// +// 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 + +#define prefix_ +///////////////////////////////ct.p//////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::console::DirectoryNode + +template +prefix_ senf::console::GenericNode & +senf::console::DirectoryNode::traverse(ForwardRange const & range) +{ + typedef typename boost::range_const_iterator::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( dir->get(*i) ).thisptr(); + DirectoryNode & d (dynamic_cast( 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: diff --git a/Console/Node.hh b/Console/Node.hh index c2c8be5..79e5c1b 100644 --- a/Console/Node.hh +++ b/Console/Node.hh @@ -54,6 +54,7 @@ namespace console { // Types typedef boost::shared_ptr ptr; + typedef boost::shared_ptr cptr; typedef boost::weak_ptr 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 ptr; + typedef boost::shared_ptr cptr; typedef boost::weak_ptr weak_ptr; typedef boost::iterator_range 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 + 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 ptr; + typedef boost::shared_ptr cptr; typedef boost::weak_ptr 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 diff --git a/Console/Parse.ih b/Console/Parse.ih index 2f7c80d..9f7edf9 100644 --- a/Console/Parse.ih +++ b/Console/Parse.ih @@ -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 diff --git a/Console/Server.cc b/Console/Server.cc index 569a7cf..83f35b2 100644 --- a/Console/Server.cc +++ b/Console/Server.cc @@ -126,10 +126,10 @@ prefix_ void senf::console::Client::clientData(ReadHelper::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();