prefix_ bool senf::console::Executor::operator()(ParseCommandInfo const & command,
std::ostream & output)
{
-# warning Implement Executor::operator()
SENF_LOG(( "Executing: " << command ));
- if (command.builtin() == ParseCommandInfo::BuiltinEXIT)
+
+ if (cwd_.expired())
+ cwd_ = boost::static_pointer_cast<DirectoryNode>(
+ root().shared_from_this());
+
+ switch(command.builtin()) {
+ case ParseCommandInfo::NoBuiltin :
+ break;
+
+ case ParseCommandInfo::BuiltinCD :
+ if ( command.arguments() &&
+ ! chdir(command.arguments().begin()[0]) )
+ output << "invalid directory\n";
+ break;
+
+ case ParseCommandInfo::BuiltinLS :
+ for (DirectoryNode::child_iterator i (cwd().children().begin());
+ i != cwd().children().end(); ++i)
+ output << i->first << "\n";
+ break;
+
+ case ParseCommandInfo::BuiltinPUSHD :
+ dirstack_.push_back(cwd_);
+ if ( command.arguments()
+ && ! chdir(command.arguments().begin()[0]) )
+ output << "invalid directory\n";
+ break;
+
+ case ParseCommandInfo::BuiltinPOPD :
+ if (! dirstack_.empty()) {
+ cwd_ = dirstack_.back();
+ dirstack_.pop_back();
+ }
+ break;
+
+ case ParseCommandInfo::BuiltinEXIT :
throw ExitException();
+ }
return true;
}
+prefix_ bool senf::console::Executor::chdir(ParseCommandInfo::argument_value_type const & path)
+{
+ try {
+ DirectoryNode::ptr dir (cwd_.lock());
+ ParseCommandInfo::token_iterator i (path.begin());
+ ParseCommandInfo::token_iterator const i_end (path.end());
+ if (i != i_end && i->value().empty()) {
+ dir = boost::static_pointer_cast<DirectoryNode>(
+ root().shared_from_this());
+ ++ i;
+ }
+ for (; i != i_end; ++i) {
+ if (i->value() == "..") {
+ dir = dir->parent();
+ if (! dir)
+ dir = boost::static_pointer_cast<DirectoryNode>(
+ root().shared_from_this());
+ }
+ else if (! i->value().empty() && i->value() != ".")
+ dir = boost::static_pointer_cast<DirectoryNode>(
+ (*dir)[i->value()].shared_from_this());
+ }
+ cwd_ = dir;
+ }
+ catch (std::bad_cast &) {
+ return false;
+ }
+ catch (UnknownNodeNameException &) {
+ return false;
+ }
+ return true;
+}
+
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
//#include "Executor.mpp"
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2008
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+// Stefan Bund <g0dil@berlios.de>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+/** \file
+ \brief Executor inline non-template implementation */
+
+//#include "Executor.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::Executor
+
+prefix_ senf::console::Executor::Executor()
+{
+ cwd_ = boost::static_pointer_cast<DirectoryNode>(
+ root().shared_from_this());
+}
+
+prefix_ senf::console::DirectoryNode & senf::console::Executor::cwd()
+ const
+{
+ return cwd_.expired() ? root() : *cwd_.lock();
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
#define HH_Executor_ 1
// Custom includes
+#include <boost/utility.hpp>
#include "Parse.hh"
#include "../Utils/Logger/SenfLog.hh"
+#include "Node.hh"
//#include "Executor.mpp"
///////////////////////////////hh.p////////////////////////////////////////
/** \brief
*/
class Executor
+ : boost::noncopyable
{
SENF_LOG_CLASS_AREA();
SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
struct ExitException {}; // NOT derived from std::exception !
///////////////////////////////////////////////////////////////////////////
+ //\/name Structors and default members
+ ///\{
+ Executor();
+
+ ///\}
+ ///////////////////////////////////////////////////////////////////////////
+
bool operator()(ParseCommandInfo const & command, std::ostream & output);
-
+ DirectoryNode & cwd() const;
+
protected:
private:
+ bool chdir(ParseCommandInfo::argument_value_type const & path);
+ DirectoryNode::weak_ptr cwd_;
+ typedef std::vector<DirectoryNode::weak_ptr> DirStack;
+ DirStack dirstack_;
};
}}
///////////////////////////////hh.e////////////////////////////////////////
-//#include "Executor.cci"
+#include "Executor.cci"
//#include "Executor.ct"
//#include "Executor.cti"
#endif
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
+prefix_ senf::console::DirectoryNode & senf::console::root()
+{
+ static DirectoryNode::ptr rootNode(new DirectoryNode(""));
+ return *rootNode;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::GenericNode
+
+prefix_ std::string senf::console::GenericNode::path()
+ const
+{
+ std::string path (name());
+ ptr node (parent());
+ while (node) {
+ path = node->name() + "/" + path;
+ node = node->parent();
+ }
+ return path.empty() ? "/" : path;
+}
+
///////////////////////////////////////////////////////////////////////////
//senf::console::DirectoryNode
prefix_ void senf::console::DirectoryNode::add(GenericNode::ptr node, bool uniquify)
{
+ BOOST_ASSERT( ! node->parent() );
if (children_.find(node->name()) != children_.end()) {
if (! uniquify)
throw DuplicateNodeNameException() << ": '" << node->name() << "'";
name(*node, newName);
}
children_.insert(std::make_pair(node->name(),node));
+ node->parent_ = this;
}
prefix_ senf::console::GenericNode &
///////////////////////////////////////////////////////////////////////////
// senf::console::GenericNode
+prefix_ senf::console::GenericNode::~GenericNode()
+{}
+
prefix_ std::string const & senf::console::GenericNode::name()
const
{
return name_;
}
-prefix_ senf::console::GenericNode::GenericNode(std::string const & name, bool managed)
- : name_ (name), managed_ (managed)
+prefix_ senf::console::GenericNode::GenericNode(std::string const & name)
+ : name_ (name), parent_ (0)
{}
prefix_ void senf::console::GenericNode::name(std::string const & name)
node.name_ = name;
}
-prefix_ senf::console::DirectoryNode & senf::console::GenericNode::parent()
- const
-{
- SENF_ASSERT( parent_ );
- return *parent_;
-}
-
-prefix_ bool senf::console::GenericNode::managed()
+prefix_ boost::shared_ptr<senf::console::DirectoryNode> senf::console::GenericNode::parent()
const
{
- return managed_;
-}
-
-prefix_ bool senf::console::GenericNode::release()
-{
- // Beware ! call release() first so the call is not short-circuited way !
- return intrusive_refcount_base::release() && managed_;
+ return boost::static_pointer_cast<DirectoryNode>(
+ parent_ ? parent_->shared_from_this() : ptr() );
}
///////////////////////////////////////////////////////////////////////////
// senf::console::DirectoryNode
-prefix_ void senf::console::DirectoryNode::add(std::auto_ptr<GenericNode> node, bool uniquify)
-{
- SENF_ASSERT( node->managed() );
- add(GenericNode::ptr(node.release()), uniquify);
-}
-
-prefix_ void senf::console::DirectoryNode::add(GenericNode & node, bool uniquify)
+prefix_ senf::console::GenericNode &
+senf::console::DirectoryNode::add(std::auto_ptr<GenericNode> node, bool uniquify)
{
- SENF_ASSERT( ! node.managed() );
- add(GenericNode::ptr(&node),uniquify);
+ GenericNode::ptr p (node.release());
+ add(p, uniquify);
+ return *p;
}
prefix_ senf::console::DirectoryNode &
return dynamic_cast<CommandNode&>(lookup(name));
}
-prefix_ senf::console::DirectoryNode::DirectoryNode(std::string const & name, bool managed)
- : GenericNode(name, managed)
+prefix_ senf::console::DirectoryNode &
+senf::console::DirectoryNode::mkdir(std::string const & name)
+{
+ return static_cast<DirectoryNode &>(
+ add(std::auto_ptr<GenericNode>(new DirectoryNode(name))));
+}
+
+prefix_ senf::console::DirectoryNode::ChildrenRange senf::console::DirectoryNode::children()
+ const
+{
+ return boost::make_iterator_range(children_.begin(), children_.end());
+}
+
+prefix_ senf::console::DirectoryNode::DirectoryNode(std::string const & name)
+ : GenericNode(name)
{}
///////////////////////////////////////////////////////////////////////////
// senf::console::CommandNode
-prefix_ senf::console::CommandNode::CommandNode(std::string const & name, bool managed)
- : GenericNode(name, managed)
+prefix_ senf::console::CommandNode::CommandNode(std::string const & name)
+ : GenericNode(name)
{}
///////////////////////////////cci.e///////////////////////////////////////
// Custom includes
#include <map>
-#include <boost/intrusive_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
#include <boost/utility.hpp>
-#include "../Utils/intrusive_refcount.hh"
+#include <boost/range/iterator_range.hpp>
#include "../Utils/Exception.hh"
//#include "Node.mpp"
/** \brief
*/
class GenericNode
- : public intrusive_refcount_t<GenericNode>
+ : public boost::enable_shared_from_this<GenericNode>
{
public:
///////////////////////////////////////////////////////////////////////////
// Types
- typedef boost::intrusive_ptr<GenericNode> ptr;
+ typedef boost::shared_ptr<GenericNode> ptr;
+ typedef boost::weak_ptr<GenericNode> weak_ptr;
///////////////////////////////////////////////////////////////////////////
+ virtual ~GenericNode();
+
std::string const & name() const;
- DirectoryNode & parent() const;
+ boost::shared_ptr<DirectoryNode> parent() const;
bool managed() const;
+ std::string path() const;
+
protected:
- explicit GenericNode(std::string const & name, bool managed = false);
+ explicit GenericNode(std::string const & name);
void name(std::string const & name);
static void name(GenericNode & node, std::string const & name);
void parent(DirectoryNode * parent);
private:
- bool release();
-
std::string name_;
- bool managed_;
DirectoryNode * parent_;
friend class intrusive_refcount_base;
+ friend class DirectoryNode;
};
/** \brief
*/
class DirectoryNode : public GenericNode
{
+ typedef std::map<std::string, GenericNode::ptr> ChildMap;
+
public:
- typedef boost::intrusive_ptr<DirectoryNode> ptr;
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef boost::shared_ptr<DirectoryNode> ptr;
+ typedef boost::weak_ptr<DirectoryNode> weak_ptr;
+
+ typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
+ typedef ChildMap::const_iterator child_iterator;
+
+ ///////////////////////////////////////////////////////////////////////////
- void add(std::auto_ptr<GenericNode> node, bool uniquify = true);
- void add(GenericNode & node, bool uniquify = true);
+ GenericNode & add(std::auto_ptr<GenericNode> node, bool uniquify = true);
DirectoryNode & operator[](std::string const & name) const;
CommandNode & operator()(std::string const & name) const;
+ DirectoryNode & mkdir(std::string const & name);
+
+ ChildrenRange children() const;
+
protected:
- explicit DirectoryNode(std::string const & name, bool managed = false);
+ explicit DirectoryNode(std::string const & name);
private:
void add(GenericNode::ptr node, bool uniquify);
GenericNode & lookup(std::string const & name) const;
- typedef std::map<std::string, GenericNode::ptr> ChildMap;
ChildMap children_;
+
+ friend DirectoryNode & root();
};
struct DuplicateNodeNameException : public senf::Exception
class CommandNode : public GenericNode
{
public:
- typedef boost::intrusive_ptr<CommandNode> ptr;
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef boost::shared_ptr<CommandNode> ptr;
+ typedef boost::weak_ptr<CommandNode> weak_ptr;
+
+ ///////////////////////////////////////////////////////////////////////////
protected:
- explicit CommandNode(std::string const & name, bool managed = false);
+ explicit CommandNode(std::string const & name);
private:
};
+ DirectoryNode & root();
+
}}
///////////////////////////////hh.e////////////////////////////////////////
{
boost::spirit::rule<Scanner> command, path, argument, word, string, hexstring, token,
punctuation, hexbyte, balanced_tokens, simple_argument, complex_argument, builtin,
- skip, commands, block, statement;
+ skip, commands, block, statement, relpath, abspath;
boost::spirit::chset<> special_p, punctuation_p, space_p, invalid_p, word_p;
boost::spirit::distinct_parser<> keyword_p;
using namespace boost::spirit;
typedef ParseDispatcher PD;
+ ///////////////////////////////////////////////////////////////////
+ // Spirit grammar
+ //
+ // Syntax summary:
+ // This is EBNF with some minor tweaks to accommodate C++ syntax
+ //
+ // * and + precede their argument
+ // >> is followed by
+ // ! optional
+ // a % b match any number of a's separated by b
+ // a - b match a but not b
+ //
+ // Beside this, we use some special parsers (ch_p, eps_p, confix_p, lex_escape_ch_p,
+ // keyword_p, comment_p) and directives (lexeme_d), however, the parser should be
+ // quite readable.
+ //
+ // ch_p match character
+ // eps_p always matches nothing (to attach unconditional actions)
+ // confix_p(a,b,c) match b, preceded by a and terminated by c. Used to parse
+ // string literals and comments
+ // lex_escape_ch_p match a lex style escape char. This is like a C++ style
+ // literal string escape char, however \x will be replaced by 'x'
+ // for any char 'x' if it has no special meaning.
+ // keyword_p match a delimited keyword
+ // comment_p(a,b) match comment starting with a and terminated with b. b
+ // defaults to end-of-line
+ //
+ // lexeme_d don't skip whitespace (as defined by the skip parser)
+ //
+ // Aligned to the right at column 50 are semantic actions.
+ //
+ // For clarity, I have used 'ch_p' explicitly throughout even though it is auxiliary
+ // in most cases.
+ //
+ // More info is in the Boost.Spirit documentation
+
commands
= * command
;
command
- = builtin
+ = builtin >> (ch_p(';') | end_p)
| path >> ( block | statement )
+ | ch_p(';') // Ignore empty commands
;
builtin
path // Returns value in context.path
= eps_p [ clear_a(self.context.path) ]
- >> ( ! ch_p('/') [ push_back_a(self.context.path, "") ] )
- >> ( word [ push_back_a(self.context.path) ]
+ >> relpath | abspath
+ ;
+
+ relpath
+ = ( word [ push_back_a(self.context.path) ]
% ch_p('/') )
>> ( ! ch_p('/') [ push_back_a(self.context.path,"") ] )
;
+ abspath
+ = ch_p('/') [ push_back_a(self.context.path, "") ]
+ >> ! ( ( word [ push_back_a(self.context.path) ]
+ % ch_p('/') )
+ >> ( ! ch_p('/') [ push_back_a(self.context.path,"") ] ) )
+ ;
+
balanced_tokens
= ch_p('(') [ self.dispatch(&PD::pushPunctuation, "(") ]
>> * token
= space_p | comment_p('#')
;
+ ///////////////////////////////////////////////////////////////////
+
+ start_parsers(
+ commands, // CommandParser
+ skip // SkipParser
+ );
+
BOOST_SPIRIT_DEBUG_TRACE_RULE(command,1);
BOOST_SPIRIT_DEBUG_TRACE_RULE(path,1);
BOOST_SPIRIT_DEBUG_TRACE_RULE(argument,1);
BOOST_SPIRIT_DEBUG_TRACE_RULE(simple_argument,1);
BOOST_SPIRIT_DEBUG_TRACE_RULE(complex_argument,1);
BOOST_SPIRIT_DEBUG_TRACE_RULE(builtin,1);
-
- start_parsers(
- commands, // CommandParser
- skip // SkipParser
- );
-
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(commands,1);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(block,1);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(statement,1);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(relpath,1);
+ BOOST_SPIRIT_DEBUG_TRACE_RULE(abspath,1);
}
};
};
prefix_ senf::console::Client::Client(ClientHandle handle, std::string const & name)
: handle_ (handle), name_ (name), out_(::dup(handle.fd()))
{
- out_ << name_ << "# " << std::flush;
+ showPrompt();
ReadHelper<ClientHandle>::dispatch( handle_, 16384u, ReadUntil("\n"),
senf::membind(&Client::clientData, this) );
}
return;
}
- out_ << name_ << "# " << std::flush;
+ showPrompt();
ReadHelper<ClientHandle>::dispatch( handle_, 16384u, ReadUntil("\n"),
senf::membind(&Client::clientData, this) );
}
+prefix_ void senf::console::Client::showPrompt()
+{
+ out_ << name_ << ":" << executor_.cwd().path() << "# " << std::flush;
+}
+
///////////////////////////////cc.e////////////////////////////////////////
#undef prefix_
//#include "Server.mpp"
Client(ClientHandle handle, std::string const & name);
void clientData(ReadHelper<ClientHandle>::ptr helper);
+ void showPrompt();
ClientHandle handle_;
std::string tail_;
{
senf::log::ConsoleTarget::instance().route< senf::SenfLog, senf::log::NOTICE >();
+ senf::console::root().mkdir("network").mkdir("eth0");
+ senf::console::root().mkdir("server");
+
senf::console::Server::start( senf::INet4SocketAddress("127.0.0.1:23232") )
.name("testServer");