Console: Added Module
g0dil [Wed, 19 Mar 2008 15:34:54 +0000 (15:34 +0000)]
Console: Implement very (very) fundamental node tree
Console: Implement parser

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@747 270642c3-0616-0410-b53a-bc976706d245

13 files changed:
Console/Doxyfile [new file with mode: 0644]
Console/Mainpage.dox [new file with mode: 0644]
Console/Node.cc [new file with mode: 0644]
Console/Node.cci [new file with mode: 0644]
Console/Node.hh [new file with mode: 0644]
Console/Node.test.cc [new file with mode: 0644]
Console/Parse.cc [new file with mode: 0644]
Console/Parse.cci [new file with mode: 0644]
Console/Parse.hh [new file with mode: 0644]
Console/Parse.ih [new file with mode: 0644]
Console/Parse.test.cc [new file with mode: 0644]
Console/SConscript [new file with mode: 0644]
Console/main.test.cc [new file with mode: 0644]

diff --git a/Console/Doxyfile b/Console/Doxyfile
new file mode 100644 (file)
index 0000000..0a359ce
--- /dev/null
@@ -0,0 +1,10 @@
+@INCLUDE = "$(TOPDIR)/doclib/Doxyfile.global"
+
+PROJECT_NAME = libConsole
+GENERATE_TAGFILE = doc/Console.tag
+ALPHABETICAL_INDEX = NO
+
+TAGFILES = \
+    "$(TOPDIR)/Socket/doc/Socket.tag" \
+    "$(TOPDIR)/Scheduler/doc/Scheduler.tag" \
+    "$(TOPDIR)/Utils/doc/Utils.tag"
diff --git a/Console/Mainpage.dox b/Console/Mainpage.dox
new file mode 100644 (file)
index 0000000..f430b75
--- /dev/null
@@ -0,0 +1,42 @@
+// $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.
+
+/** \mainpage The Configuration and Runtime Control Framework
+
+    The Console library implements a runtime interactive (network) console which allows to
+    configure, control and manipulate a running application in any way. Additionally this library
+    provides support for configuration files and command line parsing which can be used with or
+    without the network console.
+ */
+
+\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"
+// mode: flyspell
+// mode: auto-fill
+// End:
diff --git a/Console/Node.cc b/Console/Node.cc
new file mode 100644 (file)
index 0000000..964eb22
--- /dev/null
@@ -0,0 +1,77 @@
+// $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 Node non-inline non-template implementation */
+
+#include "Node.hh"
+//#include "Node.ih"
+
+// Custom includes
+
+//#include "Node.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+//senf::console::DirectoryNode
+
+prefix_ void senf::console::DirectoryNode::add(GenericNode::ptr node, bool uniquify)
+{
+    if (children_.find(node->name()) != children_.end()) {
+        if (! uniquify)
+            throw DuplicateNodeNameException() << ": '" << node->name() << "'";
+        unsigned suffix (0);
+        std::string newName;
+        do {
+            ++suffix;
+            newName = node->name() + boost::lexical_cast<std::string>(suffix);
+        } while (children_.find(newName) != children_.end());
+        name(*node, newName);
+    }
+    children_.insert(std::make_pair(node->name(),node));
+}
+
+prefix_ senf::console::GenericNode &
+senf::console::DirectoryNode::lookup(std::string const & name)
+    const
+{
+    ChildMap::const_iterator i (children_.find(name));
+    if (i == children_.end())
+        throw UnknownNodeNameException() << ": '" << name << "'";
+    return *(i->second);
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "Node.mpp"
+
+\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:
diff --git a/Console/Node.cci b/Console/Node.cci
new file mode 100644 (file)
index 0000000..88ed2c6
--- /dev/null
@@ -0,0 +1,128 @@
+// $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 Node inline non-template implementation */
+
+//#include "Node.ih"
+
+// Custom includes
+#include "../Utils/senfassert.hh"
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::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_ void senf::console::GenericNode::name(std::string const & name)
+{
+    name_ = name;
+}
+
+prefix_ void senf::console::GenericNode::name(GenericNode & node, 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()
+    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_;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// 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)
+{
+    SENF_ASSERT( ! node.managed() );
+    add(GenericNode::ptr(&node),uniquify);
+}
+
+prefix_ senf::console::DirectoryNode &
+senf::console::DirectoryNode::operator[](std::string const & name)
+    const
+{
+    return dynamic_cast<DirectoryNode&>(lookup(name));
+}
+
+prefix_ senf::console::CommandNode &
+senf::console::DirectoryNode::operator()(std::string const & name)
+    const
+{
+    return dynamic_cast<CommandNode&>(lookup(name));
+}
+
+prefix_ senf::console::DirectoryNode::DirectoryNode(std::string const & name, bool managed)
+    : GenericNode(name, managed)
+{}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::CommandNode
+
+prefix_ senf::console::CommandNode::CommandNode(std::string const & name, bool managed)
+    : GenericNode(name, managed)
+{}
+
+///////////////////////////////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:
diff --git a/Console/Node.hh b/Console/Node.hh
new file mode 100644 (file)
index 0000000..154bc97
--- /dev/null
@@ -0,0 +1,140 @@
+// $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 Node public header */
+
+#ifndef HH_Node_
+#define HH_Node_ 1
+
+// Custom includes
+#include <map>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/utility.hpp>
+#include "../Utils/intrusive_refcount.hh"
+#include "../Utils/Exception.hh"
+
+//#include "Node.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace console {
+
+    class DirectoryNode;
+    class CommandNode;
+
+    /** \brief
+      */
+    class GenericNode 
+        : public intrusive_refcount_t<GenericNode>
+    {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        typedef boost::intrusive_ptr<GenericNode> ptr;
+
+        ///////////////////////////////////////////////////////////////////////////
+
+        std::string const & name() const;
+        DirectoryNode & parent() const;
+        bool managed() const;
+
+    protected:
+        explicit GenericNode(std::string const & name, bool managed = false);
+
+        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;
+    };
+
+    /** \brief
+      */
+    class DirectoryNode : public GenericNode
+    {
+    public:
+        typedef boost::intrusive_ptr<DirectoryNode> ptr;
+
+        void add(std::auto_ptr<GenericNode> node, bool uniquify = true);
+        void add(GenericNode & node, bool uniquify = true);
+
+        DirectoryNode & operator[](std::string const & name) const;
+        CommandNode & operator()(std::string const & name) const;
+
+    protected:
+        explicit DirectoryNode(std::string const & name, bool managed = false);
+
+    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_;
+    };
+
+    struct DuplicateNodeNameException : public senf::Exception
+    { DuplicateNodeNameException() : senf::Exception("Duplicate node name") {}};
+
+    struct UnknownNodeNameException : public senf::Exception
+    { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
+
+    /** \brief
+      */
+    class CommandNode : public GenericNode
+    {
+    public:
+        typedef boost::intrusive_ptr<CommandNode> ptr;
+
+    protected:
+        explicit CommandNode(std::string const & name, bool managed = false);
+
+    private:
+
+    };
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "Node.cci"
+//#include "Node.ct"
+//#include "Node.cti"
+#endif
+
+\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:
diff --git a/Console/Node.test.cc b/Console/Node.test.cc
new file mode 100644 (file)
index 0000000..2170d42
--- /dev/null
@@ -0,0 +1,53 @@
+// $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 Node.test unit tests */
+
+//#include "Node.test.hh"
+//#include "Node.test.ih"
+
+// Custom includes
+#include "Node.hh"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+BOOST_AUTO_UNIT_TEST(node)
+{}
+
+///////////////////////////////cc.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:
diff --git a/Console/Parse.cc b/Console/Parse.cc
new file mode 100644 (file)
index 0000000..502dd1c
--- /dev/null
@@ -0,0 +1,182 @@
+// $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 Parse non-inline non-template implementation */
+
+#include "Parse.hh"
+#include "Parse.ih"
+
+// Custom includes
+#include <boost/iterator/transform_iterator.hpp>
+
+//#include "Parse.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace senf {
+namespace console {
+namespace detail {
+
+    struct ParserAccess
+    {
+        static void init(ParseCommandInfo & info)
+            { info.init(); }
+
+        static void setCommand(ParseCommandInfo & info, std::string const & commandPath)
+            { info.setCommand(commandPath); }
+
+        static void startArgument(ParseCommandInfo & info)
+            { info.startArgument(); }
+
+        static void endArgument(ParseCommandInfo & info)
+            { info.endArgument(); }
+
+        static void addToken(ParseCommandInfo & info, ArgumentToken const & token)
+            { info.addToken(token); }
+
+        static void finalize(ParseCommandInfo & info)
+            { info.finalize(); }
+
+        static ArgumentToken makeToken(std::string const & token)
+            { return ArgumentToken(token); }
+    };
+
+    struct ParseDispatcher
+    {
+        ParseDispatcher()
+            : info_ (0) {}
+        
+        ParseCommandInfo * info_;
+
+        ParseCommandInfo & info() {
+            SENF_ASSERT( info_ );
+            return *info_;
+        }
+
+        struct BindInfo {
+            BindInfo( ParseDispatcher & d, ParseCommandInfo & i)
+                : dispatcher (d) { dispatcher.info_ = &i; }
+
+            ~BindInfo() { dispatcher.info_  = 0; }
+
+            ParseDispatcher & dispatcher;
+        };
+
+        void beginCommand(std::string const & command)
+            { ParserAccess::init(info());
+              ParserAccess::setCommand(info(), command); }
+
+        void endCommand()
+            { ParserAccess::finalize(info()); }
+
+        void pushArgument(std::string const & argument)
+            { ParserAccess::startArgument(info()); 
+              ParserAccess::addToken(info(), ParserAccess::makeToken(argument)); 
+              ParserAccess::endArgument(info()); }
+
+        void openGroup()
+            { ParserAccess::startArgument(info()); }
+
+        void closeGroup()
+            { ParserAccess::endArgument(info()); }
+
+        void pushPunctuation(std::string const & token)
+            { ParserAccess::addToken(info(), ParserAccess::makeToken(token)); }
+
+        void pushWord(std::string const & token)
+            { ParserAccess::addToken(info(), ParserAccess::makeToken(token)); }
+    };
+
+}}}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::ParseCommandInfo
+
+struct senf::console::ParseCommandInfo::MakeRange
+{
+    MakeRange() {}
+    MakeRange(ParseCommandInfo::token_iterator b) : b_ (b) {}
+
+    senf::console::ParseCommandInfo::token_iterator b_;
+
+    typedef ParseCommandInfo::argument_value_type result_type;
+        
+    result_type operator()(TempArguments::iterator::value_type const & v) const {
+        return result_type( b_ + v.first, b_ + v.second );
+    }
+};
+
+prefix_ void senf::console::ParseCommandInfo::finalize()
+{
+    arguments_.resize( tempArguments_.size() );
+
+    std::copy( boost::make_transform_iterator( tempArguments_.begin(), 
+                                               MakeRange(tokens_.begin()) ),
+               boost::make_transform_iterator( tempArguments_.end(), 
+                                               MakeRange() ),
+               arguments_.begin() );
+
+    tempArguments_.clear();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::SingleCommandParser
+
+struct senf::console::SingleCommandParser::Impl
+{
+    detail::ParseDispatcher dispatcher;
+    detail::CommandGrammar<detail::ParseDispatcher>::Context context;
+    detail::CommandGrammar<detail::ParseDispatcher> grammar;
+    detail::SkipGrammar skipGrammar;
+
+    Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
+};
+
+prefix_ senf::console::SingleCommandParser::SingleCommandParser()
+    : impl_ (new Impl())
+{}
+
+prefix_ senf::console::SingleCommandParser::~SingleCommandParser()
+{}
+
+prefix_ bool senf::console::SingleCommandParser::parseCommand(std::string command,
+                                                              ParseCommandInfo & info)
+{
+    detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
+    return boost::spirit::parse( command.c_str(), impl().grammar, impl().skipGrammar ).full;
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "Parse.mpp"
+
+\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:
diff --git a/Console/Parse.cci b/Console/Parse.cci
new file mode 100644 (file)
index 0000000..1a72abf
--- /dev/null
@@ -0,0 +1,149 @@
+// $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 Parse inline non-template implementation */
+
+// We do NOT want to include the complete parser definition into every other compilation unit
+// (disabled) #include "Parse.ih"
+
+// Custom includes
+#include "../Utils/senfassert.hh"
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::ArgumentToken
+
+prefix_ std::string const & senf::console::ArgumentToken::value()
+    const
+{
+    return token_;
+}
+
+prefix_ senf::console::ArgumentToken::ArgumentToken(std::string token)
+    : token_ (token)
+{}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::ParseCommandInfo
+
+prefix_ std::string const & senf::console::ParseCommandInfo::commandPath()
+    const
+{
+    return commandPath_;
+}
+
+prefix_ senf::console::ParseCommandInfo::size_type senf::console::ParseCommandInfo::arguments()
+    const
+{
+    return arguments_.size();
+}
+
+prefix_ senf::console::ParseCommandInfo::argument_iterator
+senf::console::ParseCommandInfo::begin_arguments()
+    const
+{
+    return arguments_.begin();
+}
+
+prefix_ senf::console::ParseCommandInfo::argument_iterator
+senf::console::ParseCommandInfo::end_arguments()
+    const
+{
+    return arguments_.end();
+}
+
+prefix_ senf::console::ParseCommandInfo::size_type senf::console::ParseCommandInfo::tokens()
+    const
+{
+    return tokens_.size();
+}
+
+prefix_ senf::console::ParseCommandInfo::token_iterator
+senf::console::ParseCommandInfo::begin_tokens()
+    const
+{
+    return tokens_.begin();
+}
+
+prefix_ senf::console::ParseCommandInfo::token_iterator
+senf::console::ParseCommandInfo::end_tokens()
+    const
+{
+    return tokens_.end();
+}
+
+////////////////////////////////////////
+// private members
+
+prefix_ void senf::console::ParseCommandInfo::init()
+{
+    commandPath_ = "";
+    tokens_.clear();
+    arguments_.clear();
+    tempArguments_.clear();
+}
+
+prefix_ void senf::console::ParseCommandInfo::setCommand(std::string const & commandPath)
+{
+    commandPath_ = commandPath;
+}
+
+prefix_ void senf::console::ParseCommandInfo::startArgument()
+{
+    tempArguments_.push_back( TempArgumentRange( tokens_.size(), tokens_.size() ) );
+}
+
+prefix_ void senf::console::ParseCommandInfo::endArgument()
+{
+    tempArguments_.back().second = tokens_.size();
+}
+
+prefix_ void senf::console::ParseCommandInfo::addToken(ArgumentToken const & token)
+{
+    tokens_.push_back(token);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::SingleCommandParser
+
+prefix_ senf::console::SingleCommandParser::Impl & senf::console::SingleCommandParser::impl()
+{
+    SENF_ASSERT(impl_);
+    return *impl_;
+}
+
+///////////////////////////////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:
diff --git a/Console/Parse.hh b/Console/Parse.hh
new file mode 100644 (file)
index 0000000..4a5d32a
--- /dev/null
@@ -0,0 +1,159 @@
+// $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 Parse public header */
+
+#ifndef HH_Parse_
+#define HH_Parse_ 1
+
+// Custom includes
+#include <string>
+#include <vector>
+#include <boost/utility.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/range/iterator_range.hpp>
+
+//#include "Parse.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+namespace console {
+
+    namespace detail { struct ParserAccess; }
+
+    /** \brief
+      */
+    class ArgumentToken
+    {
+    public:
+        std::string const & value() const;
+
+    protected:
+
+    private:
+        explicit ArgumentToken(std::string token);
+
+        std::string token_;
+
+        friend class detail::ParserAccess;
+    };
+
+
+    /** \brief
+      */
+    class ParseCommandInfo
+    {
+        typedef std::vector<ArgumentToken> Tokens;
+        
+    public:
+        typedef Tokens::const_iterator token_iterator;
+        typedef boost::iterator_range<token_iterator> argument_value_type;
+
+    private:
+        typedef std::vector<argument_value_type> Arguments;
+
+    public:
+        typedef Arguments::const_iterator argument_iterator;
+        typedef Arguments::size_type size_type;
+
+        std::string const & commandPath() const;
+        
+        size_type arguments() const;
+        argument_iterator begin_arguments() const;
+        argument_iterator end_arguments() const;
+        
+        size_type tokens() const;
+        token_iterator begin_tokens() const;
+        token_iterator end_tokens() const;
+        
+    protected:
+
+    private:
+        void init();
+        void setCommand(std::string const & commandPath);
+        void startArgument();
+        void endArgument();
+        void addToken(ArgumentToken const & token);
+        void finalize();
+
+        struct MakeRange;
+
+        std::string commandPath_;
+
+        typedef std::pair<Tokens::size_type, Tokens::size_type> TempArgumentRange;
+        typedef std::vector<TempArgumentRange> TempArguments;
+
+        Tokens tokens_;
+        Arguments arguments_;
+        TempArguments tempArguments_;
+
+        friend class detail::ParserAccess;
+    };
+
+    /** \brief
+      */
+    class SingleCommandParser
+        : boost::noncopyable
+    {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///@{
+
+        SingleCommandParser();
+        ~SingleCommandParser();
+
+        ///@}
+        ///////////////////////////////////////////////////////////////////////////
+
+        bool parseCommand(std::string command, ParseCommandInfo & info);
+
+    private:
+        struct Impl;
+
+        Impl & impl();
+
+        boost::scoped_ptr<Impl> impl_;
+    };
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "Parse.cci"
+//#include "Parse.ct"
+//#include "Parse.cti"
+#endif
+
+\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:
diff --git a/Console/Parse.ih b/Console/Parse.ih
new file mode 100644 (file)
index 0000000..d5a9e2d
--- /dev/null
@@ -0,0 +1,258 @@
+// $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 Parse internal header */
+
+#ifndef IH_Parse_
+#define IH_Parse_ 1
+
+// Custom includes
+#include <boost/regex.hpp>
+#include <boost/spirit.hpp>
+#include <boost/spirit/utility/regex.hpp>
+#include <boost/spirit/actor.hpp>
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/ref.hpp>
+
+///////////////////////////////ih.p////////////////////////////////////////
+
+namespace senf {
+namespace console {
+namespace detail {
+
+    struct append_action
+    {
+        template <class T, class Value>
+        void act(T & ref, Value const & value) const
+            { ref += T(1, value); }
+
+        template <class T, class Iterator>
+        void act(T & ref, Iterator const & f, Iterator const & l) const
+            { ref += T(f,l); }
+    };
+
+    template <class T>
+    inline boost::spirit::ref_value_actor<T, append_action> 
+    append_a(T & ref)
+    {
+        return boost::spirit::ref_value_actor<T, append_action>(ref);
+    }
+    
+    template <class T, class Value>
+    inline boost::spirit::ref_const_ref_actor<T, Value, append_action> 
+    append_a(T & ref, Value const & value)
+    {
+        return boost::spirit::ref_const_ref_actor<T, Value, append_action>(ref, value);
+    }
+
+    template <class ParseDispatcher>
+    struct CommandGrammar : boost::spirit::grammar<CommandGrammar<ParseDispatcher> >
+    {
+        ///////////////////////////////////////////////////////////////////////////
+        // The parse context (variables needed while parsing)
+
+        struct Context {
+            std::string str;
+            char ch;
+        };
+
+        Context & context;
+
+        ///////////////////////////////////////////////////////////////////////////
+        // Dispatching semantic actions
+
+        ParseDispatcher & dispatcher;
+
+        struct Dispatch_actor
+        {
+            Dispatch_actor(boost::function<void ()> fn_) : fn (fn_) {}
+
+            template <class Value>
+            void operator()(Value const & value) const
+                { fn(); }
+
+            template <class Iterator>
+            void operator()(Iterator const & f, Iterator const & l) const
+                { fn(); }
+
+            boost::function<void ()> fn;
+        };
+        
+        template <class Callback>
+        Dispatch_actor dispatch(Callback cb) const
+            { return Dispatch_actor(boost::bind(cb, boost::ref(dispatcher))); }
+
+        template <class Callback, class Arg>
+        Dispatch_actor dispatch(Callback cb, Arg const & arg) const
+            { return Dispatch_actor(boost::bind(cb, boost::ref(dispatcher), arg)); }
+
+        ///////////////////////////////////////////////////////////////////////////
+
+        CommandGrammar(ParseDispatcher & d, Context & c) 
+            : context(c), dispatcher(d) {}
+
+        template <class Scanner>
+        struct definition
+        {
+            boost::spirit::rule<Scanner> command, path, argument, word, string, hexstring, token;
+            boost::spirit::rule<Scanner> punctuation, hexbyte, balanced_tokens, simple_argument;
+            boost::spirit::rule<Scanner> complex_argument;
+
+            definition(CommandGrammar const & self) {
+                using namespace boost::spirit;
+                typedef ParseDispatcher PD;
+                
+                command 
+                    =    path                     [ self.dispatch(&PD::beginCommand, 
+                                                                  boost::cref(self.context.str)) ]
+                      >> * argument
+                      >> ! ch_p(';')
+                      >> eps_p                    [ self.dispatch(&PD::endCommand) ]
+                    ;
+
+                argument
+                    =    simple_argument          [ self.dispatch(&PD::pushArgument, 
+                                                                  boost::cref(self.context.str)) ]
+                    |    complex_argument
+                    ;
+                
+                simple_argument         // All these return their value in context.str
+                    =    string
+                    |    hexstring
+                    |    path
+                    ;
+                
+                complex_argument        // Argument consists of multiple tokens
+                    =    ch_p('(')                [ self.dispatch(&PD::openGroup) ]
+                       >> * token
+                       >> ch_p(')')               [ self.dispatch(&PD::closeGroup) ]
+                    ;
+
+                string                  // Returns value in context.str
+                    =    eps_p                    [ clear_a(self.context.str) ]
+                      >> lexeme_d
+                         [
+                             ch_p('"')
+                          >> * ( ( lex_escape_ch_p[ assign_a(self.context.ch) ] 
+                                   - '"' 
+                                 )                [ append_a(self.context.str,
+                                                             self.context.ch) ] 
+                               )
+                          >> ch_p('"')
+                         ]
+                    ;
+
+                hexstring               // Returns value in context.str
+                    =    eps_p                    [ clear_a(self.context.str) ]
+                      >> confix_p( "x\"", * hexbyte, '"' )
+                    ;
+
+                path                    // Returns value in context.str
+                    =    eps_p                    [ clear_a(self.context.str) ]
+                      >> ( ! ch_p('/')            [ append_a(self.context.str) ] 
+                         ) 
+                      >> (   word                 [ append_a(self.context.str) ] 
+                           % ch_p('/')            [ append_a(self.context.str) ] 
+                         )
+                    ;
+
+                balanced_tokens 
+                    =    ch_p('(')                [ self.dispatch(&PD::pushPunctuation, "(") ]
+                      >> * token
+                      >> ch_p(')')                [ self.dispatch(&PD::pushPunctuation, ")") ]
+                    ;
+
+                token
+                    =    simple_argument          [ self.dispatch(&PD::pushWord, 
+                                                                  boost::cref(self.context.str)) ]
+                    |    punctuation              [ self.dispatch(&PD::pushPunctuation,
+                                                                  boost::cref(self.context.str)) ]
+                    |    balanced_tokens
+                    ;
+
+                punctuation             // Returns value in context.str
+                    =    regex_p("[,=]")          [ assign_a(self.context.str) ]
+                    ;
+
+                word
+                    =    regex_p("[^ \t\n\r;,=(){}/\"]+")
+                    ;
+
+                hexbyte
+                    =    uint_parser<char, 16, 2, 2>()
+                                                  [ append_a(self.context.str) ]
+                    ;
+
+                BOOST_SPIRIT_DEBUG_RULE(command);
+                BOOST_SPIRIT_DEBUG_RULE(path);
+                BOOST_SPIRIT_DEBUG_RULE(argument);
+                BOOST_SPIRIT_DEBUG_RULE(word);
+                BOOST_SPIRIT_DEBUG_RULE(string);
+                BOOST_SPIRIT_DEBUG_RULE(hexstring);
+                BOOST_SPIRIT_DEBUG_RULE(token);
+                BOOST_SPIRIT_DEBUG_RULE(punctuation);
+                BOOST_SPIRIT_DEBUG_RULE(hexbyte);
+                BOOST_SPIRIT_DEBUG_RULE(balanced_tokens);
+                BOOST_SPIRIT_DEBUG_RULE(simple_argument);
+                BOOST_SPIRIT_DEBUG_RULE(complex_argument);
+            }
+
+            boost::spirit::rule<Scanner> const & start() const { return command; }
+        };
+    };
+
+    struct SkipGrammar
+        : public boost::spirit::grammar<SkipGrammar>
+    {
+        template <class Scanner>
+        struct definition
+        {
+            boost::spirit::rule<Scanner> rule;
+
+            definition(SkipGrammar const & self) {
+                rule 
+                    =    boost::spirit::regex_p("[ \t]+") 
+                    |    boost::spirit::comment_p('#')
+                    ;
+            }
+
+            boost::spirit::rule<Scanner> const & start() const { return rule; }
+        };
+    };
+
+}}}
+
+///////////////////////////////ih.e////////////////////////////////////////
+#endif
+
+\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:
diff --git a/Console/Parse.test.cc b/Console/Parse.test.cc
new file mode 100644 (file)
index 0000000..a6d170b
--- /dev/null
@@ -0,0 +1,168 @@
+// $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 Parse.test unit tests */
+
+//#include "Parse.test.hh"
+//#include "Parse.test.ih"
+
+// Custom includes
+#include <sstream>
+#include "Parse.hh"
+#include "Parse.ih"
+
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace 
+{
+    struct TestParseDispatcher 
+    {
+        TestParseDispatcher(std::ostream & os) : os_ (os) {}
+
+        std::ostream & os_;
+
+        void beginCommand(std::string const & command) 
+            { os_ << "beginCommand( " << command << " )\n"; }
+        void endCommand() 
+            { os_ << "endCommand()\n"; }
+        
+        void pushArgument(std::string const & argument)
+            { os_ << "pushArgument( " << argument << " )\n"; }
+        void openGroup()
+            { os_ << "openGroup()\n"; }
+        void closeGroup()
+            { os_ << "closeGroup()\n"; }
+        void pushPunctuation(std::string const & token)
+            { os_ << "pushPunctuation( " << token << " )\n"; }
+        void pushWord(std::string const & token)
+            { os_ << "pushWord( " << token << " )\n"; }
+    };
+}
+
+BOOST_AUTO_UNIT_TEST(commandParser)
+{
+    senf::console::detail::CommandGrammar<TestParseDispatcher>::Context context;
+    std::stringstream ss;
+    TestParseDispatcher dispatcher (ss);
+    senf::console::detail::CommandGrammar<TestParseDispatcher> grammar (dispatcher, context);
+    senf::console::detail::SkipGrammar skipGrammar;
+
+    char text[] = 
+        "# Comment\n"
+        "doo / bii / doo arg/../path"
+        "                flab::blub"
+        "                123.434>a"
+        "                (a,b,c (huhu))"
+        "                \"foo\\\"bar\" #\n"
+        "                x\"01 02 # Inner comment\n"
+        "                   0304\"";
+
+    BOOST_CHECK( boost::spirit::parse( 
+                     text, 
+                     grammar, 
+                     skipGrammar ) . full );
+    BOOST_CHECK_EQUAL( ss.str(), 
+                       "beginCommand( doo/bii/doo )\n"
+                       "pushArgument( arg/../path )\n"
+                       "pushArgument( flab::blub )\n"
+                       "pushArgument( 123.434>a )\n"
+                       "openGroup()\n"
+                       "pushWord( a )\n"
+                       "pushPunctuation( , )\n"
+                       "pushWord( b )\n"
+                       "pushPunctuation( , )\n"
+                       "pushWord( c )\n"
+                       "pushPunctuation( ( )\n"
+                       "pushWord( huhu )\n"
+                       "pushPunctuation( ) )\n"
+                       "closeGroup()\n"
+                       "pushArgument( foo\"bar )\n"
+                       "pushArgument( \x01\x02\x03\x04 )\n"
+                       "endCommand()\n" );
+}
+
+BOOST_AUTO_UNIT_TEST(singleCommandParser)
+{
+    senf::console::SingleCommandParser parser;
+
+    char const text[] = 
+        "# Comment\n"
+        "doo / bii / doo arg/../path"
+        "                flab::blub"
+        "                123.434>a"
+        "                (a,b,c (huhu))"
+        "                \"foo\\\"bar\" #\n"
+        "                x\"01 02 # Inner comment\n"
+        "                   0304\"";
+
+    senf::console::ParseCommandInfo info;
+    BOOST_CHECK( parser.parseCommand(text, info) );
+
+    BOOST_CHECK_EQUAL( info.commandPath(), "doo/bii/doo" );
+    BOOST_REQUIRE_EQUAL( info.arguments(), 6u );
+    BOOST_REQUIRE_EQUAL( info.tokens(), 13u );
+
+    char const * tokens[] = { "arg/../path", 
+                              "flab::blub", 
+                              "123.434>a", 
+                              "a", ",", "b", ",", "c", "(", "huhu", ")",
+                              "foo\"bar",
+                              "\x01\x02\x03\x04" };
+
+    BOOST_REQUIRE_EQUAL( info.begin_arguments()[0].size(), 1u );
+    BOOST_CHECK_EQUAL( info.begin_arguments()[0].begin()->value(), tokens[0] );
+
+    BOOST_REQUIRE_EQUAL( info.begin_arguments()[1].size(), 1u );
+    BOOST_CHECK_EQUAL( info.begin_arguments()[1].begin()->value(), tokens[1] );
+
+    BOOST_REQUIRE_EQUAL( info.begin_arguments()[2].size(), 1u );
+    BOOST_CHECK_EQUAL( info.begin_arguments()[2].begin()->value(), tokens[2] );
+
+    BOOST_REQUIRE_EQUAL( info.begin_arguments()[3].size(), 8u );
+    for (unsigned i (0); i<8; ++i)
+        BOOST_CHECK_EQUAL( info.begin_arguments()[3].begin()[i].value(), tokens[3+i] );
+
+    BOOST_REQUIRE_EQUAL( info.begin_arguments()[4].size(), 1u );
+    BOOST_CHECK_EQUAL( info.begin_arguments()[4].begin()->value(), tokens[11] );
+
+    BOOST_REQUIRE_EQUAL( info.begin_arguments()[5].size(), 1u );
+    BOOST_CHECK_EQUAL( info.begin_arguments()[5].begin()->value(), tokens[12] );
+}
+
+///////////////////////////////cc.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:
diff --git a/Console/SConscript b/Console/SConscript
new file mode 100644 (file)
index 0000000..ce543c3
--- /dev/null
@@ -0,0 +1,14 @@
+# -*- python -*-
+
+Import('env')
+import SENFSCons
+
+###########################################################################
+
+sources = SENFSCons.GlobSources()
+SENFSCons.StandardTargets(env)
+SENFSCons.Lib(env,
+              library = 'Console',
+              sources = sources,
+              LIBS = [ 'Socket', 'Scheduler', 'Utils' ])
+SENFSCons.Doxygen(env)
diff --git a/Console/main.test.cc b/Console/main.test.cc
new file mode 100644 (file)
index 0000000..b6d1686
--- /dev/null
@@ -0,0 +1,49 @@
+// $Id$
+//
+// Copyright (C) 2006
+// 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.
+
+// Definition of non-inline non-template functions
+
+//#include "test.hh"
+//#include "test.ih"
+
+// Custom includes
+#define BOOST_AUTO_TEST_MAIN
+#include "../Utils/auto_unit_test.hh"
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// comment-column: 40
+// End: