21 #include <boost/range/iterator_range.hpp> 22 #include <boost/bind.hpp> 23 #include <boost/format.hpp> 24 #include <boost/preprocessor/stringize.hpp> 25 #include <boost/algorithm/string/join.hpp> 37 struct TraversTokens {
38 typedef std::string
const & result_type;
52 SENF_ASSERT( ! cwd_.empty(),
"Internal error: CWD history empty ?" );
53 while (cwd_.size()>1 && (cwd_.back().expired() || ! cwd_.back().lock()->active()))
55 return * cwd_.back().lock();
63 senf::IGNORE( cwd() );
64 return "/" + boost::algorithm::join(
65 senf::make_transform_range(
66 boost::make_iterator_range(boost::next(cwd_.begin()), cwd_.end()),
74 SENF_LOG((
"Executing: " << command ));
77 senf::IGNORE( cwd() );
81 case ParseCommandInfo::NoBuiltin :
84 exec(output, command);
87 case ParseCommandInfo::BuiltinCD :
96 "'cd' cannot be skipped (don't use 'cd' in conf-files)");
100 case ParseCommandInfo::BuiltinLS :
107 case ParseCommandInfo::BuiltinLL :
114 case ParseCommandInfo::BuiltinLR :
121 case ParseCommandInfo::BuiltinPUSHD :
126 exec(output, command);
129 case ParseCommandInfo::BuiltinPOPD :
134 case ParseCommandInfo::BuiltinEXIT :
141 case ParseCommandInfo::BuiltinHELP :
148 case ParseCommandInfo::BuiltinECHO :
151 echo( output, command.
tokens() );
156 catch (InvalidPathException & ex) {
159 catch (InvalidDirectoryException & ex) {
162 catch (InvalidCommandException &) {
174 catch (InvalidPathException & ex) {
177 catch (InvalidDirectoryException & ex) {
182 prefix_ void senf::console::Executor::exec(std::ostream & output,
189 if (! command.
tokens().empty())
190 throw InvalidCommandException();
191 if (command.
builtin() == ParseCommandInfo::BuiltinPUSHD)
197 throw InvalidCommandException();
200 dynamic_cast<CommandNode &
>(node)(rv, output, command);
201 if (command.
builtin() == ParseCommandInfo::BuiltinPUSHD) {
206 catch (boost::bad_any_cast &) {
207 throw InvalidCommandException();
210 newDir.push_back(rvdir);
211 dirstack_.push_back(Path());
212 dirstack_.back().swap(cwd_);
218 if (command.
builtin() == ParseCommandInfo::BuiltinPUSHD) {
219 dirstack_.push_back(Path());
220 dirstack_.back().swap(cwd_);
230 if (dir.size() == 1 && *dir.begin() == WordToken(
"-")) {
232 senf::IGNORE( cwd() );
238 traverseDirectory(dir, newDir);
244 prefix_ void senf::console::Executor::ls(std::ostream & output,
248 traverseDirectory(path, dir);
252 for (; i != i_end; ++i)
253 output << i->first <<
"\n";
256 prefix_ void senf::console::Executor::echo(std::ostream & output,
259 ParseCommandInfo::TokensRange::iterator i (args.begin());
260 ParseCommandInfo::TokensRange::iterator i_end (args.end());
262 output << (i++)->value();
263 if (i != i_end) output <<
' ';
268 prefix_ void senf::console::Executor::ll(std::ostream & output,
271 # define HELP_COLUMN 28 273 unsigned width (Client::getWidth(output, 80u, 60u)-(
HELP_COLUMN+1));
275 traverseDirectory(path, dir);
280 for (; i != i_end; ++i)
283 % ( i->second->isDirectory()
285 : i->second->isLink()
288 % i->second->shorthelp().substr(0,width);
293 # define HELP_COLUMN 40 297 typedef std::map<senf::console::DirectoryNode*,std::string> NodesMap;
299 void dolr(std::ostream & output,
unsigned width, NodesMap & nodes, std::string
const & base,
303 std::string pad (2*level,
' ');
306 for (; i != i_end; ++i) {
307 if (i->second->followLink().isDirectory()) {
309 static_cast<senf::console::DirectoryNode&>(i->second->followLink()));
310 NodesMap::iterator j (nodes.find(&subnode));
311 if (j == nodes.end()) {
314 % ( i->second->isDirectory() ?
"/" : i->second->isLink() ?
"@" :
"" )
315 % i->second->shorthelp().substr(0,width);
316 std::string subbase (base);
317 if (! subbase.empty())
320 nodes.insert(std::make_pair(&subnode, subbase));
321 dolr(output, width, nodes, subbase, level+1, subnode);
323 output << pad << i->first
324 << ( i->second->isDirectory() ?
"/" : i->second->isLink() ?
"@" :
"" )
325 <<
" -> " << j->second <<
"\n";
329 % ( i->second->isDirectory() ?
"/" : i->second->isLink() ?
"@" :
"" )
330 % i->second->shorthelp().substr(0,width);
337 prefix_ void senf::console::Executor::lr(std::ostream & output,
338 ParseCommandInfo::TokensRange path)
341 traverseDirectory(path, dir);
342 DirectoryNode & node (*dir.back().lock());
344 dolr(output, Client::getWidth(output, 80u, 60u)-(
HELP_COLUMN+1),
350 prefix_ void senf::console::Executor::pushd(ParseCommandInfo::TokensRange dir)
355 traverseDirectory(dir, newDir);
357 catch (IgnoreCommandException &) {
361 dirstack_.push_back(Path());
362 dirstack_.back().swap(cwd_);
366 prefix_ void senf::console::Executor::popd()
368 if (! dirstack_.empty()) {
369 cwd_.swap(dirstack_.back());
370 dirstack_.pop_back();
374 prefix_ void senf::console::Executor::exit()
376 throw ExitException();
379 prefix_ void senf::console::Executor::help(std::ostream & output,
380 ParseCommandInfo::TokensRange path)
382 GenericNode
const & node (traverseNode(path));
385 output << std::flush;
389 senf::console::Executor::traverseNode(ParseCommandInfo::TokensRange
const & path)
392 return *cwd_.back().lock();
395 traverseDirectory(boost::make_iterator_range(
397 boost::prior(path.end())),
400 Token
const & tok (*boost::prior(path.end()));
401 if (tok == WordToken(
"..")) {
404 return *dir.back().lock();
406 DirectoryNode & base (*dir.back().lock());
407 if (tok == WordToken(
".") || tok == NoneToken())
411 policy_( base, name );
412 return dir.back().lock()->get(name);
414 catch (UnknownNodeNameException &) {
415 throw InvalidPathException( boost::algorithm::join(
416 senf::make_transform_range(path, boost::bind(&Token::value, _1)),
422 senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange
const & path,
425 std::string errorPath;
427 ParseCommandInfo::TokensRange::const_iterator i (path.begin());
428 ParseCommandInfo::TokensRange::const_iterator
const i_end (path.end());
429 for (; i != i_end; ++i) {
430 if (i != path.begin())
432 errorPath += i->value();
433 if (*i == NoneToken()) {
434 if (i == path.begin()) {
436 dir.push_back(root_);
439 else if (*i == WordToken(
"..")) {
443 else if (*i == WordToken(
"."))
446 DirectoryNode & base (*dir.back().lock());
449 policy_( base, name );
450 dir.push_back(base[name].thisptr());
454 catch (std::bad_cast &) {
455 throw InvalidDirectoryException(errorPath);
457 catch (UnknownNodeNameException &) {
458 throw InvalidDirectoryException(errorPath);
462 prefix_ std::string senf::console::Executor::complete(DirectoryNode & dir,
463 std::string
const &
name)
465 if (! dir.hasChild(name)) {
466 DirectoryNode::ChildrenRange completions (dir.completions(name));
468 return completions.begin()->first;
477 os <<
"<Directory at '" << value->path() <<
"'>";
479 os <<
"<Null Directory>";
TokensRange tokens() const
All argument tokens.
boost::shared_ptr< DirectoryNode > ptr
Config/console tree directory node.
void senf_console_format_value(DirectoryNode::ptr value, std::ostream &os)
void execute(std::ostream &output, ParseCommandInfo const &command)
Execute command.
Syntax error parsing command arguments exception.
void complete(LineEditor &editor, Completer completer)
Thrown by the SecurityPolicy to silently ignore a command.
Single parsed console command.
TokensRange commandPath() const
Command path.
bool has_one_elt(Range r)
GenericNode & getNode(ParseCommandInfo const &command)
DirectoryNode & cwd() const
Current working directory.
ChildMap::const_iterator child_iterator
BuiltinCommand builtin() const
Command type.
std::string const & value() const
String value of token.
#define SENF_ASSERT(x, comment)
boost::iterator_range< token_iterator > TokensRange
Config/console tree command node.
ChildrenRange children() const
Return iterator range over all children.
unspecified_keyword_type name
Argument name.
Config/console node tree base-class.
void format(Type const &value, std::ostream &os)
Format return value.
std::string cwdPath() const
Return pathname of current directory.