Console: Add builtin parsing
g0dil [Thu, 20 Mar 2008 17:28:27 +0000 (17:28 +0000)]
Console: Expose Server to libarary user

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

Console/Executor.cc
Console/Parse.cc
Console/Parse.cci
Console/Parse.hh
Console/Parse.ih
Console/Parse.test.cc
Console/Server.cc
Console/Server.cci [new file with mode: 0644]
Console/Server.hh
Console/Server.ih [deleted file]
Console/testServer.cc

index 0a9285a..3865656 100644 (file)
@@ -39,7 +39,7 @@ prefix_ bool senf::console::Executor::operator()(ParseCommandInfo const & comman
                                                  std::ostream & output)
 {
 #   warning Implement Executor::operator()
-    SENF_LOG(( "Executing '" << command.commandPath() << "'" ));
+    SENF_LOG(( "Executing: " << command ));
     return true;
 }
 
index 502dd1c..1f8a6b2 100644 (file)
@@ -27,6 +27,7 @@
 #include "Parse.ih"
 
 // Custom includes
+#include "../Utils/String.hh"
 #include <boost/iterator/transform_iterator.hpp>
 
 //#include "Parse.mpp"
@@ -42,7 +43,10 @@ namespace detail {
         static void init(ParseCommandInfo & info)
             { info.init(); }
 
-        static void setCommand(ParseCommandInfo & info, std::string const & commandPath)
+        static void setBuiltin(ParseCommandInfo & info, ParseCommandInfo::BuiltinCommand builtin)
+            { info.setBuiltin(builtin); }
+
+        static void setCommand(ParseCommandInfo & info, std::vector<std::string> & commandPath)
             { info.setCommand(commandPath); }
 
         static void startArgument(ParseCommandInfo & info)
@@ -82,7 +86,7 @@ namespace detail {
             ParseDispatcher & dispatcher;
         };
 
-        void beginCommand(std::string const & command)
+        void beginCommand(std::vector<std::string> & command)
             { ParserAccess::init(info());
               ParserAccess::setCommand(info(), command); }
 
@@ -105,6 +109,27 @@ namespace detail {
 
         void pushWord(std::string const & token)
             { ParserAccess::addToken(info(), ParserAccess::makeToken(token)); }
+
+        void builtin_cd(std::vector<std::string> & path)
+            { ParserAccess::init(info());
+              ParserAccess::setBuiltin(info(), ParseCommandInfo::BuiltinCD);
+              setBuiltinPathArg(path);
+              ParserAccess::finalize(info()); }
+
+        void builtin_ls(std::vector<std::string> & path)
+            { ParserAccess::init(info());
+              ParserAccess::setBuiltin(info(), ParseCommandInfo::BuiltinLS);
+              setBuiltinPathArg(path);
+              ParserAccess::finalize(info()); }
+
+        void setBuiltinPathArg(std::vector<std::string> & path)
+            {
+                ParserAccess::startArgument(info());
+                for (std::vector<std::string>::const_iterator i (path.begin());
+                     i != path.end(); ++i)
+                    ParserAccess::addToken(info(), ParserAccess::makeToken(*i));
+                ParserAccess::endArgument(info());
+            }
     };
 
 }}}
@@ -139,15 +164,43 @@ prefix_ void senf::console::ParseCommandInfo::finalize()
     tempArguments_.clear();
 }
 
+prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
+                                                 ParseCommandInfo const & info)
+{
+    if (info.builtin() == ParseCommandInfo::NoBuiltin) 
+        stream << senf::stringJoin(info.commandPath(), "/");
+    else {
+        char const * builtins[] = { "", "cd", "ls" };
+        stream << "builtin-" << builtins[info.builtin()];
+    }
+        
+    ParseCommandInfo::ArgumentsRange args (info.arguments());
+    for (ParseCommandInfo::argument_iterator i (args.begin()); i != args.end(); ++i) {
+        ParseCommandInfo::token_iterator j (i->begin());
+        stream << " [";
+        if ( j != i->end() ) {
+            for (;;) {
+                stream << "'" << j->value() << "'";
+                if ( ++j != i->end() ) stream << ' ';
+                else                   break;
+            }
+        }
+        stream << "]";
+    }
+
+    return stream;
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::SingleCommandParser
 
 struct senf::console::SingleCommandParser::Impl
 {
+    typedef detail::CommandGrammar<detail::ParseDispatcher> Grammar;
+
     detail::ParseDispatcher dispatcher;
-    detail::CommandGrammar<detail::ParseDispatcher>::Context context;
-    detail::CommandGrammar<detail::ParseDispatcher> grammar;
-    detail::SkipGrammar skipGrammar;
+    Grammar::Context context;
+    Grammar grammar;
 
     Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
 };
@@ -163,7 +216,10 @@ prefix_ bool senf::console::SingleCommandParser::parseCommand(std::string comman
                                                               ParseCommandInfo & info)
 {
     detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info);
-    return boost::spirit::parse( command.c_str(), impl().grammar, impl().skipGrammar ).full;
+    return boost::spirit::parse( command.c_str(), 
+                                 impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
+                                 impl().grammar.use_parser<Impl::Grammar::SkipParser>()
+        ).full;
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index 1a72abf..0c7c0c6 100644 (file)
@@ -48,50 +48,31 @@ prefix_ senf::console::ArgumentToken::ArgumentToken(std::string token)
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::ParseCommandInfo
 
-prefix_ std::string const & senf::console::ParseCommandInfo::commandPath()
+prefix_ senf::console::ParseCommandInfo::BuiltinCommand
+senf::console::ParseCommandInfo::builtin()
     const
 {
-    return commandPath_;
+    return builtin_;
 }
 
-prefix_ senf::console::ParseCommandInfo::size_type senf::console::ParseCommandInfo::arguments()
+prefix_ senf::console::ParseCommandInfo::CommandPathRange
+senf::console::ParseCommandInfo::commandPath()
     const
 {
-    return arguments_.size();
+    return boost::make_iterator_range(commandPath_.begin(), commandPath_.end());
 }
 
-prefix_ senf::console::ParseCommandInfo::argument_iterator
-senf::console::ParseCommandInfo::begin_arguments()
+prefix_ senf::console::ParseCommandInfo::ArgumentsRange
+senf::console::ParseCommandInfo::arguments()
     const
 {
-    return arguments_.begin();
+    return boost::make_iterator_range(arguments_.begin(), arguments_.end());
 }
 
-prefix_ senf::console::ParseCommandInfo::argument_iterator
-senf::console::ParseCommandInfo::end_arguments()
+prefix_ senf::console::ParseCommandInfo::TokensRange senf::console::ParseCommandInfo::tokens()
     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();
+    return boost::make_iterator_range(tokens_.begin(), tokens_.end());
 }
 
 ////////////////////////////////////////
@@ -99,15 +80,23 @@ senf::console::ParseCommandInfo::end_tokens()
 
 prefix_ void senf::console::ParseCommandInfo::init()
 {
-    commandPath_ = "";
+    builtin_ = NoBuiltin;
+    commandPath_.clear();
     tokens_.clear();
     arguments_.clear();
     tempArguments_.clear();
 }
 
-prefix_ void senf::console::ParseCommandInfo::setCommand(std::string const & commandPath)
+prefix_ void senf::console::ParseCommandInfo::setBuiltin(BuiltinCommand builtin)
+{
+    builtin_ = builtin;
+}
+
+prefix_ void
+senf::console::ParseCommandInfo::setCommand(std::vector<std::string> & commandPath)
 {
-    commandPath_ = commandPath;
+    commandPath_.clear();
+    commandPath_.swap(commandPath);
 }
 
 prefix_ void senf::console::ParseCommandInfo::startArgument()
index 4a5d32a..3b059af 100644 (file)
@@ -64,11 +64,14 @@ namespace console {
     class ParseCommandInfo
     {
         typedef std::vector<ArgumentToken> Tokens;
+        typedef std::vector<std::string> CommandPath;
         
     public:
+        typedef CommandPath::const_iterator path_iterator;
         typedef Tokens::const_iterator token_iterator;
         typedef boost::iterator_range<token_iterator> argument_value_type;
 
+
     private:
         typedef std::vector<argument_value_type> Arguments;
 
@@ -76,21 +79,23 @@ namespace console {
         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;
+        typedef boost::iterator_range<path_iterator> CommandPathRange;
+        typedef boost::iterator_range<argument_iterator> ArgumentsRange;
+        typedef boost::iterator_range<token_iterator> TokensRange;
+
+        enum BuiltinCommand { NoBuiltin, BuiltinCD, BuiltinLS };
+
+        BuiltinCommand builtin() const;
+        CommandPathRange commandPath() const;
+        ArgumentsRange arguments() const;
+        TokensRange tokens() const;
         
     protected:
 
     private:
         void init();
-        void setCommand(std::string const & commandPath);
+        void setBuiltin(BuiltinCommand builtin);
+        void setCommand(std::vector<std::string> & commandPath);
         void startArgument();
         void endArgument();
         void addToken(ArgumentToken const & token);
@@ -98,11 +103,12 @@ namespace console {
 
         struct MakeRange;
 
-        std::string commandPath_;
+        std::vector<std::string> commandPath_;
 
         typedef std::pair<Tokens::size_type, Tokens::size_type> TempArgumentRange;
         typedef std::vector<TempArgumentRange> TempArguments;
 
+        BuiltinCommand builtin_;
         Tokens tokens_;
         Arguments arguments_;
         TempArguments tempArguments_;
@@ -110,6 +116,8 @@ namespace console {
         friend class detail::ParserAccess;
     };
 
+    std::ostream & operator<<(std::ostream & stream, ParseCommandInfo const & info);
+
     /** \brief
       */
     class SingleCommandParser
index d5a9e2d..54c2c45 100644 (file)
 #define IH_Parse_ 1
 
 // Custom includes
+#include <vector>
 #include <boost/regex.hpp>
 #include <boost/spirit.hpp>
-#include <boost/spirit/utility/regex.hpp>
+#include <boost/spirit/utility/grammar_def.hpp>
 #include <boost/spirit/actor.hpp>
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
@@ -70,10 +71,16 @@ namespace detail {
     struct CommandGrammar : boost::spirit::grammar<CommandGrammar<ParseDispatcher> >
     {
         ///////////////////////////////////////////////////////////////////////////
+        // Start rules
+
+        enum { CommandParser, SkipParser };
+
+        ///////////////////////////////////////////////////////////////////////////
         // The parse context (variables needed while parsing)
 
         struct Context {
             std::string str;
+            std::vector<std::string> path;
             char ch;
         };
 
@@ -113,19 +120,61 @@ namespace detail {
             : context(c), dispatcher(d) {}
 
         template <class Scanner>
-        struct definition
+        struct definition 
+            : public boost::spirit::grammar_def< boost::spirit::rule<Scanner>, 
+                                                 boost::spirit::rule<Scanner> >
         {
             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;
+            boost::spirit::rule<Scanner> complex_argument, builtin, skip;
+
+            boost::spirit::chset<> special_p, punctuation_p, space_p, invalid_p, word_p;
+
+            boost::spirit::distinct_parser<> keyword_p;
+
+            definition(CommandGrammar const & self) : 
+
+                // Characters with a special meaning within the parser
+                // and characters reserved for future extensions
+                special_p ("/(){};"),
 
-            definition(CommandGrammar const & self) {
+                // Characters which are returned as punctuation tokens
+                punctuation_p (",="),
+
+                // Whitespace characters (we don't want newlines in there)
+                space_p (" \t"),
+
+                // Invalid characters: All chars below \x20 (space) which are not space_p
+                // (don't put a \0 in the chset<> argument *string* ...)
+                invalid_p (
+                    boost::spirit::chset<>('\0') | boost::spirit::chset<>("\x01-\x20") - space_p ),
+
+                // Valid word characters
+                word_p (
+                    boost::spirit::anychar_p - special_p - punctuation_p - space_p - invalid_p),
+
+                // Keywords must not be followed by a word char or '/'
+                keyword_p ( word_p | boost::spirit::ch_p('/') )
+
+            {
                 using namespace boost::spirit;
                 typedef ParseDispatcher PD;
-                
+
+                builtin
+                    =    keyword_p("cd") 
+                      >> path
+                      >> eps_p                    [ self.dispatch(&PD::builtin_cd,
+                                                                  boost::ref(self.context.path)) ]
+                    |    keyword_p("ls") 
+                      >> ! path
+                      >> eps_p                    [ self.dispatch(&PD::builtin_cd,
+                                                                  boost::ref(self.context.path)) ]
+                    ;
+
                 command 
-                    =    path                     [ self.dispatch(&PD::beginCommand, 
-                                                                  boost::cref(self.context.str)) ]
+                    =    builtin
+                    |    path                     [ self.dispatch(&PD::beginCommand, 
+                                                                  boost::ref(self.context.path)) ]
                       >> * argument
                       >> ! ch_p(';')
                       >> eps_p                    [ self.dispatch(&PD::endCommand) ]
@@ -133,14 +182,14 @@ namespace detail {
 
                 argument
                     =    simple_argument          [ self.dispatch(&PD::pushArgument, 
-                                                                  boost::cref(self.context.str)) ]
+                                                                  boost::ref(self.context.str)) ]
                     |    complex_argument
                     ;
                 
                 simple_argument         // All these return their value in context.str
                     =    string
                     |    hexstring
-                    |    path
+                    |    word
                     ;
                 
                 complex_argument        // Argument consists of multiple tokens
@@ -168,13 +217,12 @@ namespace detail {
                       >> 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) ] 
-                         )
+                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) ] 
+                           % ch_p('/') )
+                      >> ( ! ch_p('/')            [ push_back_a(self.context.path,"") ] )
                     ;
 
                 balanced_tokens 
@@ -185,18 +233,18 @@ namespace detail {
 
                 token
                     =    simple_argument          [ self.dispatch(&PD::pushWord, 
-                                                                  boost::cref(self.context.str)) ]
+                                                                  boost::ref(self.context.str)) ]
                     |    punctuation              [ self.dispatch(&PD::pushPunctuation,
-                                                                  boost::cref(self.context.str)) ]
+                                                                  boost::ref(self.context.str)) ]
                     |    balanced_tokens
                     ;
 
                 punctuation             // Returns value in context.str
-                    =    regex_p("[,=]")          [ assign_a(self.context.str) ]
+                    =    punctuation_p            [ assign_a(self.context.str) ]
                     ;
 
-                word
-                    =    regex_p("[^ \t\n\r;,=(){}/\"]+")
+                word                    // Returns value in context.str
+                    =    lexeme_d[ + word_p ]     [ assign_a(self.context.str) ]
                     ;
 
                 hexbyte
@@ -204,40 +252,31 @@ namespace detail {
                                                   [ 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; }
-        };
-    };
+                skip
+                    =    space_p
+                    |    comment_p('#')
+                    ;
 
-    struct SkipGrammar
-        : public boost::spirit::grammar<SkipGrammar>
-    {
-        template <class Scanner>
-        struct definition
-        {
-            boost::spirit::rule<Scanner> rule;
+                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(word,1);
+                BOOST_SPIRIT_DEBUG_TRACE_RULE(string,1);
+                BOOST_SPIRIT_DEBUG_TRACE_RULE(hexstring,1);
+                BOOST_SPIRIT_DEBUG_TRACE_RULE(token,1);
+                BOOST_SPIRIT_DEBUG_TRACE_RULE(punctuation,1);
+                BOOST_SPIRIT_DEBUG_TRACE_RULE(hexbyte,1);
+                BOOST_SPIRIT_DEBUG_TRACE_RULE(balanced_tokens,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(
+                    command,            // CommandParser
+                    skip                // SkipParser
+                );
 
-            definition(SkipGrammar const & self) {
-                rule 
-                    =    boost::spirit::regex_p("[ \t]+") 
-                    |    boost::spirit::comment_p('#')
-                    ;
             }
-
-            boost::spirit::rule<Scanner> const & start() const { return rule; }
         };
     };
 
index a6d170b..11d8a38 100644 (file)
 //#include "Parse.test.hh"
 //#include "Parse.test.ih"
 
+// #define BOOST_SPIRIT_DEBUG
+// #define BOOST_SPIRIT_DEBUG_TRACENODE 0
+
 // Custom includes
 #include <sstream>
 #include "Parse.hh"
 #include "Parse.ih"
+#include "../Utils/String.hh"
 
 #include <boost/test/auto_unit_test.hpp>
 #include <boost/test/test_tools.hpp>
 
 namespace 
 {
+    
+
     struct TestParseDispatcher 
     {
         TestParseDispatcher(std::ostream & os) : os_ (os) {}
 
         std::ostream & os_;
 
-        void beginCommand(std::string const & command) 
-            { os_ << "beginCommand( " << command << " )\n"; }
+        void beginCommand(std::vector<std::string> const & command) 
+            { os_ << "beginCommand( " << senf::stringJoin(command, "/") << " )\n"; }
         void endCommand() 
             { os_ << "endCommand()\n"; }
         
@@ -60,6 +66,11 @@ namespace
             { os_ << "pushPunctuation( " << token << " )\n"; }
         void pushWord(std::string const & token)
             { os_ << "pushWord( " << token << " )\n"; }
+
+        void builtin_cd(std::vector<std::string> const & path)
+            { os_ << "builtin_cd( " << senf::stringJoin(path, "/") << " )\n"; }
+        void builtin_ls(std::vector<std::string> const & path)
+            { os_ << "builtin_cd( " << senf::stringJoin(path, "/") << " )\n"; }
     };
 }
 
@@ -68,12 +79,13 @@ 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;
+    
+    typedef senf::console::detail::CommandGrammar<TestParseDispatcher> Grammar;
+    Grammar grammar (dispatcher, context);
 
     char text[] = 
         "# Comment\n"
-        "doo / bii / doo arg/../path"
+        "doo / bii / doo arg"
         "                flab::blub"
         "                123.434>a"
         "                (a,b,c (huhu))"
@@ -83,11 +95,11 @@ BOOST_AUTO_UNIT_TEST(commandParser)
 
     BOOST_CHECK( boost::spirit::parse( 
                      text, 
-                     grammar, 
-                     skipGrammar ) . full );
+                     grammar.use_parser<Grammar::CommandParser>(), 
+                     grammar.use_parser<Grammar::SkipParser>() ) . full );
     BOOST_CHECK_EQUAL( ss.str(), 
                        "beginCommand( doo/bii/doo )\n"
-                       "pushArgument( arg/../path )\n"
+                       "pushArgument( arg )\n"
                        "pushArgument( flab::blub )\n"
                        "pushArgument( 123.434>a )\n"
                        "openGroup()\n"
@@ -111,7 +123,7 @@ BOOST_AUTO_UNIT_TEST(singleCommandParser)
 
     char const text[] = 
         "# Comment\n"
-        "doo / bii / doo arg/../path"
+        "doo / bii / doo arg"
         "                flab::blub"
         "                123.434>a"
         "                (a,b,c (huhu))"
@@ -122,35 +134,38 @@ BOOST_AUTO_UNIT_TEST(singleCommandParser)
     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 * path[] = { "doo", "bii", "doo" };
+
+    BOOST_CHECK_EQUAL_COLLECTIONS( info.commandPath().begin(), info.commandPath().end(),
+                                   path, path + sizeof(path)/sizeof(path[0]) );
+    BOOST_REQUIRE_EQUAL( info.arguments().size(), 6u );
+    BOOST_REQUIRE_EQUAL( info.tokens().size(), 13u );
 
-    char const * tokens[] = { "arg/../path", 
+    char const * tokens[] = { "arg", 
                               "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.arguments().begin()[0].size(), 1u );
+    BOOST_CHECK_EQUAL( info.arguments().begin()[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.arguments().begin()[1].size(), 1u );
+    BOOST_CHECK_EQUAL( info.arguments().begin()[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.arguments().begin()[2].size(), 1u );
+    BOOST_CHECK_EQUAL( info.arguments().begin()[2].begin()->value(), tokens[2] );
 
-    BOOST_REQUIRE_EQUAL( info.begin_arguments()[3].size(), 8u );
+    BOOST_REQUIRE_EQUAL( info.arguments().begin()[3].size(), 8u );
     for (unsigned i (0); i<8; ++i)
-        BOOST_CHECK_EQUAL( info.begin_arguments()[3].begin()[i].value(), tokens[3+i] );
+        BOOST_CHECK_EQUAL( info.arguments().begin()[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.arguments().begin()[4].size(), 1u );
+    BOOST_CHECK_EQUAL( info.arguments().begin()[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] );
+    BOOST_REQUIRE_EQUAL( info.arguments().begin()[5].size(), 1u );
+    BOOST_CHECK_EQUAL( info.arguments().begin()[5].begin()->value(), tokens[12] );
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index 0fd831d..5790d83 100644 (file)
@@ -24,7 +24,7 @@
     \brief Server non-inline non-template implementation */
 
 #include "Server.hh"
-#include "Server.ih"
+//#include "Server.ih"
 
 // Custom includes
 #include <unistd.h>
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
-prefix_ void senf::console::start(senf::INet4SocketAddress const & address)
+prefix_ senf::console::Server &
+senf::console::Server::start(senf::INet4SocketAddress const & address)
 {
     senf::TCPv4ServerSocketHandle handle (address);
-    handle.protocol().reuseaddr();
-    senf::console::detail::Server::start(handle);
-    SENF_LOG((detail::Server::SENFLogArea)(log::NOTICE)( 
+    senf::console::Server::start(handle);
+    SENF_LOG((Server::SENFLogArea)(log::NOTICE)( 
                  "Console server started at " << address ));
+    return *instance_;
 }
 
-prefix_ void senf::console::start(senf::INet6SocketAddress const & address)
+prefix_ senf::console::Server &
+senf::console::Server::start(senf::INet6SocketAddress const & address)
 {
     senf::TCPv6ServerSocketHandle handle (address);
-    handle.protocol().reuseaddr();
-    senf::console::detail::Server::start(handle);
-    SENF_LOG((detail::Server::SENFLogArea)(log::NOTICE)( 
+    senf::console::Server::start(handle);
+    SENF_LOG((Server::SENFLogArea)(log::NOTICE)( 
                  "Console server started at " << address ));
+    return *instance_;
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// senf::console::detail::Server
+// senf::console::Server
 
-boost::scoped_ptr<senf::console::detail::Server> senf::console::detail::Server::instance_;
+boost::scoped_ptr<senf::console::Server> senf::console::Server::instance_;
 
-prefix_ void senf::console::detail::Server::start(ServerHandle handle)
+prefix_ void senf::console::Server::start(ServerHandle handle)
 {
     SENF_ASSERT( ! instance_ );
     instance_.reset(new Server(handle));
 }
 
-prefix_ senf::console::detail::Server::Server(ServerHandle handle)
+prefix_ senf::console::Server::Server(ServerHandle handle)
     : handle_ (handle)
 {
     Scheduler::instance().add( handle_, senf::membind(&Server::newClient, this) );
 }
 
-prefix_ senf::console::detail::Server::~Server()
+prefix_ senf::console::Server::~Server()
 {
     Scheduler::instance().remove(handle_);
 }
 
-prefix_ void senf::console::detail::Server::newClient(Scheduler::EventId event)
+prefix_ void senf::console::Server::newClient(Scheduler::EventId event)
 {
     ServerHandle::ClientSocketHandle client (handle_.accept());
-    boost::intrusive_ptr<Client> p (new Client(client));
+    boost::intrusive_ptr<Client> p (new Client(client, name_));
     clients_.insert( p );
     SENF_LOG(( "Registered new client " << p.get() ));
 }
 
-prefix_ void senf::console::detail::Server::removeClient(Client & client)
+prefix_ void senf::console::Server::removeClient(Client & client)
 {
     SENF_LOG(( "Disposing client " << & client ));
     // THIS DELETES THE CLIENT INSTANCE !!
@@ -96,26 +98,26 @@ prefix_ void senf::console::detail::Server::removeClient(Client & client)
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// senf::console::detail::Client
+// senf::console::Client
 
-prefix_ senf::console::detail::Client::Client(ClientHandle handle)
-    : handle_ (handle), out_(::dup(handle.fd()))
+prefix_ senf::console::Client::Client(ClientHandle handle, std::string const & name)
+    : handle_ (handle), name_ (name), out_(::dup(handle.fd()))
 {
-    out_ << "# " << std::flush;
+    out_ << name_ << "# " << std::flush;
     ReadHelper<ClientHandle>::dispatch( handle_, 16384u, ReadUntil("\n"),
                                         senf::membind(&Client::clientData, this) );
 }
 
-prefix_ senf::console::detail::Client::~Client()
+prefix_ senf::console::Client::~Client()
 {}
 
-prefix_ void senf::console::detail::Client::stopClient()
+prefix_ void senf::console::Client::stopClient()
 {
     // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER removeClient RETURNS
     Server::instance_->removeClient(*this);
 }
 
-prefix_ void senf::console::detail::Client::clientData(ReadHelper<ClientHandle>::ptr helper)
+prefix_ void senf::console::Client::clientData(ReadHelper<ClientHandle>::ptr helper)
 {
     if (helper->error() || handle_.eof()) {
         // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS
@@ -132,13 +134,19 @@ prefix_ void senf::console::detail::Client::clientData(ReadHelper<ClientHandle>:
     tail_ = helper->tail();
     boost::trim(data); // Gets rid of superfluous  \r or \n characters
 
+    if (data == "exit") {
+        // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS
+        stopClient();
+        return;
+    }
+        
     ParseCommandInfo command;
     if (parser_.parseCommand(data, command))
         executor_(command, out_);
     else 
         out_ << "syntax error" << std::endl;
 
-    out_ << "# " << std::flush;
+    out_ << name_ << "# " << std::flush;
     ReadHelper<ClientHandle>::dispatch( handle_, 16384u, ReadUntil("\n"),
                                         senf::membind(&Client::clientData, this) );
 }
diff --git a/Console/Server.cci b/Console/Server.cci
new file mode 100644 (file)
index 0000000..12e0c00
--- /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 Server inline non-template implementation */
+
+//#include "Server.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::Server
+
+prefix_ void senf::console::Server::name(std::string const & name)
+{
+    name_ = name;
+}
+
+///////////////////////////////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:
index 09bfbaf..e21eea6 100644 (file)
 #define HH_Server_ 1
 
 // Custom includes
+#include <set>
+#include <boost/utility.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/iostreams/device/file_descriptor.hpp>
+#include <boost/iostreams/stream.hpp>
+#include "../Utils/intrusive_refcount.hh"
+#include "../Socket/Protocols/INet/TCPSocketHandle.hh"
+#include "../Socket/ServerSocketHandle.hh"
+#include "../Scheduler/Scheduler.hh"
+#include "../Scheduler/ReadHelper.hh"
+#include "Parse.hh"
+#include "Executor.hh"
 #include "../Socket/Protocols/INet/INetAddressing.hh"
 
 //#include "Server.mpp"
 namespace senf {
 namespace console {
 
-    void start(senf::INet4SocketAddress const & address);
-    void start(senf::INet6SocketAddress const & address);
+    class Client;
+
+    /** \brief
+      */
+    class Server
+        : boost::noncopyable
+    {
+        SENF_LOG_CLASS_AREA();
+        SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        typedef senf::ServerSocketHandle<
+            senf::MakeSocketPolicy< senf::TCPv4SocketProtocol::Policy, 
+                                    senf::UnspecifiedAddressingPolicy>::policy > ServerHandle;
+
+        ~Server();
+
+        static Server & start(senf::INet4SocketAddress const & address);
+        static Server & start(senf::INet6SocketAddress const & address);
+
+        void name(std::string const & name);
+
+    protected:
+
+    private:
+        Server(ServerHandle handle);
+
+        static void start(ServerHandle handle);
+
+        void newClient(Scheduler::EventId event);
+        void removeClient(Client & client);
+        
+        ServerHandle handle_;
+        
+        typedef std::set< boost::intrusive_ptr<Client> > Clients;
+        Clients clients_;
+        std::string name_;
+        
+        static boost::scoped_ptr<Server> instance_;
+        
+        friend class Client;
+    };
+    
+    /** \brief
+     */
+    class Client
+        : public senf::intrusive_refcount
+    {
+        SENF_LOG_CLASS_AREA();
+        SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
+    public:
+        typedef Server::ServerHandle::ClientSocketHandle ClientHandle;
+
+        ~Client();
+
+        void stopClient();
+
+    protected:
+        
+    private:
+        Client(ClientHandle handle, std::string const & name);
+
+        void clientData(ReadHelper<ClientHandle>::ptr helper);
+        
+        ClientHandle handle_;
+        std::string tail_;
+        SingleCommandParser parser_;
+        Executor executor_;
+        std::string name_;
+
+        typedef boost::iostreams::stream<boost::iostreams::file_descriptor_sink> fdostream;
+        fdostream out_;
+
+        friend class Server;
+    };
 
 }}
 
 ///////////////////////////////hh.e////////////////////////////////////////
-//#include "Server.cci"
+#include "Server.cci"
 //#include "Server.ct"
 //#include "Server.cti"
 #endif
diff --git a/Console/Server.ih b/Console/Server.ih
deleted file mode 100644 (file)
index d25aed3..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-// $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 Server internal header */
-
-#ifndef IH_Server_
-#define IH_Server_ 1
-
-// Custom includes
-#include <set>
-#include <boost/utility.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/iostreams/device/file_descriptor.hpp>
-#include <boost/iostreams/stream.hpp>
-#include "../Utils/intrusive_refcount.hh"
-#include "../Socket/Protocols/INet/TCPSocketHandle.hh"
-#include "../Socket/ServerSocketHandle.hh"
-#include "../Scheduler/Scheduler.hh"
-#include "../Scheduler/ReadHelper.hh"
-#include "Parse.hh"
-#include "Executor.hh"
-
-///////////////////////////////ih.p////////////////////////////////////////
-
-namespace senf {
-namespace console {
-namespace detail {
-
-    class Client;
-
-    /** \brief
-      */
-    class Server
-        : boost::noncopyable
-    {
-        SENF_LOG_CLASS_AREA();
-        SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
-    public:
-        ///////////////////////////////////////////////////////////////////////////
-        // Types
-
-        typedef senf::ServerSocketHandle<
-            senf::MakeSocketPolicy< senf::TCPv4SocketProtocol::Policy, 
-                                    senf::UnspecifiedAddressingPolicy>::policy > ServerHandle;
-
-        ~Server();
-
-        static void start(ServerHandle handle);
-
-    protected:
-
-    private:
-        Server(ServerHandle handle);
-
-        void newClient(Scheduler::EventId event);
-        void removeClient(Client & client);
-        
-        ServerHandle handle_;
-        
-        typedef std::set< boost::intrusive_ptr<Client> > Clients;
-        Clients clients_;
-        
-        static boost::scoped_ptr<Server> instance_;
-        
-        friend class Client;
-    };
-    
-    /** \brief
-     */
-    class Client
-        : public senf::intrusive_refcount
-    {
-        SENF_LOG_CLASS_AREA();
-        SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
-    public:
-        typedef Server::ServerHandle::ClientSocketHandle ClientHandle;
-
-        ~Client();
-
-        void stopClient();
-
-    protected:
-        
-    private:
-        Client(ClientHandle handle);
-
-        void clientData(ReadHelper<ClientHandle>::ptr helper);
-        
-        ClientHandle handle_;
-        std::string tail_;
-        SingleCommandParser parser_;
-        Executor executor_;
-
-        typedef boost::iostreams::stream<boost::iostreams::file_descriptor_sink> fdostream;
-        fdostream out_;
-
-        friend class Server;
-    };
-
-}}}
-
-///////////////////////////////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:
index caf9106..8e9323a 100644 (file)
@@ -40,7 +40,8 @@ int main(int, char const **)
 {
     senf::log::ConsoleTarget::instance().route< senf::SenfLog, senf::log::NOTICE >();
 
-    senf::console::start( senf::INet4SocketAddress("127.0.0.1:23232") );
+    senf::console::Server::start( senf::INet4SocketAddress("127.0.0.1:23232") )
+        .name("testServer ");
 
     senf::Scheduler::instance().process();
 }