From: g0dil Date: Fri, 9 May 2008 09:17:22 +0000 (+0000) Subject: Console: Refactor argument parsing into iterator X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=e879290346fe5242d7df2d70ee552d264081492f;p=senf.git Console: Refactor argument parsing into iterator 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 --- diff --git a/Console/Executor.cc b/Console/Executor.cc index 4d9b2f9..fdbb850 100644 --- a/Console/Executor.cc +++ b/Console/Executor.cc @@ -60,7 +60,7 @@ prefix_ void senf::console::Executor::execute(std::ostream & output, GenericNode & node ( traverseCommand(command.commandPath()) ); DirectoryNode * dir ( dynamic_cast(&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( traverseNode(path) ); diff --git a/Console/Executor.hh b/Console/Executor.hh index 92a2dfe..86e54be 100644 --- a/Console/Executor.hh +++ b/Console/Executor.hh @@ -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 {}; diff --git a/Console/Mainpage.dox b/Console/Mainpage.dox index e6cf404..d094f24 100644 --- a/Console/Mainpage.dox +++ b/Console/Mainpage.dox @@ -288,15 +288,21 @@ \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 diff --git a/Console/Parse.cc b/Console/Parse.cc index c06a2bc..52858e9 100644 --- a/Console/Parse.cc +++ b/Console/Parse.cc @@ -54,20 +54,11 @@ namespace detail { static void setCommand(ParseCommandInfo & info, std::vector & 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 & path) { ParserAccess::init(info_); ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinCD); setBuiltinPathArg(path); - ParserAccess::finalize(info_); cb_(info_); } + cb_(info_); } void builtin_ls(std::vector & path) { ParserAccess::init(info_); ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinLS); setBuiltinPathArg(path); - ParserAccess::finalize(info_); cb_(info_); } + cb_(info_); } void pushDirectory(std::vector & 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 & path) { ParserAccess::init(info_); ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinHELP); setBuiltinPathArg(path); - ParserAccess::finalize(info_); cb_(info_); } + cb_(info_); } void setBuiltinPathArg(std::vector & path) { - ParserAccess::startArgument(info_); + pushPunctuation("("); for (std::vector::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 diff --git a/Console/Parse.cci b/Console/Parse.cci index c85fad8..c9ff9ad 100644 --- a/Console/Parse.cci +++ b/Console/Parse.cci @@ -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 & 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_; } /////////////////////////////////////////////////////////////////////////// diff --git a/Console/Parse.hh b/Console/Parse.hh index a37ed01..8c2ab32 100644 --- a/Console/Parse.hh +++ b/Console/Parse.hh @@ -194,6 +194,7 @@ #include #include #include +#include #include //#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 Tokens; typedef std::vector CommandPath; - + class ArgumentIterator; + public: typedef CommandPath::const_iterator path_iterator; typedef Tokens::const_iterator token_iterator; - typedef boost::iterator_range argument_value_type; - - - private: - typedef std::vector 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 CommandPathRange; typedef boost::iterator_range ArgumentsRange; @@ -300,26 +327,42 @@ namespace console { void init(); void setBuiltin(BuiltinCommand builtin); void setCommand(std::vector & commandPath); - void startArgument(); - void endArgument(); void addToken(ArgumentToken const & token); - void finalize(); struct MakeRange; std::vector commandPath_; - - typedef std::pair TempArgumentRange; - typedef std::vector 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 */ diff --git a/Console/Parse.ih b/Console/Parse.ih index 9a62aa7..5129197 100644 --- a/Console/Parse.ih +++ b/Console/Parse.ih @@ -82,10 +82,21 @@ namespace detail { /////////////////////////////////////////////////////////////////////////// // The parse context (variables needed while parsing) + typedef ArgumentToken::TokenType TokenType; + struct Context { std::string str; std::vector 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 + 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 + ArgumentToken::TokenType const CommandGrammar::Context::BasicString ( + ArgumentToken::BasicString); + + template + ArgumentToken::TokenType const CommandGrammar::Context::HexString( + ArgumentToken::HexString); + template + ArgumentToken::TokenType const CommandGrammar::Context::Word( + ArgumentToken::Word); + + template + std::string const CommandGrammar::Context::EmptyString; #endif diff --git a/Console/Parse.test.cc b/Console/Parse.test.cc index 9d465b7..8171ce9 100644 --- a/Console/Parse.test.cc +++ b/Console/Parse.test.cc @@ -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 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//////////////////////////////////////// diff --git a/Console/ParsedCommand.mpp b/Console/ParsedCommand.mpp index 2d645d6..c5ffd18 100644 --- a/Console/ParsedCommand.mpp +++ b/Console/ParsedCommand.mpp @@ -252,9 +252,12 @@ prefix_ void senf::console::ParsedCommandOverload 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::type riterator; @@ -288,9 +291,12 @@ prefix_ void senf::console::ParsedCommandOverload 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::type riterator; diff --git a/Console/testServer.cc b/Console/testServer.cc index 3ed6ba9..1d0ed58 100644 --- a/Console/testServer.cc +++ b/Console/testServer.cc @@ -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"; } diff --git a/Scheduler/Scheduler.cc b/Scheduler/Scheduler.cc index 758b980..1c78fa4 100644 --- a/Scheduler/Scheduler.cc +++ b/Scheduler/Scheduler.cc @@ -45,6 +45,7 @@ #include #include #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(); diff --git a/Utils/Backtrace.cc b/Utils/Backtrace.cc index 09239c8..9ae708d 100644 --- a/Utils/Backtrace.cc +++ b/Utils/Backtrace.cc @@ -30,6 +30,7 @@ #include #include #include +#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_ diff --git a/Utils/Backtrace.hh b/Utils/Backtrace.hh index b2d39d7..4861a3b 100644 --- a/Utils/Backtrace.hh +++ b/Utils/Backtrace.hh @@ -35,6 +35,7 @@ namespace senf { void formatBacktrace(std::ostream & os, void ** backtrace, unsigned numEntries); + void backtrace(std::ostream & os, unsigned numEntries); } diff --git a/Utils/Daemon/Daemon.test.cc b/Utils/Daemon/Daemon.test.cc index f561e97..57a5115 100644 --- a/Utils/Daemon/Daemon.test.cc +++ b/Utils/Daemon/Daemon.test.cc @@ -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()");