#include <boost/range/iterator_range.hpp>
#include <boost/bind.hpp>
#include <boost/format.hpp>
+#include <boost/preprocessor/stringize.hpp>
#include "../../Utils/senfassert.hh"
#include "../../Utils/Range.hh"
#include "../../Utils/String.hh"
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;
+# define HELP_COLUMN 28
+
+ unsigned width (senf::console::Client::getWidth(output, 80u, 60u)-(HELP_COLUMN+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());
- boost::format fmt ("%s%s %|28t|%s\n");
+ boost::format fmt ("%s%s %|" BOOST_PP_STRINGIZE(HELP_COLUMN) "t|%s\n");
for (; i != i_end; ++i)
output << fmt
% i->first
? "@"
: "" )
% i->second->shorthelp().substr(0,width);
+
+# undef HELP_COLUMN
}
+# define HELP_COLUMN 40
+
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");
+ boost::format fmt ("%s%s%s %|" BOOST_PP_STRINGIZE(HELP_COLUMN) "t|%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()) {
+ output << fmt
+ % pad % i->first
+ % ( i->second->isDirectory() ? "/" : i->second->isLink() ? "@" : "" )
+ % i->second->shorthelp().substr(0,width);
std::string subbase (base);
if (! subbase.empty())
subbase += "/";
nodes.insert(std::make_pair(&subnode, subbase));
dolr(output, width, nodes, subbase, level+1, subnode);
} else
- output << pad << " -> " << j->second << "\n";
+ output << pad << i->first
+ << ( i->second->isDirectory() ? "/" : i->second->isLink() ? "@" : "" )
+ << " -> " << j->second << "\n";
+ } else {
+ output << fmt
+ % pad % i->first
+ % ( i->second->isDirectory() ? "/" : i->second->isLink() ? "@" : "" )
+ % i->second->shorthelp().substr(0,width);
}
}
}
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);
+ dolr(output, senf::console::Client::getWidth(output, 80u, 60u)-(HELP_COLUMN+1),
+ nodes, "", 0, node);
}
+#undef HELP_COLUMN
+
prefix_ void senf::console::Executor::pushd(ParseCommandInfo::TokensRange dir)
{
Path newDir (cwd_);
class DirectoryNode;
class CommandNode;
+ /** \brief Get console root node */
DirectoryNode & root();
+
+ /** \brief Dump console directory structure
+
+ Recursively dumps the console directory structure starting at \a dir. By default, dumps the
+ complete tree beginning at the root node.
+
+ In contrast to the console 'lr' command, links are dumped by showing the \e absolute path
+ to the target node.
+ */
void dump(std::ostream & os, DirectoryNode & dir=root());
/** \brief Config/console node tree base-class
//#include "VectorSupport.ih"
// Custom includes
+#include <boost/format.hpp>
#define prefix_
///////////////////////////////ct.p////////////////////////////////////////
os << ")";
}
+template <class T1, class T2>
+prefix_ void senf::console::ArgumentTraits< std::pair<T1,T2> >::
+parse(ParseCommandInfo::TokensRange const & tokens, type & out)
+{
+ CheckedArgumentIteratorWrapper arg (tokens);
+ senf::console::parse( *(arg++), out.first );
+ senf::console::parse( *(arg++), out.second );
+}
+
+template <class T1, class T2>
+prefix_ std::string senf::console::ArgumentTraits< std::pair<T1,T2> >::description()
+{
+ return (boost::format("pair<%s,%s>")
+ % ArgumentTraits<T1>::description()
+ % ArgumentTraits<T2>::description()).str();
+}
+
+template <class T1, class T2>
+prefix_ std::string senf::console::ArgumentTraits< std::pair<T1,T2> >::str(type const & value)
+{
+ std::stringstream ss;
+ senf::console::format(value, ss);
+ return ss.str();
+}
+
+template <class T1, class T2>
+prefix_ void senf::console::ReturnValueTraits< std::pair<T1,T2> >::format(type const & value,
+ std::ostream & os)
+{
+ os << "(";
+ senf::console::format(value.first, os);
+ os << " ";
+ senf::console::format(value.second, os);
+ os << ")";
+}
+
#endif
///////////////////////////////ct.e////////////////////////////////////////
: public SequenceReturnValueTraits< std::list<T,Alloc> >
{};
+ template <class T1, class T2>
+ struct ArgumentTraits< std::pair<T1,T2> >
+ {
+ typedef std::pair<T1,T2> type;
+ static bool const singleToken = false;
+
+ static void parse(ParseCommandInfo::TokensRange const & tokens, type & out);
+ static std::string description();
+ static std::string str(type const & value);
+ };
+
+ template <class T1, class T2>
+ struct ReturnValueTraits< std::pair<T1,T2> >
+ {
+ typedef std::pair<T1,T2> type;
+
+ static void format(type const & value, std::ostream & os);
+ };
+
#endif
}}
reader_->enablePrompt();
}
+prefix_ unsigned senf::console::Client::getWidth(std::ostream & os, unsigned defaultWidth,
+ unsigned minWidth)
+{
+ unsigned rv (defaultWidth);
+ try {
+ rv = get(os).width();
+ }
+ catch (std::bad_cast &) {}
+ return rv < minWidth ? defaultWidth : rv;
+}
+
///////////////////////////////////////////////////////////////////////////
// senf::console::Client::SysBacktrace
void stop(); ///< Stop the client
/**< This will close the client socket. */
- std::string const & name() const;
- ClientHandle handle() const;
- std::ostream & stream();
- std::string promptString() const;
- DirectoryNode & root() const;
- DirectoryNode & cwd() const;
- Server::Mode mode() const;
+ std::string const & name() const; ///< Get name of the client instance
+ /**< This name is used in the prompt string and is set by
+ the server. */
+ ClientHandle handle() const; ///< Get the client's network socket handle
+ std::ostream & stream(); ///< Get client's output stream
+ /**< Data sent to this stream is sent out over the network
+ via the client's socket handle. Write operation is
+ non-blocking and data may be dropped. Data is written
+ using Client::write(). */
+ std::string promptString() const; ///< Get the prompt string
+ DirectoryNode & root() const; ///< Get configured root node
+ DirectoryNode & cwd() const; ///< Get current directory
+ /**< This is the directory, the console currently is changed
+ into by the user of the console. */
+ Server::Mode mode() const; ///< Get operation mode
+ /**< \see Server::mode() */
void write(std::string const & data) const;
- std::string const & backtrace() const;
- unsigned width() const;
+ ///< Write data to network socket
+ /**< The data is automatically filtered depending on the
+ type of connection (e.g. on a telnet connection,
+ specific bytes are quoted). */
+ std::string const & backtrace() const; ///< Get backtrace of last console error, if any
+ unsigned width() const; ///< Get console width
+ /**< If possible, this will be the width of the connected
+ terminal, otherwise a default value (normally 80) is
+ returned. */
static Client & get(std::ostream & os);
+ ///< Access client instance
+ /**< Allows to access the client instance from console
+ command implementations. The first argument to a
+ console command is a stream object. \e If this stream
+ object belongs to a network console client, this call
+ will return the associated Client instance reference.
+ \throws std::bad_cast if \a os is not associated with a
+ Client instance. */
+ static unsigned getWidth(std::ostream & os, unsigned defaultWidth = 0,
+ unsigned minWidth = 0);
+ ///< Get width of client console if possible
+ /**< If possible, the width of the client console attached
+ to the stream \a os is returned. If this is not
+ possible, the \a defaultValue will be used.
+
+ If the width obtained this way is smaller than \a
+ minWidth, \a defaultValue will be returned instead. */
protected: