Console: Refactor argument parsing into iterator
g0dil [Fri, 9 May 2008 09:17:22 +0000 (09:17 +0000)]
Scheduler: Make Scheduler more robust by ignoring closed file descriptors

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

14 files changed:
Console/Executor.cc
Console/Executor.hh
Console/Mainpage.dox
Console/Parse.cc
Console/Parse.cci
Console/Parse.hh
Console/Parse.ih
Console/Parse.test.cc
Console/ParsedCommand.mpp
Console/testServer.cc
Scheduler/Scheduler.cc
Utils/Backtrace.cc
Utils/Backtrace.hh
Utils/Daemon/Daemon.test.cc

index 4d9b2f9..fdbb850 100644 (file)
@@ -60,7 +60,7 @@ prefix_ void senf::console::Executor::execute(std::ostream & output,
             GenericNode & node ( traverseCommand(command.commandPath()) );
             DirectoryNode * dir ( dynamic_cast<DirectoryNode*>(&node) );
             if ( dir ) {
-                if (autocd_ && command.arguments().empty()) {
+                if (autocd_ && command.tokens().empty()) {
                     oldCwd_ = cwd_;
                     cwd_ = dir->thisptr();
                 } else
@@ -83,14 +83,14 @@ prefix_ void senf::console::Executor::execute(std::ostream & output,
                 }
                 else {
                     oldCwd_ = cwd_;
-                    cwd_ = traverseDirectory(command.arguments().begin()[0]).thisptr();
+                    cwd_ = traverseDirectory(*command.arguments().begin()).thisptr();
                 }
             }
             break;
             
         case ParseCommandInfo::BuiltinLS : {
             DirectoryNode const & dir ( command.arguments()
-                                        ? traverseDirectory(command.arguments().begin()[0])
+                                        ? traverseDirectory(*command.arguments().begin())
                                         : cwd() );
             for (DirectoryNode::child_iterator i (dir.children().begin());
                  i != dir.children().end(); ++i) {
@@ -105,7 +105,7 @@ prefix_ void senf::console::Executor::execute(std::ostream & output,
         case ParseCommandInfo::BuiltinPUSHD :
             dirstack_.push_back(cwd_);
             if ( command.arguments() )
-                cwd_ = traverseDirectory(command.arguments().begin()[0]).thisptr();
+                cwd_ = traverseDirectory(*command.arguments().begin()).thisptr();
             break;
             
         case ParseCommandInfo::BuiltinPOPD :
@@ -120,7 +120,7 @@ prefix_ void senf::console::Executor::execute(std::ostream & output,
 
         case ParseCommandInfo::BuiltinHELP :
             GenericNode const & node (command.arguments() 
-                                      ? traverseNode(command.arguments().begin()[0])
+                                      ? traverseNode(*command.arguments().begin())
                                       : cwd());
             output << prettyName(typeid(node)) << " at " << node.path() << "\n\n";
             node.help(output);
@@ -141,7 +141,7 @@ prefix_ void senf::console::Executor::execute(std::ostream & output,
 }
 
 prefix_ senf::console::GenericNode &
-senf::console::Executor::traverseNode(ParseCommandInfo::argument_value_type const & path)
+senf::console::Executor::traverseNode(ParseCommandInfo::TokensRange const & path)
 {
     try {
         return cwd().traverse(
@@ -173,7 +173,7 @@ senf::console::Executor::traverseCommand(ParseCommandInfo::CommandPathRange cons
 }
 
 prefix_ senf::console::DirectoryNode &
-senf::console::Executor::traverseDirectory(ParseCommandInfo::argument_value_type const & path)
+senf::console::Executor::traverseDirectory(ParseCommandInfo::TokensRange const & path)
 {
     try {
         return dynamic_cast<DirectoryNode&>( traverseNode(path) );
index 92a2dfe..86e54be 100644 (file)
@@ -107,9 +107,9 @@ namespace console {
     protected:
 
     private:
-        GenericNode & traverseNode(ParseCommandInfo::argument_value_type const & path);
+        GenericNode & traverseNode(ParseCommandInfo::TokensRange const & path);
         GenericNode & traverseCommand(ParseCommandInfo::CommandPathRange const & path); 
-        DirectoryNode & traverseDirectory(ParseCommandInfo::argument_value_type const & path);
+        DirectoryNode & traverseDirectory(ParseCommandInfo::TokensRange const & path);
 
         struct InvalidPathException {};
         struct InvalidDirectoryException {};
index e6cf404..d094f24 100644 (file)
     \code
     void fun1(std::ostream & os, senf::console::ParseCommandInfo const & command)
     {
-        // We take exactly one argument
-        if (command.arguments().size() != 1) 
+        ParseCommandInfo::ArgumentsRange args (command.arguments());
+        ParseCommandInfo::ArgumentsRange::iterator arg (args.begin());
+
+        // Check that we are not missing our argument
+        if (arg == args.end())
             raise senf::console::SyntaxErrorException("invalid number of arguments");
 
-        senf::console::ParseCommandInfo::TokensRange & argTokens (
-            command.arguments()[0]);
+        senf::console::ParseCommandInfo::TokensRange & arg1Tokens ( *(arg++) );
+
+        // Check that we don't have additional arguments
+        if (arg != args.end())
+            raise senf::console::SyntaxErrorException("invalid number of arguments");
 
         // The argument must have exactly one token
-        if (argTokens.size() != 1)
+        if (arg1Tokens.size() != 1)
             raise senf::console::SyntaxErrorException("argument syntax error");
 
         // Retrieve the token value
index c06a2bc..52858e9 100644 (file)
@@ -54,20 +54,11 @@ namespace detail {
         static void setCommand(ParseCommandInfo & info, std::vector<std::string> & 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); }
+        static ArgumentToken makeToken(ArgumentToken::TokenType type, std::string const & token)
+            { return ArgumentToken(type, token); }
     };
 
     struct ParseDispatcher
@@ -88,66 +79,77 @@ namespace detail {
               ParserAccess::setCommand(info_, command); }
 
         void endCommand()
-            { ParserAccess::finalize(info_); cb_(info_); }
+            { cb_(info_); }
 
-        void pushArgument(std::string const & argument)
-            { ParserAccess::startArgument(info_); 
-              ParserAccess::addToken(info_, ParserAccess::makeToken(argument)); 
-              ParserAccess::endArgument(info_); }
+        void pushArgument(ArgumentToken::TokenType type, std::string const & argument)
+            { ParserAccess::addToken(info_, ParserAccess::makeToken(type, argument)); }
 
         void openGroup()
-            { ParserAccess::startArgument(info_); }
+            { pushPunctuation("("); }
 
         void closeGroup()
-            { ParserAccess::endArgument(info_); }
+            { pushPunctuation(")"); }
 
         void pushPunctuation(std::string const & token)
-            { ParserAccess::addToken(info_, ParserAccess::makeToken(token)); }
+            {
+                ArgumentToken::TokenType type;
+                switch (token[0]) {
+                case '/' : type = ArgumentToken::PathSeparator; break;
+                case '(' : type = ArgumentToken::ArgumentGroupOpen; break;
+                case ')' : type = ArgumentToken::ArgumentGroupClose; break;
+                case '{' : type = ArgumentToken::DirectoryGroupOpen; break;
+                case '}' : type = ArgumentToken::DirectoryGroupClose; break;
+                case ';' : type = ArgumentToken::CommandTerminator; break;
+                default :  type = ArgumentToken::OtherPunctuation; break;
+                }
+                ParserAccess::addToken(info_, ParserAccess::makeToken(type, token));
+            }
 
-        void pushWord(std::string const & token)
-            { ParserAccess::addToken(info_, ParserAccess::makeToken(token)); }
+        void pushWord(ArgumentToken::TokenType type, std::string const & token)
+            { ParserAccess::addToken(info_, ParserAccess::makeToken(type, token)); }
 
         void builtin_cd(std::vector<std::string> & path)
             { ParserAccess::init(info_);
               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinCD);
               setBuiltinPathArg(path);
-              ParserAccess::finalize(info_); cb_(info_); }
+              cb_(info_); }
 
         void builtin_ls(std::vector<std::string> & path)
             { ParserAccess::init(info_);
               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinLS);
               setBuiltinPathArg(path);
-              ParserAccess::finalize(info_); cb_(info_); }
+              cb_(info_); }
 
         void pushDirectory(std::vector<std::string> & path)
             { ParserAccess::init(info_);
               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPUSHD);
               setBuiltinPathArg(path);
-              ParserAccess::finalize(info_); cb_(info_); }
+              cb_(info_); }
 
         void popDirectory()
             { ParserAccess::init(info_);
               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPOPD);
-              ParserAccess::finalize(info_); cb_(info_); }
+              cb_(info_); }
         
         void builtin_exit()
             { ParserAccess::init(info_);
               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinEXIT);
-              ParserAccess::finalize(info_); cb_(info_); }
+              cb_(info_); }
 
         void builtin_help(std::vector<std::string> & path)
             { ParserAccess::init(info_);
               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinHELP);
               setBuiltinPathArg(path);
-              ParserAccess::finalize(info_); cb_(info_); }
+              cb_(info_); }
 
         void setBuiltinPathArg(std::vector<std::string> & path)
             {
-                ParserAccess::startArgument(info_);
+                pushPunctuation("(");
                 for (std::vector<std::string>::const_iterator i (path.begin());
                      i != path.end(); ++i)
-                    ParserAccess::addToken(info_, ParserAccess::makeToken(*i));
-                ParserAccess::endArgument(info_);
+                    ParserAccess::addToken(info_, 
+                                           ParserAccess::makeToken(ArgumentToken::Word, *i));
+                pushPunctuation(")");
             }
     };
 
@@ -158,37 +160,6 @@ namespace detail {
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::ParseCommandInfo
 
-#ifndef DOXYGEN
-
-struct senf::console::ParseCommandInfo::MakeRange
-{
-    typedef ParseCommandInfo::argument_value_type result_type;
-    
-    MakeRange() {}
-    MakeRange(ParseCommandInfo::token_iterator b) : b_ (b) {}
-    
-    senf::console::ParseCommandInfo::token_iterator b_;
-    
-    result_type operator()(TempArguments::iterator::value_type const & v) const {
-        return result_type( b_ + v.first, b_ + v.second );
-    }
-};
-
-#endif
-
-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();
-}
-
 prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
                                                  ParseCommandInfo const & info)
 {
@@ -217,6 +188,48 @@ prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
 }
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::console::ParseCommandInfo::ArgumentIterator
+
+prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::setRange()
+    const
+{
+    if (b_->is(ArgumentToken::ArgumentGroupOpen)) {
+        unsigned level (0);
+        e_ = b_;
+        for (;;) {
+            if (e_->is(ArgumentToken::ArgumentGroupOpen))
+                ++ level;
+            else if (e_->is(ArgumentToken::ArgumentGroupClose)) {
+                -- level;
+                if (level == 0)
+                    break;
+            }
+            ++e_;
+        }
+    }
+    ++ e_;
+}
+
+prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::decrement()
+{
+    e_ = b_;
+    --b_;
+    if (b_->is(ArgumentToken::ArgumentGroupClose)) {
+        unsigned level (0);
+        for (;;) {
+            if (b_->is(ArgumentToken::ArgumentGroupClose))
+                ++ level;
+            else if (b_->is(ArgumentToken::ArgumentGroupOpen)) {
+                -- level;
+                if (level == 0)
+                    break;
+            }
+            --b_;
+        }
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
 // senf::console::CommandParser
 
 #ifndef DOXYGEN
index c85fad8..c9ff9ad 100644 (file)
@@ -41,8 +41,20 @@ prefix_ std::string const & senf::console::ArgumentToken::value()
     return token_;
 }
 
-prefix_ senf::console::ArgumentToken::ArgumentToken(std::string token)
-    : token_ (token)
+prefix_ senf::console::ArgumentToken::TokenType senf::console::ArgumentToken::type()
+    const
+{
+    return type_;
+}
+
+prefix_ bool senf::console::ArgumentToken::is(unsigned tokens)
+    const
+{
+    return tokens & type_;
+}
+
+prefix_ senf::console::ArgumentToken::ArgumentToken(TokenType type, std::string token)
+    : type_(type), token_ (token)
 {}
 
 ///////////////////////////////////////////////////////////////////////////
@@ -66,7 +78,8 @@ prefix_ senf::console::ParseCommandInfo::ArgumentsRange
 senf::console::ParseCommandInfo::arguments()
     const
 {
-    return boost::make_iterator_range(arguments_.begin(), arguments_.end());
+    return boost::make_iterator_range( ArgumentIterator(tokens_.begin()),
+                                       ArgumentIterator(tokens_.end()) );
 }
 
 prefix_ senf::console::ParseCommandInfo::TokensRange senf::console::ParseCommandInfo::tokens()
@@ -83,8 +96,6 @@ prefix_ void senf::console::ParseCommandInfo::init()
     builtin_ = NoBuiltin;
     commandPath_.clear();
     tokens_.clear();
-    arguments_.clear();
-    tempArguments_.clear();
 }
 
 prefix_ void senf::console::ParseCommandInfo::setBuiltin(BuiltinCommand builtin)
@@ -99,19 +110,43 @@ senf::console::ParseCommandInfo::setCommand(std::vector<std::string> & commandPa
     commandPath_.swap(commandPath);
 }
 
-prefix_ void senf::console::ParseCommandInfo::startArgument()
+prefix_ void senf::console::ParseCommandInfo::addToken(ArgumentToken const & token)
 {
-    tempArguments_.push_back( TempArgumentRange( tokens_.size(), tokens_.size() ) );
+    tokens_.push_back(token);
 }
 
-prefix_ void senf::console::ParseCommandInfo::endArgument()
+///////////////////////////////////////////////////////////////////////////
+// senf::console::ParseCommandInfo::ArgumentIterator
+
+prefix_ senf::console::ParseCommandInfo::ArgumentIterator::ArgumentIterator()
+{}
+
+prefix_ senf::console::ParseCommandInfo::ArgumentIterator::
+ArgumentIterator(ParseCommandInfo::TokensRange::iterator i)
+    : b_(i), e_(i)
+{}
+
+prefix_ senf::console::ParseCommandInfo::ArgumentIterator::reference
+senf::console::ParseCommandInfo::ArgumentIterator::dereference()
+    const
 {
-    tempArguments_.back().second = tokens_.size();
+    if (b_ == e_) setRange();
+    return b_->is(ArgumentToken::ArgumentGroupOpen) 
+        ? boost::make_iterator_range(boost::next(b_), boost::prior(e_))
+        : boost::make_iterator_range(b_, e_);
 }
 
-prefix_ void senf::console::ParseCommandInfo::addToken(ArgumentToken const & token)
+prefix_ bool
+senf::console::ParseCommandInfo::ArgumentIterator::equal(ArgumentIterator const & other)
+    const
 {
-    tokens_.push_back(token);
+    return b_ == other.b_;
+}
+
+prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::increment()
+{
+    if (b_ == e_) setRange();
+    b_ = e_;
 }
 
 ///////////////////////////////////////////////////////////////////////////
index a37ed01..8c2ab32 100644 (file)
 #include <boost/utility.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <boost/range/iterator_range.hpp>
+#include <boost/iterator/iterator_facade.hpp>
 #include <boost/function.hpp>
 
 //#include "Parse.mpp"
@@ -214,14 +215,54 @@ namespace console {
     class ArgumentToken
     {
     public:
+        enum TokenType { 
+            PathSeparator       = 0x0001,
+            ArgumentGroupOpen   = 0x0002,
+            ArgumentGroupClose  = 0x0004,
+            DirectoryGroupOpen  = 0x0008,
+            DirectoryGroupClose = 0x0010,
+            CommandTerminator   = 0x0020,
+            OtherPunctuation    = 0x0040,
+            BasicString         = 0x0080,
+            HexString           = 0x0100,
+            Word                = 0x0200
+        };
+
+        enum TokenGroup {
+            ArgumentGrouper     = ArgumentGroupOpen 
+                                | ArgumentGroupClose,
+
+            DirectoryGrouper    = DirectoryGroupOpen 
+                                | DirectoryGroupClose,
+
+            Punctuation         = DirectoryGroupOpen 
+                                | DirectoryGroupClose 
+                                | PathSeparator 
+                                | CommandTerminator 
+                                | OtherPunctuation,
+
+            String              = BasicString 
+                                | HexString,
+
+            SimpleArgument      = Word 
+                                | BasicString 
+                                | HexString
+        };
+        
         std::string const & value() const; ///< String value of token
                                         /**< This value is properly unquoted */
 
+        TokenType type() const;         ///< Token type
+
+        bool is(unsigned tokens) const; ///< Check, whether tokens type matches \a tokens
+                                        /**< \a tokens is a bit-mask of token types to check. */
+
     protected:
 
     private:
-        explicit ArgumentToken(std::string token);
+        ArgumentToken(TokenType type, std::string token);
 
+        TokenType type_;
         std::string token_;
 
         friend class detail::ParserAccess;
@@ -239,32 +280,18 @@ namespace console {
         \li the arguments. Every argument consists of a range of ArgumentToken instances.
 
         \ingroup console_parser
-
-        \todo Completely change the 'arguments()' member implementation: let the parser just
-            generate a flat list of tokens and implement an 'argument iterator' with the following
-            features: 1. return argument ranges, automatically detecting paranthesis 2. trying to
-            increment the iterator beyond it's range just throws an argument syntax error. For this
-            to work, the parser needs to not drop the outermost '()' pair 3. detect bad paranthesis
-            (should not be necessary since the parser already does this). This allows to use this
-            same iterator to parse nested complex arguments.
       */
     class ParseCommandInfo
     {
         typedef std::vector<ArgumentToken> Tokens;
         typedef std::vector<std::string> CommandPath;
-        
+        class ArgumentIterator; 
+
     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;
-
-    public:
-        typedef Arguments::const_iterator argument_iterator;
-        typedef Arguments::size_type size_type;
+        typedef ArgumentIterator argument_iterator;
+        typedef Tokens::size_type size_type;
 
         typedef boost::iterator_range<path_iterator> CommandPathRange;
         typedef boost::iterator_range<argument_iterator> ArgumentsRange;
@@ -300,26 +327,42 @@ namespace console {
         void init();
         void setBuiltin(BuiltinCommand builtin);
         void setCommand(std::vector<std::string> & commandPath);
-        void startArgument();
-        void endArgument();
         void addToken(ArgumentToken const & token);
-        void finalize();
 
         struct MakeRange;
 
         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_;
 
         friend class detail::ParserAccess;
     };
 
+    class ParseCommandInfo::ArgumentIterator
+        : public boost::iterator_facade< ParseCommandInfo::ArgumentIterator, 
+                                         ParseCommandInfo::TokensRange,
+                                         boost::bidirectional_traversal_tag,
+                                         ParseCommandInfo::TokensRange >
+    {
+        ArgumentIterator();
+
+    private:
+        ArgumentIterator(ParseCommandInfo::TokensRange::iterator i);
+
+        reference dereference() const;
+        bool equal(ArgumentIterator const & other) const;
+        void increment();
+        void decrement();
+
+        mutable ParseCommandInfo::TokensRange::iterator b_;
+        mutable ParseCommandInfo::TokensRange::iterator e_;
+
+        void setRange() const;
+
+        friend class boost::iterator_core_access;
+        friend class ParseCommandInfo;
+    };
+
     /**< \brief Output ParseCommandInfo instance
          \related ParseCommandInfo
       */
index 9a62aa7..5129197 100644 (file)
@@ -82,10 +82,21 @@ namespace detail {
         ///////////////////////////////////////////////////////////////////////////
         // The parse context (variables needed while parsing)
 
+        typedef ArgumentToken::TokenType TokenType;
+
         struct Context {
             std::string str;
             std::vector<std::string> path;
             char ch;
+            TokenType type;
+            
+            // OUCH ... This is sooooo stupid .. push_back_a and assign_a take their 
+            // arguments by const-reference and STORE the REFERENCE ... they do NOT accept
+            // literal values !!!!!! 
+            static const TokenType BasicString;
+            static const TokenType HexString;
+            static const TokenType Word;
+            static const std::string EmptyString;
         };
 
         Context & context;
@@ -118,6 +129,10 @@ namespace detail {
         Dispatch_actor dispatch(Callback cb, Arg const & arg) const
             { return Dispatch_actor(boost::bind(cb, boost::ref(dispatcher), arg)); }
 
+        template <class Callback, class Arg1, class Arg2>
+        Dispatch_actor dispatch(Callback cb, Arg1 const & arg1, Arg2 const & arg2) const
+            { return Dispatch_actor(boost::bind(cb, boost::ref(dispatcher), arg1, arg2)); }
+
         ///////////////////////////////////////////////////////////////////////////
 
         CommandGrammar(ParseDispatcher & d, Context & c) 
@@ -242,6 +257,7 @@ namespace detail {
 
                 argument
                     =    simple_argument          [ self.dispatch(&PD::pushArgument, 
+                                                                  boost::ref(self.context.type),
                                                                   boost::ref(self.context.str)) ]
                     |    complex_argument
                     ;
@@ -260,6 +276,8 @@ namespace detail {
 
                 string                  // Returns value in context.str
                     =    eps_p                    [ clear_a(self.context.str) ]
+                      >> eps_p                    [ assign_a(self.context.type, 
+                                                             self.context.BasicString) ]
                       >> lexeme_d
                          [
                              ch_p('"')
@@ -274,6 +292,8 @@ namespace detail {
 
                 hexstring               // Returns value in context.str
                     =    eps_p                    [ clear_a(self.context.str) ]
+                      >> eps_p                    [ assign_a(self.context.type, 
+                                                             self.context.HexString) ]
                       >> confix_p( "x\"", * hexbyte, '"' )
                     ;
 
@@ -283,13 +303,15 @@ namespace detail {
                     ;
 
                 relpath
-                    =    (   word                 [ push_back_a(self.context.path) ] 
+                    =    (   word                 [ push_back_a(self.context.path) ]
                            % ch_p('/') )
-                      >> ( ! ch_p('/')            [ push_back_a(self.context.path,"") ] )
+                      >> ( ! ch_p('/')            [ push_back_a(self.context.path,
+                                                                self.context.EmptyString) ] )
                     ;
 
                 abspath
-                    =    ch_p('/')                [ push_back_a(self.context.path, "") ]
+                    =    ch_p('/')                [ push_back_a(self.context.path,
+                                                                self.context.EmptyString) ]
                       >> ( relpath
                          | eps_p                  [ push_back_a(self.context.path, "") ] )
                     ;
@@ -301,7 +323,8 @@ namespace detail {
                     ;
 
                 token
-                    =    simple_argument          [ self.dispatch(&PD::pushWord, 
+                    =    simple_argument          [ self.dispatch(&PD::pushWord,
+                                                                 boost::ref(self.context.type), 
                                                                   boost::ref(self.context.str)) ]
                     |    punctuation              [ self.dispatch(&PD::pushPunctuation,
                                                                   boost::ref(self.context.str)) ]
@@ -313,7 +336,12 @@ namespace detail {
                     ;
 
                 word                    // Returns value in context.str
-                    =    lexeme_d[ + word_p ]     [ assign_a(self.context.str) ]
+                    =    lexeme_d
+                         [
+                             eps_p                [ assign_a(self.context.type,
+                                                            self.context.Word) ]
+                          >> (+ word_p)           [ assign_a(self.context.str) ]
+                         ]
                     ;
 
                 hexbyte
@@ -354,7 +382,20 @@ namespace detail {
         };
     };
 
+    template <class ParseDispatcher>
+    ArgumentToken::TokenType const CommandGrammar<ParseDispatcher>::Context::BasicString (
+        ArgumentToken::BasicString);
+
+    template <class ParseDispatcher>
+    ArgumentToken::TokenType const CommandGrammar<ParseDispatcher>::Context::HexString(
+        ArgumentToken::HexString);
 
+    template <class ParseDispatcher>
+    ArgumentToken::TokenType const CommandGrammar<ParseDispatcher>::Context::Word(
+        ArgumentToken::Word);
+
+    template <class ParseDispatcher>
+    std::string const CommandGrammar<ParseDispatcher>::Context::EmptyString;
 
 #endif
 
index 9d465b7..8171ce9 100644 (file)
@@ -59,7 +59,8 @@ namespace
         void endCommand() 
             { os_ << "endCommand()\n"; }
         
-        void pushArgument(std::string const & argument)
+        void pushArgument(senf::console::ArgumentToken::TokenType type, 
+                          std::string const & argument)
             { os_ << "pushArgument( " << argument << " )\n"; }
         void openGroup()
             { os_ << "openGroup()\n"; }
@@ -67,7 +68,8 @@ namespace
             { os_ << "closeGroup()\n"; }
         void pushPunctuation(std::string const & token)
             { os_ << "pushPunctuation( " << token << " )\n"; }
-        void pushWord(std::string const & token)
+        void pushWord(senf::console::ArgumentToken::TokenType type, 
+                      std::string const & token)
             { os_ << "pushWord( " << token << " )\n"; }
 
         void builtin_cd(std::vector<std::string> const & path)
@@ -166,34 +168,48 @@ BOOST_AUTO_UNIT_TEST(commandParser)
 
     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 );
+    BOOST_CHECK_EQUAL( info.tokens().size(), 15u );
 
     char const * tokens[] = { "arg", 
                               "flab::blub", 
                               "123.434>a", 
-                              "a", ",", "b", ",", "c", "(", "huhu", ")",
+                              "(", "a", ",", "b", ",", "c", "(", "huhu", ")", ")",
                               "foo\"bar",
                               "\x01\x02\x03\x04" };
 
-    BOOST_REQUIRE_EQUAL( info.arguments().begin()[0].size(), 1u );
-    BOOST_CHECK_EQUAL( info.arguments().begin()[0].begin()->value(), tokens[0] );
-
-    BOOST_REQUIRE_EQUAL( info.arguments().begin()[1].size(), 1u );
-    BOOST_CHECK_EQUAL( info.arguments().begin()[1].begin()->value(), tokens[1] );
-
-    BOOST_REQUIRE_EQUAL( info.arguments().begin()[2].size(), 1u );
-    BOOST_CHECK_EQUAL( info.arguments().begin()[2].begin()->value(), tokens[2] );
-
-    BOOST_REQUIRE_EQUAL( info.arguments().begin()[3].size(), 8u );
+    senf::console::ParseCommandInfo::argument_iterator args (info.arguments().begin());
+    BOOST_REQUIRE( args != info.arguments().end() );
+    BOOST_REQUIRE_EQUAL( args->size(), 1u );
+    BOOST_CHECK_EQUAL( args->begin()->value(), tokens[0] );
+
+    ++ args;
+    BOOST_REQUIRE( args != info.arguments().end() );
+    BOOST_REQUIRE_EQUAL( args->size(), 1u );
+    BOOST_CHECK_EQUAL( args->begin()->value(), tokens[1] );
+                         
+    ++ args;
+    BOOST_REQUIRE( args != info.arguments().end() );
+    BOOST_REQUIRE_EQUAL( args->size(), 1u );
+    BOOST_CHECK_EQUAL( args->begin()->value(), tokens[2] );
+
+    ++ args;
+    BOOST_REQUIRE( args != info.arguments().end() );
+    BOOST_REQUIRE_EQUAL( args->size(), 8u );
     for (unsigned i (0); i<8; ++i)
-        BOOST_CHECK_EQUAL( info.arguments().begin()[3].begin()[i].value(), tokens[3+i] );
+        BOOST_CHECK_EQUAL( args->begin()[i].value(), tokens[4+i] );
+
+    ++ args;
+    BOOST_REQUIRE( args != info.arguments().end() );
+    BOOST_REQUIRE_EQUAL( args->size(), 1u );
+    BOOST_CHECK_EQUAL( args->begin()->value(), tokens[13] );
 
-    BOOST_REQUIRE_EQUAL( info.arguments().begin()[4].size(), 1u );
-    BOOST_CHECK_EQUAL( info.arguments().begin()[4].begin()->value(), tokens[11] );
+    ++ args;
+    BOOST_REQUIRE( args != info.arguments().end() );
+    BOOST_REQUIRE_EQUAL( args->size(), 1u );
+    BOOST_CHECK_EQUAL( args->begin()->value(), tokens[14] );
 
-    BOOST_REQUIRE_EQUAL( info.arguments().begin()[5].size(), 1u );
-    BOOST_CHECK_EQUAL( info.arguments().begin()[5].begin()->value(), tokens[12] );
+    ++ args;
+    BOOST_CHECK( args == info.arguments().end() );
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index 2d645d6..c5ffd18 100644 (file)
@@ -252,9 +252,12 @@ prefix_ void senf::console::ParsedCommandOverload<FunctionTraits, ReturnValue, B
 v_execute(std::ostream & os, ParseCommandInfo const & command)
     const
 {
-    if ( command.arguments().size() > BOOST_PP_ITERATION() )
+    // We NEED to know the number of arguments beforehand so we can assign default values
+    // correctly ... hrmpf ...
+    unsigned nArgs ( command.arguments().size() );
+    if ( nArgs > BOOST_PP_ITERATION() )
         throw SyntaxErrorException("invalid number of arguments");
-    int nDefaults ( BOOST_PP_ITERATION() - command.arguments().size() );
+    int nDefaults ( BOOST_PP_ITERATION() - nArgs );
 
     typedef typename boost::range_const_reverse_iterator<ParseCommandInfo::ArgumentsRange>::type
         riterator;
@@ -288,9 +291,12 @@ prefix_ void senf::console::ParsedCommandOverload<FunctionTraits, void, BOOST_PP
 v_execute(std::ostream & os, ParseCommandInfo const & command)
     const
 {
-    if ( command.arguments().size() > BOOST_PP_ITERATION() )
+    // We NEED to know the number of arguments beforehand so we can assign default values
+    // correctly ... hrmpf ...
+    unsigned nArgs ( command.arguments().size() );
+    if ( nArgs > BOOST_PP_ITERATION() )
         throw SyntaxErrorException("invalid number of arguments");
-    int nDefaults ( BOOST_PP_ITERATION() - command.arguments().size() );
+    int nDefaults ( BOOST_PP_ITERATION() - nArgs );
 
     typedef typename boost::range_const_reverse_iterator<ParseCommandInfo::ArgumentsRange>::type
         riterator;
index 3ed6ba9..1d0ed58 100644 (file)
@@ -32,14 +32,11 @@ namespace kw = senf::console::kw;
 
 void echo(std::ostream & output, senf::console::ParseCommandInfo const & command)
 {
-    typedef senf::console::ParseCommandInfo::ArgumentsRange::iterator iterator;
-    iterator i (command.arguments().begin());
-    iterator i_end (command.arguments().end());
+    typedef senf::console::ParseCommandInfo::TokensRange::iterator iterator;
+    iterator i (command.tokens().begin());
+    iterator i_end (command.tokens().end());
     for (; i != i_end; ++i) {
-        iterator::value_type::iterator j (i->begin());
-        iterator::value_type::iterator j_end (i->end());
-        for (; j != j_end; ++j) 
-            output << j->value() << ' ';
+        output << i->value() << ' ';
     }
     output << "\n";
 }
index 758b980..1c78fa4 100644 (file)
@@ -45,6 +45,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include "../Utils/Exception.hh"
+#include "../Utils/Backtrace.hh"
 
 static const int EPollInitialSize = 16;
 
@@ -56,24 +57,24 @@ prefix_ senf::Scheduler::Scheduler()
       eventTime_(0), eventEarly_(ClockService::milliseconds(11)), eventAdjust_(0)
 {
     if (epollFd_<0)
-        SENF_THROW_SYSTEM_EXCEPTION("");
+        SENF_THROW_SYSTEM_EXCEPTION("::epoll_create()");
 
     if (::pipe(sigpipe_) < 0)
-        SENF_THROW_SYSTEM_EXCEPTION("");
+        SENF_THROW_SYSTEM_EXCEPTION("::pipe()");
 
     int flags (::fcntl(sigpipe_[1],F_GETFL));
     if (flags < 0) 
-        SENF_THROW_SYSTEM_EXCEPTION("");
+        SENF_THROW_SYSTEM_EXCEPTION("::fcntl(F_GETFL)");
     flags |= O_NONBLOCK;
     if (::fcntl(sigpipe_[1], F_SETFL, flags) < 0) 
-        SENF_THROW_SYSTEM_EXCEPTION("");
+        SENF_THROW_SYSTEM_EXCEPTION("::fcntl(F_SETFL)");
 
     ::epoll_event ev;
     ::memset(&ev, 0, sizeof(ev));
     ev.events = EV_READ;
     ev.data.fd = sigpipe_[0];
     if (::epoll_ctl(epollFd_, EPOLL_CTL_ADD, sigpipe_[0], &ev) < 0)
-        SENF_THROW_SYSTEM_EXCEPTION("");
+        SENF_THROW_SYSTEM_EXCEPTION("::epoll_ctl(EPOLL_CTL_ADD)");
 }
 
 prefix_ void senf::Scheduler::registerSignal(unsigned signal, SimpleCallback const & cb)
@@ -111,7 +112,7 @@ prefix_ void senf::Scheduler::do_add(int fd, FdCallback const & cb, int eventMas
         action = EPOLL_CTL_ADD;
         i = fdTable_.insert(std::make_pair(fd, EventSpec())).first;
     }
-    if (i->second.epollMask() == 0) {
+    else if (i->second.epollMask() == 0) {
         action = EPOLL_CTL_ADD;
         fdErase_.erase( std::remove(fdErase_.begin(), fdErase_.end(), unsigned(fd)),
                         fdErase_.end() );
@@ -126,14 +127,23 @@ prefix_ void senf::Scheduler::do_add(int fd, FdCallback const & cb, int eventMas
     ev.events = i->second.epollMask();
     ev.data.fd = fd;
 
-    if (! i->second.file && epoll_ctl(epollFd_, action, fd, &ev) < 0) {
-        if (errno == EPERM) {
-            // Argh ... epoll does not support ordinary files :-( :-(
-            i->second.file = true;
-            ++ files_;
+    for (;;) {
+        if ( (!i->second.file) && (epoll_ctl(epollFd_, action, fd, &ev) < 0) ) {
+            switch (errno) {
+            case EPERM :
+                // Argh ... epoll does not support ordinary files :-( :-(
+                i->second.file = true;
+                ++ files_;
+                return;
+            case ENOENT :
+                action = EPOLL_CTL_ADD;
+                break;
+            default:
+                SENF_THROW_SYSTEM_EXCEPTION("::epoll_ctl()");
+            }
         }
         else
-            SENF_THROW_SYSTEM_EXCEPTION("::epoll_ctl()");
+            return;
     }
 }
 
@@ -162,7 +172,7 @@ prefix_ void senf::Scheduler::do_remove(int fd, int eventMask)
         fdErase_.push_back(fd);
     }
 
-    if (! file && epoll_ctl(epollFd_, action, fd, &ev) < 0)
+    if (! file && epoll_ctl(epollFd_, action, fd, &ev) < 0 && errno != ENOENT)
         SENF_THROW_SYSTEM_EXCEPTION("::epoll_ctl()");
     if (file)
         -- files_;
@@ -179,7 +189,7 @@ prefix_ void senf::Scheduler::registerSigHandlers()
             if (signal == SIGCHLD)
                 sa.sa_flags |= SA_NOCLDSTOP;
             if (::sigaction(signal, &sa, 0) < 0)
-                SENF_THROW_SYSTEM_EXCEPTION("");
+                SENF_THROW_SYSTEM_EXCEPTION("::sigaction()");
         }
     }
 }
@@ -246,13 +256,15 @@ prefix_ void senf::Scheduler::process()
         ///\todo Handle more than one epoll_event per call
         struct epoll_event ev;
         
-        ::sigprocmask(SIG_UNBLOCK, &sigset_, 0);
-        int events (epoll_wait(epollFd_, &ev, 1, timeout));
-        ::sigprocmask(SIG_BLOCK, &sigset_, 0);
+        if (::sigprocmask(SIG_UNBLOCK, &sigset_, 0) < 0)
+            SENF_THROW_SYSTEM_EXCEPTION("::sigprocmask(SIG_UNBLOCK)");
+        int events (::epoll_wait(epollFd_, &ev, 1, timeout));
+        if (::sigprocmask(SIG_BLOCK, &sigset_, 0) < 0)
+            SENF_THROW_SYSTEM_EXCEPTION("::sigprocmask(SIG_BLOCK)");
 
         if (events<0)
             if (errno != EINTR)
-                SENF_THROW_SYSTEM_EXCEPTION("");
+                SENF_THROW_SYSTEM_EXCEPTION("::epoll_wait()");
 
         eventTime_ = ClockService::now();
 
index 09239c8..9ae708d 100644 (file)
@@ -30,6 +30,7 @@
 #include <execinfo.h>
 #include <cxxabi.h>
 #include <boost/regex.hpp>
+#include "Buffer.hh"
 
 //#include "Backtrace.mpp"
 #define prefix_
@@ -72,6 +73,12 @@ prefix_ void senf::formatBacktrace(std::ostream & os, void ** backtrace, unsigne
     free(symbols);
 }
 
+prefix_ void senf::backtrace(std::ostream & os, unsigned numEntries)
+{
+    SENF_SCOPED_BUFFER( void*, entries, numEntries);
+    unsigned n ( ::backtrace(entries, numEntries) );
+    senf::formatBacktrace(os, entries, n);
+}
 
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
index b2d39d7..4861a3b 100644 (file)
@@ -35,6 +35,7 @@
 namespace senf {
 
     void formatBacktrace(std::ostream & os, void ** backtrace, unsigned numEntries);
+    void backtrace(std::ostream & os, unsigned numEntries);
 
 }
 
index f561e97..57a5115 100644 (file)
@@ -84,7 +84,14 @@ namespace {
         pid  = ::fork();
         if (pid < 0) throw senf::SystemException("::fork()");
         if (pid == 0) {
-            ::_exit(myMain(argc, argv));
+            try {
+                ::_exit(myMain(argc, argv));
+            } catch (std::exception & ex) {
+                std::cerr << "Unexpected exception: " << ex.what() << std::endl;
+            } catch (...) {
+                std::cerr << "Unexpected exception" << std::endl;
+            }
+            ::_exit(2);
         }
         int status;
         if (::waitpid(pid, &status, 0) < 0) throw senf::SystemException("::waitpid()");