#include <boost/utility.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/bind.hpp>
+#include <boost/format.hpp>
#include "../../Utils/senfassert.hh"
#include "../../Utils/Range.hh"
#include "../../Utils/String.hh"
#include "../../Utils/range.hh"
+#include "Server.hh"
//#include "Executor.mpp"
#define prefix_
namespace {
- struct TraverseTokens {
+ struct TraversTokens {
typedef std::string const & result_type;
result_type operator()(senf::console::Token const & token) const {
return token.value();
{
if (skipping())
return "";
+ (void) cwd(); // ensure, cwd is live.
return "/" + senf::stringJoin(
senf::make_transform_range(
boost::make_iterator_range(boost::next(cwd_.begin()), cwd_.end()),
break;
try {
// The parser ensures, we have exactly one argument
- cd(*command.arguments().begin());
+ cd(command.commandPath());
}
catch (IgnoreCommandException &) {
throw SyntaxErrorException(
if (skipping())
break;
// The parser ensures, we have either one or no argument
- ls( output,
- command.tokens().empty() ? command.tokens() : *command.arguments().begin() );
+ ls( output, command.commandPath() );
+ break;
+
+ case ParseCommandInfo::BuiltinLR :
+ if (skipping())
+ break;
+ // The parser ensures, we have either one or no argument
+ lr( output, command.commandPath() );
break;
case ParseCommandInfo::BuiltinPUSHD :
// The parser ensures, we have exactly one argument
- pushd( *command.arguments().begin() );
+ if (skipping())
+ pushd(command.commandPath());
+ else
+ exec(output, command);
break;
case ParseCommandInfo::BuiltinPOPD :
if (skipping())
break;
// The parser ensures, we have either one or no arguments
- help( output,
- command.tokens().empty() ? command.tokens() : *command.arguments().begin() );
+ help( output, command.commandPath() );
break;
}
}
- catch (InvalidPathException &) {
- throw SyntaxErrorException("invalid path");
+ catch (InvalidPathException & ex) {
+ throw SyntaxErrorException("invalid path") << " '" << ex.path << "'";
}
- catch (InvalidDirectoryException &) {
- throw SyntaxErrorException("invalid directory");
+ catch (InvalidDirectoryException & ex) {
+ throw SyntaxErrorException("invalid directory") << " '" << ex.path << "'";
}
catch (InvalidCommandException &) {
throw SyntaxErrorException("invalid command");
catch (IgnoreCommandException &) {}
}
+prefix_ senf::console::GenericNode &
+senf::console::Executor::getNode(ParseCommandInfo const & command)
+{
+ return traverseNode(command.commandPath());
+}
+
prefix_ void senf::console::Executor::exec(std::ostream & output,
ParseCommandInfo const & command)
{
- GenericNode & node ( traverseNode(command.commandPath()) );
- DirectoryNode * dir ( dynamic_cast<DirectoryNode*>(&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<CommandNode &>(node)(output, command);
+ try {
+ GenericNode & node ( traverseNode(command.commandPath()) );
+ DirectoryNode * dir ( dynamic_cast<DirectoryNode*>(&node) );
+ if ( dir ) {
+ if (! command.tokens().empty())
+ throw InvalidCommandException();
+ if (command.builtin() == ParseCommandInfo::BuiltinPUSHD)
+ pushd( command.commandPath() );
+ else if (autocd_) {
+ cd(command.commandPath());
+ }
+ else
+ throw InvalidCommandException();
+ } else {
+ boost::any rv;
+ dynamic_cast<CommandNode &>(node)(rv, output, command);
+ if (command.builtin() == ParseCommandInfo::BuiltinPUSHD) {
+ DirectoryNode::ptr rvdir;
+ try {
+ rvdir = boost::any_cast<DirectoryNode::ptr>(rv);
+ }
+ catch (boost::bad_any_cast &) {
+ throw InvalidCommandException();
+ }
+ Path newDir (cwd_);
+ newDir.push_back(rvdir);
+ dirstack_.push_back(Path());
+ dirstack_.back().swap(cwd_);
+ cwd_.swap(newDir);
+ }
+ }
+ }
+ catch (IgnoreCommandException &) {
+ if (command.builtin() == ParseCommandInfo::BuiltinPUSHD) {
+ dirstack_.push_back(Path());
+ dirstack_.back().swap(cwd_);
+ }
+ else
+ throw;
}
}
prefix_ void senf::console::Executor::ls(std::ostream & output,
ParseCommandInfo::TokensRange path)
{
+ unsigned width (80);
+ try {
+ width = senf::console::Client::get(output).width();
+ }
+ catch (std::bad_cast &)
+ {}
+ if (width<60)
+ width = 80;
+ width -= 28+1;
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 (i->second->isDirectory())
- output << "/";
- else if (i->second->isLink())
- output << "@";
- output << "\n";
+ boost::format fmt ("%s%s %|28t|%s\n");
+ for (; i != i_end; ++i)
+ output << fmt
+ % i->first
+ % ( i->second->isDirectory()
+ ? "/"
+ : i->second->isLink()
+ ? "@"
+ : "" )
+ % i->second->shorthelp().substr(0,width);
+}
+
+namespace {
+
+ typedef std::map<senf::console::DirectoryNode*,std::string> NodesMap;
+
+ void dolr(std::ostream & output, unsigned width, NodesMap & nodes, std::string const & base,
+ unsigned level, senf::console::DirectoryNode & node)
+ {
+ boost::format fmt ("%s%s%s %|40t|%s\n");
+ std::string pad (2*level, ' ');
+ senf::console::DirectoryNode::child_iterator i (node.children().begin());
+ senf::console::DirectoryNode::child_iterator const i_end (node.children().end());
+ for (; i != i_end; ++i) {
+ output << fmt
+ % pad
+ % i->first
+ % ( i->second->isDirectory()
+ ? "/"
+ : i->second->isLink()
+ ? "@"
+ : "" )
+ % i->second->shorthelp().substr(0,width);
+ if (i->second->followLink().isDirectory()) {
+ senf::console::DirectoryNode & subnode (
+ static_cast<senf::console::DirectoryNode&>(i->second->followLink()));
+ NodesMap::iterator j (nodes.find(&subnode));
+ if (j == nodes.end()) {
+ std::string subbase (base);
+ if (! subbase.empty())
+ subbase += "/";
+ subbase += i->first;
+ nodes.insert(std::make_pair(&subnode, subbase));
+ dolr(output, width, nodes, subbase, level+1, subnode);
+ } else
+ output << pad << " -> " << j->second << "\n";
+ }
+ }
+ }
+
+}
+
+prefix_ void senf::console::Executor::lr(std::ostream & output,
+ ParseCommandInfo::TokensRange path)
+{
+ unsigned width (80);
+ try {
+ width = senf::console::Client::get(output).width();
}
+ catch (std::bad_cast &)
+ {}
+ if (width<60)
+ width = 80;
+ width -= 40+1;
+ Path dir (cwd_);
+ traverseDirectory(path, dir);
+ DirectoryNode & node (*dir.back().lock());
+ NodesMap nodes;
+ dolr(output, width, nodes, "", 0, node);
}
prefix_ void senf::console::Executor::pushd(ParseCommandInfo::TokensRange dir)
return dir.back().lock()->get(name);
}
catch (UnknownNodeNameException &) {
- throw InvalidPathException();
+ throw InvalidPathException(
+ senf::stringJoin(
+ senf::make_transform_range(path, boost::bind(&Token::value, _1)),
+ "/"));
}
}
senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange const & path,
Path & dir)
{
+ std::string errorPath;
try {
ParseCommandInfo::TokensRange::const_iterator i (path.begin());
ParseCommandInfo::TokensRange::const_iterator const i_end (path.end());
for (; i != i_end; ++i) {
+ if (i != path.begin())
+ errorPath += "/";
+ errorPath += i->value();
if (*i == NoneToken()) {
if (i == path.begin()) {
dir.clear();
}
}
catch (std::bad_cast &) {
- throw InvalidDirectoryException();
+ throw InvalidDirectoryException(errorPath);
}
catch (UnknownNodeNameException &) {
- throw InvalidDirectoryException();
+ throw InvalidDirectoryException(errorPath);
}
}
return name;
}
+prefix_ void senf::console::senf_console_format_value(DirectoryNode::ptr value,
+ std::ostream & os)
+{
+ if (value)
+ os << "<Directory at '" << value->path() << "'>";
+ else
+ os << "<Null Directory>";
+}
+
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
//#include "Executor.mpp"