X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Console%2FExecutor.cc;h=d5f56fbdc535b67c70a73494e67100e9e1efb8cb;hb=9e7071473642404359c8b7a88c78fe02f00baf16;hp=517c46cdec141055e03122ff0714be039d0afa79;hpb=c70f7413515b513656f850f51a3cc2ea9d776a37;p=senf.git diff --git a/Console/Executor.cc b/Console/Executor.cc index 517c46c..d5f56fb 100644 --- a/Console/Executor.cc +++ b/Console/Executor.cc @@ -27,6 +27,12 @@ //#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_ @@ -36,7 +42,7 @@ namespace { struct TraverseTokens { typedef std::string const & result_type; - result_type operator()(senf::console::ArgumentToken const & token) const { + result_type operator()(senf::console::Token const & token) const { return token.value(); } }; @@ -46,134 +52,249 @@ namespace { /////////////////////////////////////////////////////////////////////////// // senf::console::Executor -prefix_ void 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().active()) - cwd_ = root().thisptr(); + if (! skipping()) + (void) cwd(); // Prune the cwd path of expired entries try { switch(command.builtin()) { - case ParseCommandInfo::NoBuiltin : - traverseCommand(command.commandPath())(output, command.arguments()); + case ParseCommandInfo::NoBuiltin : + if (skipping()) + return; + exec(output, command); break; case ParseCommandInfo::BuiltinCD : - if ( command.arguments() ) { - if (command.arguments().begin()->size() == 1 - && command.arguments().begin()->begin()->value() == "-") { - if (oldCwd_.expired() || ! oldCwd_.lock()->active()) { - oldCwd_ = cwd_; - cwd_ = root().thisptr(); - } else - swap(cwd_, oldCwd_); - } - else { - oldCwd_ = cwd_; - cwd_ = traverseDirectory(command.arguments().begin()[0]).thisptr(); - } + 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 : { - DirectoryNode const & dir ( command.arguments() - ? traverseDirectory(command.arguments().begin()[0]) - : cwd() ); - 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"; - } + 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 : - dirstack_.push_back(cwd_); - if ( command.arguments() ) - cwd_ = traverseDirectory(command.arguments().begin()[0]).thisptr(); + // The parser ensures, we have exactly one argument + pushd( *command.arguments().begin() ); break; case ParseCommandInfo::BuiltinPOPD : - if (! dirstack_.empty()) { - cwd_ = dirstack_.back(); - dirstack_.pop_back(); - } + // The parser ensures, we have no arguments + popd(); break; case ParseCommandInfo::BuiltinEXIT : - throw ExitException(); + if (skipping()) + break; + // The parser ensures, we have no arguments + exit(); + break; case ParseCommandInfo::BuiltinHELP : - GenericNode const & node (command.arguments() - ? traverseNode(command.arguments().begin()[0]) - : cwd()); - output << prettyName(typeid(node)) << " at " << node.path() << "\n\n"; - node.help(output); - output << std::flush; + 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 &) { - output << "invalid path" << std::endl; + throw SyntaxErrorException("invalid path"); } catch (InvalidDirectoryException &) { - output << "invalid directory" << std::endl; + throw SyntaxErrorException("invalid directory"); } catch (InvalidCommandException &) { - output << "invalid command" << std::endl; + throw SyntaxErrorException("invalid command"); } + catch (IgnoreCommandException &) {} } -prefix_ senf::console::GenericNode & -senf::console::Executor::traverseNode(ParseCommandInfo::argument_value_type const & path) +prefix_ void senf::console::Executor::exec(std::ostream & output, + ParseCommandInfo const & command) { - try { - return cwd().traverse( - boost::make_iterator_range( - boost::make_transform_iterator(path.begin(), TraverseTokens()), - boost::make_transform_iterator(path.end(), TraverseTokens()))); + 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); } - catch (std::bad_cast &) { - throw InvalidPathException(); +} + + +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 } - catch (UnknownNodeNameException &) { - throw InvalidPathException(); + 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_ senf::console::DirectoryNode & -senf::console::Executor::traverseDirectory(ParseCommandInfo::argument_value_type const & path) +prefix_ void senf::console::Executor::ls(std::ostream & output, + ParseCommandInfo::TokensRange path) { - try { - return dynamic_cast( traverseNode(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"; } - catch (std::bad_cast &) { - throw InvalidDirectoryException(); +} + +prefix_ void senf::console::Executor::pushd(ParseCommandInfo::TokensRange dir) +{ + Path newDir (cwd_); + if (! skipping()) { + try { + traverseDirectory(dir, newDir); + } + catch (IgnoreCommandException &) { + newDir.clear(); + } } - catch (InvalidPathException &) { - throw InvalidDirectoryException(); + 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_ senf::console::CommandNode & -senf::console::Executor::traverseCommand(ParseCommandInfo::CommandPathRange const & path) +prefix_ void +senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange const & path, + Path & dir) { try { - return dynamic_cast( cwd().traverse(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 InvalidCommandException(); + throw InvalidDirectoryException(); } catch (UnknownNodeNameException &) { - throw InvalidCommandException(); - } + throw InvalidDirectoryException(); + } } - + ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ //#include "Executor.mpp"