X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Console%2FExecutor.cc;h=d5f56fbdc535b67c70a73494e67100e9e1efb8cb;hb=9e7071473642404359c8b7a88c78fe02f00baf16;hp=71c3f786a6e8cb5f411d7ef53ec7ebd194738c22;hpb=5e9e6057a4e5c1241ff3f1b75b0f797eb570725d;p=senf.git diff --git a/Console/Executor.cc b/Console/Executor.cc index 71c3f78..d5f56fb 100644 --- a/Console/Executor.cc +++ b/Console/Executor.cc @@ -27,92 +27,274 @@ //#include "Executor.ih" // Custom includes +#include +#include +#include +#include "../Utils/senfassert.hh" +#include "../Utils/Range.hh" +#include "../Utils/String.hh" //#include "Executor.mpp" #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// +namespace { + + struct TraverseTokens { + typedef std::string const & result_type; + result_type operator()(senf::console::Token const & token) const { + return token.value(); + } + }; + +} + /////////////////////////////////////////////////////////////////////////// // senf::console::Executor -prefix_ bool senf::console::Executor::operator()(ParseCommandInfo const & command, - std::ostream & output) +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_ std::string senf::console::Executor::cwdPath() + const +{ + if (skipping()) + return ""; + return "/" + senf::stringJoin( + senf::make_transform_range( + boost::make_iterator_range(boost::next(cwd_.begin()), cwd_.end()), + boost::bind(&DirectoryNode::name, boost::bind(&DirectoryNode::weak_ptr::lock, _1))), + "/" ); +} + +prefix_ void senf::console::Executor::execute(std::ostream & output, + ParseCommandInfo const & command) { SENF_LOG(( "Executing: " << command )); - if (cwd_.expired()) - cwd_ = boost::static_pointer_cast( - root().shared_from_this()); - - switch(command.builtin()) { - case ParseCommandInfo::NoBuiltin : - break; - - 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 << "\n"; - 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(); + if (! skipping()) + (void) cwd(); // Prune the cwd path of expired entries + + try { + switch(command.builtin()) { + case ParseCommandInfo::NoBuiltin : + if (skipping()) + return; + exec(output, command); + break; + + case ParseCommandInfo::BuiltinCD : + if (skipping()) + break; + try { + // The parser ensures, we have exactly one argument + cd(*command.arguments().begin()); + } + catch (IgnoreCommandException &) { + throw SyntaxErrorException( + "'cd' cannot be skipped (don't use 'cd' in conf-files)"); + } + break; + + case ParseCommandInfo::BuiltinLS : + if (skipping()) + break; + // The parser ensures, we have either one or no argument + ls( output, + command.tokens().empty() ? command.tokens() : *command.arguments().begin() ); + break; + + case ParseCommandInfo::BuiltinPUSHD : + // The parser ensures, we have exactly one argument + pushd( *command.arguments().begin() ); + break; + + case ParseCommandInfo::BuiltinPOPD : + // The parser ensures, we have no arguments + popd(); + break; + + case ParseCommandInfo::BuiltinEXIT : + if (skipping()) + break; + // The parser ensures, we have no arguments + exit(); + break; + + case ParseCommandInfo::BuiltinHELP : + if (skipping()) + break; + // The parser ensures, we have either one or no arguments + help( output, + command.tokens().empty() ? command.tokens() : *command.arguments().begin() ); + break; + } - break; + } + catch (InvalidPathException &) { + throw SyntaxErrorException("invalid path"); + } + catch (InvalidDirectoryException &) { + throw SyntaxErrorException("invalid directory"); + } + catch (InvalidCommandException &) { + throw SyntaxErrorException("invalid command"); + } + catch (IgnoreCommandException &) {} +} - case ParseCommandInfo::BuiltinEXIT : - throw ExitException(); +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); } - return true; } -prefix_ bool senf::console::Executor::chdir(ParseCommandInfo::argument_value_type const & path) + +prefix_ void senf::console::Executor::cd(ParseCommandInfo::TokensRange dir) { - 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; + 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 { + 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_ void +senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange const & path, + Path & dir) +{ + try { + ParseCommandInfo::TokensRange::const_iterator i (path.begin()); + ParseCommandInfo::TokensRange::const_iterator const i_end (path.end()); for (; i != i_end; ++i) { - if (i->value() == "..") { - dir = dir->parent(); - if (! dir) - dir = boost::static_pointer_cast( - root().shared_from_this()); + 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()); } - else if (! i->value().empty() && i->value() != ".") - dir = boost::static_pointer_cast( - (*dir)[i->value()].shared_from_this()); } - cwd_ = dir; } catch (std::bad_cast &) { - return false; + throw InvalidDirectoryException(); } catch (UnknownNodeNameException &) { - return false; + throw InvalidDirectoryException(); } - return true; } - + ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ //#include "Executor.mpp"