X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Console%2FExecutor.cc;h=d5f56fbdc535b67c70a73494e67100e9e1efb8cb;hb=9e7071473642404359c8b7a88c78fe02f00baf16;hp=82033483b84565674fe0b9fc6e44dad6789d216f;hpb=d620e7ff9b68377ea20ca266c23cc3f05781868c;p=senf.git diff --git a/Console/Executor.cc b/Console/Executor.cc index 8203348..d5f56fb 100644 --- a/Console/Executor.cc +++ b/Console/Executor.cc @@ -27,22 +27,272 @@ //#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) { -# warning Implement Executor::operator() SENF_LOG(( "Executing: " << command )); - if (command.builtin() == ParseCommandInfo::BuiltinEXIT) - throw ExitException(); - return true; + + 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; + + } + } + catch (InvalidPathException &) { + throw SyntaxErrorException("invalid path"); + } + catch (InvalidDirectoryException &) { + throw SyntaxErrorException("invalid directory"); + } + catch (InvalidCommandException &) { + throw SyntaxErrorException("invalid command"); + } + 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 { + 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 == 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 (UnknownNodeNameException &) { + throw InvalidDirectoryException(); + } } ///////////////////////////////cc.e////////////////////////////////////////