From: g0dil Date: Fri, 11 Apr 2008 13:47:10 +0000 (+0000) Subject: Console: More documentation and cleanup X-Git-Url: http://g0dil.de/git?p=senf.git;a=commitdiff_plain;h=63c40810b93b4d8f3d6dad5f987adc5f2bf5b5ed Console: More documentation and cleanup git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@806 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Console/Mainpage.dox b/Console/Mainpage.dox index b63300e..3e8e458 100644 --- a/Console/Mainpage.dox +++ b/Console/Mainpage.dox @@ -348,16 +348,18 @@ \li \e default_value: Arguments default value + + See senf::console::ParsedArgumentAttributor 'List of all members' \section console_memberfn Registering member functions Member functions are supported like non-member functions. They must however be added through a - senf::console::ScopedDirectory<> instance to bind them to their instance. + senf::console::ScopedDirectory instance to bind them to their instance. \code class Test { public: - ScopedDirectory dir; + senf::console::ScopedDirectory dir; Test(std::string label) : dir(this), label_ (label) { dir.add("test4", &Test::test2); @@ -379,7 +381,7 @@ \endcode Binding via senf::console::ScopedDirectory ensures, that the commands are automatically removed - from the tree when an object is destroyed. + from the tree when the object is destroyed. */ diff --git a/Console/Node.hh b/Console/Node.hh index 853cc1b..71c66f7 100644 --- a/Console/Node.hh +++ b/Console/Node.hh @@ -507,6 +507,11 @@ namespace console { {}; #endif + /** \brief Syntax error parsing command arguments exception + + All errors while parsing the arguments of a command must be signaled by throwing an instance + of SyntaxErrorException. This is important, so command overloading works. + */ struct SyntaxErrorException : public senf::Exception { explicit SyntaxErrorException(std::string const & msg = ""); diff --git a/Console/OverloadedCommand.hh b/Console/OverloadedCommand.hh index 1363d52..db94afe 100644 --- a/Console/OverloadedCommand.hh +++ b/Console/OverloadedCommand.hh @@ -39,11 +39,15 @@ namespace console { class OverloadedCommandNode; + /** \brief Documentation for a single argument + + This struct is used by CommandOverload::argumentDoc() + */ struct ArgumentDoc { - std::string name; - std::string type; - std::string defaultValue; - std::string doc; + std::string name; ///< Argument name + std::string type; ///< Argument type (string representation) + std::string defaultValue; ///< Default value (string representation) or empty string + std::string doc; ///< Documentation for this argument }; /** \brief Base class for command overload of OverloadedCommandNode @@ -77,14 +81,22 @@ namespace console { overload, a SyntaxErrorException must be thrown. Same as execute() */ - unsigned numArguments() const; + unsigned numArguments() const; ///< Number of arguments this overload takes void argumentDoc(unsigned index, ArgumentDoc & doc) const; - std::string doc() const; + ///< Get information on argument \a index + /**< The information is returned in \e doc. \e doc must be + empty before this call. + \pre \a index < numArguments() + \param[in] index Argument index + \param[outp doc Argument documentation */ + + std::string doc() const; ///< Get overload documentation OverloadedCommandNode & node() const; ///< Access owning node /**< \pre The command \e must have been added to an OverloadedCommandNode. */ - unsigned overloadIndex() const; + + unsigned overloadIndex() const; ///< Get index of overload in it's OverloadedCommandNode protected: CommandOverload(); @@ -93,9 +105,25 @@ namespace console { private: #endif virtual unsigned v_numArguments() const = 0; + ///< Return the number of arguments + /**< This member must be implemented in the derived class to + return the number of arguments, the command expects. */ + virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const = 0; + ///< Return argument documentation + /**< The member must be implemented int the derived class to + return all documentation information for the \a + index'th parameter in \a doc. */ + virtual std::string v_doc() const = 0; + ///< Return overload documentation + /**< This member must be implemented in the derived class to + return the overloads documentation string. */ + virtual void v_execute(std::ostream & os, ParseCommandInfo const & command) const = 0; + ///< Execute the overload + /**< This member must be implemented in the derived class + o execute the overload. */ private: OverloadedCommandNode * node_; @@ -153,15 +181,16 @@ namespace console { template Command & add(boost::intrusive_ptr overload); ///< Add an additional overload - ptr thisptr(); - cptr thisptr() const; - OverloadedCommandNode & doc(std::string const & doc); ///< Assign global help for all overloads unsigned overloadIndex(CommandOverload const & overload); + ///< Return the overload index for \a overload + /**< overloadIndex returns the index of \a overload in the + internal list of overloads. */ - protected: + ptr thisptr(); + cptr thisptr() const; private: OverloadedCommandNode(); @@ -205,10 +234,8 @@ namespace console { SimpleCommandOverload & doc(std::string const & doc); ///< Assign overload specific documentation - protected: - private: - SimpleCommandOverload(Function fn); + explicit SimpleCommandOverload(Function fn); virtual unsigned v_numArguments() const; virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const; diff --git a/Console/Parse.hh b/Console/Parse.hh index 91a1467..295f4a6 100644 --- a/Console/Parse.hh +++ b/Console/Parse.hh @@ -227,11 +227,11 @@ namespace console { friend class detail::ParserAccess; }; - /** \brief Console command + /** \brief Single parsed console command Every command parsed is returned in a ParseCommandInfo instance. This information is purely taken from the parser, no semantic information is attached at this point, the config/console - is not involved in any why. ParseCommandInfo consist of + node tree is not involved in any why. ParseCommandInfo consist of \li the type of command: built-in or normal command represented by a possibly relative path into the command tree. @@ -279,9 +279,9 @@ namespace console { constitutes one path element. If the first element is empty, the path is an absolute path, otherwise it is relative. If the last element is an empty string, the - path ends in a '/' char. */ + path ends with a '/' char. */ ArgumentsRange arguments() const; ///< Command arguments - /**< The returned range contains one token range for each + /**< The returned range contains one TokensRange for each argument. */ TokensRange tokens() const; ///< All argument tokens /**< The returned range contains \e all argument tokens in a diff --git a/Console/ParseParameter.hh b/Console/ParseParameter.hh deleted file mode 100644 index 73a8fc6..0000000 --- a/Console/ParseParameter.hh +++ /dev/null @@ -1,116 +0,0 @@ -// $Id$ -// -// Copyright (C) 2008 -// Fraunhofer Institute for Open Communication Systems (FOKUS) -// Competence Center NETwork research (NET), St. Augustin, GERMANY -// Stefan Bund -// -// 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 ParseParameter public header */ - -#ifndef HH_ParseParameter_ -#define HH_ParseParameter_ 1 - -// Custom includes -#include -#include -#include "../Utils/intrusive_refcount.hh" -#include "Parse.hh" -#include "Node.hh" - -//#include "ParseParameter.mpp" -///////////////////////////////hh.p//////////////////////////////////////// - -namespace senf { -namespace console { -namespace detail { - - struct ParameterInfoBase - : public intrusive_refcount - { - typedef boost::intrusive_ptr ptr; - - std::string type; - std::string name; - bool hasDefault; - std::string doc; - - ParameterInfoBase(std::string const & type); - - virtual std::string defaultValueStr() const = 0; - }; - - template - struct ParameterInfo - : public ParameterInfoBase - { - typedef boost::intrusive_ptr ptr; - - static ptr create(); - ParameterInfo(); - - ParameterType defaultValue; - - virtual std::string defaultValueStr() const; - }; - - template - struct ReturnValueTraits - { - typedef Type type; - - template - static void callAndWrite(Fn const & fn, std::ostream & os); - }; - - template <> - struct ReturnValueTraits - { - typedef void type; - - template - static void callAndWrite(Fn const & fn, std::ostream & os); - }; - - template - struct ParameterTraits - { - typedef Type type; - static void parse(ParseCommandInfo::TokensRange const & tokens, Type & out); - static std::string typeDescription(); - static std::string dump(Type const & value); - }; - -}}} - -///////////////////////////////hh.e//////////////////////////////////////// -//#include "ParseParameter.cci" -//#include "ParseParameter.ct" -#include "ParseParameter.cti" -#endif - - -// Local Variables: -// mode: c++ -// fill-column: 100 -// comment-column: 40 -// c-file-style: "senf" -// indent-tabs-mode: nil -// ispell-local-dictionary: "american" -// compile-command: "scons -u test" -// End: diff --git a/Console/ParsedCommand.cc b/Console/ParsedCommand.cc index 3f27917..0ef2347 100644 --- a/Console/ParsedCommand.cc +++ b/Console/ParsedCommand.cc @@ -46,7 +46,7 @@ prefix_ void senf::console::ParsedCommandOverloadBase::v_argumentDoc(unsigned in const { BOOST_ASSERT( index < parameters_.size() ); - detail::ParameterInfoBase & arg (*parameters_[index]); + detail::ArgumentInfoBase & arg (*parameters_[index]); doc.name = arg.name.empty() ? (boost::format("arg%d%d") % overloadIndex() % (index+1)).str() : arg.name; diff --git a/Console/ParsedCommand.cci b/Console/ParsedCommand.cci index 0317002..768be07 100644 --- a/Console/ParsedCommand.cci +++ b/Console/ParsedCommand.cci @@ -36,7 +36,7 @@ prefix_ senf::console::ParsedCommandOverloadBase::ParsedCommandOverloadBase() {} -prefix_ senf::console::detail::ParameterInfoBase & +prefix_ senf::console::detail::ArgumentInfoBase & senf::console::ParsedCommandOverloadBase::arg(unsigned n) const { diff --git a/Console/ParsedCommand.cti b/Console/ParsedCommand.cti index 9abe00d..e37906c 100644 --- a/Console/ParsedCommand.cti +++ b/Console/ParsedCommand.cti @@ -34,20 +34,50 @@ ///////////////////////////////cti.p/////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// +// senf::console::detail::ArgumentInfoBase + +prefix_ senf::console::detail::ArgumentInfoBase::ArgumentInfoBase(std::string const & type_) + : type (type_), name (), hasDefault (false) +{} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::ArgumentInfo + +template +prefix_ typename senf::console::detail::ArgumentInfo::ptr +senf::console::detail::ArgumentInfo::create() +{ + return ptr(new ArgumentInfo()); +} + +template +prefix_ senf::console::detail::ArgumentInfo::ArgumentInfo() + : ArgumentInfoBase ( ArgumentTraits::description() ), + defaultValue () +{} + +template +prefix_ std::string senf::console::detail::ArgumentInfo::defaultValueStr() + const +{ + return hasDefault ? ArgumentTraits::str(defaultValue) : ""; +} + +/////////////////////////////////////////////////////////////////////////// // senf::console::ParsedCommandOverloadBase template -prefix_ senf::console::detail::ParameterInfo & +prefix_ senf::console::detail::ArgumentInfo & senf::console::ParsedCommandOverloadBase::arg(unsigned n) const { - return dynamic_cast &>(arg(n)); + return dynamic_cast &>(arg(n)); } template prefix_ void senf::console::ParsedCommandOverloadBase::addParameter() { - parameters_.push_back(detail::ParameterInfo::create()); + parameters_.push_back(detail::ArgumentInfo::create()); } /////////////////////////////////////////////////////////////////////////// @@ -87,11 +117,11 @@ senf::console::ParsedCommandAttributor::ParsedCommandAttributor(Overlo {} /////////////////////////////////////////////////////////////////////////// -// senf::console::ParsedAttributeAttributorBase +// senf::console::ParsedArgumentAttributorBase template prefix_ Self -senf::console::ParsedAttributeAttributorBase::doc(std::string const & doc) +senf::console::ParsedArgumentAttributorBase::doc(std::string const & doc) const { this->ParsedCommandAttributorBase::nodeDoc(doc); @@ -99,7 +129,7 @@ senf::console::ParsedAttributeAttributorBase::doc(std::string con } template -prefix_ Self senf::console::ParsedAttributeAttributorBase:: +prefix_ Self senf::console::ParsedArgumentAttributorBase:: overloadDoc(std::string const & doc) const { @@ -109,17 +139,17 @@ overloadDoc(std::string const & doc) template prefix_ -senf::console::ParsedAttributeAttributorBase:: -ParsedAttributeAttributorBase(Overload & overload, unsigned index) +senf::console::ParsedArgumentAttributorBase:: +ParsedArgumentAttributorBase(Overload & overload, unsigned index) : ParsedCommandAttributor (overload, index) {} /////////////////////////////////////////////////////////////////////////// -// senf::console::ParsedAttributeAttributor +// senf::console::ParsedArgumentAttributor template -prefix_ typename senf::console::ParsedAttributeAttributor::next_type -senf::console::ParsedAttributeAttributor::arg() +prefix_ typename senf::console::ParsedArgumentAttributor::next_type +senf::console::ParsedArgumentAttributor::arg() const { return next(); @@ -127,8 +157,8 @@ senf::console::ParsedAttributeAttributor::arg() template template -prefix_ typename senf::console::ParsedAttributeAttributor::next_type -senf::console::ParsedAttributeAttributor:: +prefix_ typename senf::console::ParsedArgumentAttributor::next_type +senf::console::ParsedArgumentAttributor:: argInfo(ArgumentPack const & args) const { @@ -146,14 +176,14 @@ argInfo(ArgumentPack const & args) template template -prefix_ void senf::console::ParsedAttributeAttributor:: +prefix_ void senf::console::ParsedArgumentAttributor:: argInfo(Kw const &, ArgumentPack const &, boost::mpl::true_) const {} template template -prefix_ void senf::console::ParsedAttributeAttributor:: +prefix_ void senf::console::ParsedArgumentAttributor:: argInfo(boost::parameter::keyword const &, ArgumentPack const & args, boost::mpl::false_) const @@ -163,7 +193,7 @@ argInfo(boost::parameter::keyword const &, ArgumentPack const & template template -prefix_ void senf::console::ParsedAttributeAttributor:: +prefix_ void senf::console::ParsedArgumentAttributor:: argInfo(boost::parameter::keyword const &, ArgumentPack const & args, boost::mpl::false_) const @@ -173,7 +203,7 @@ argInfo(boost::parameter::keyword const &, ArgumentPack c template template -prefix_ void senf::console::ParsedAttributeAttributor:: +prefix_ void senf::console::ParsedArgumentAttributor:: argInfo(boost::parameter::keyword const &, ArgumentPack const & args, boost::mpl::false_) const @@ -183,21 +213,21 @@ argInfo(boost::parameter::keyword const &, ArgumentPack template prefix_ -senf::console::ParsedAttributeAttributor:: -ParsedAttributeAttributor(Overload & overload) - : ParsedAttributeAttributorBase (overload, index) +senf::console::ParsedArgumentAttributor:: +ParsedArgumentAttributor(Overload & overload) + : ParsedArgumentAttributorBase (overload, index) {} template -prefix_ typename senf::console::ParsedAttributeAttributor::next_type -senf::console::ParsedAttributeAttributor::next() +prefix_ typename senf::console::ParsedArgumentAttributor::next_type +senf::console::ParsedArgumentAttributor::next() const { - return ParsedAttributeAttributor(this->overload()); + return ParsedArgumentAttributor(this->overload()); } template -prefix_ void senf::console::ParsedAttributeAttributor:: +prefix_ void senf::console::ParsedArgumentAttributor:: defaultValue(value_type const & value) const { @@ -205,14 +235,14 @@ defaultValue(value_type const & value) } /////////////////////////////////////////////////////////////////////////// -// senf::console::ParsedAttributeAttributor +// senf::console::ParsedArgumentAttributor template prefix_ -senf::console::ParsedAttributeAttributor:: -ParsedAttributeAttributor(Overload & overload) - : ParsedAttributeAttributorBase< Overload, - ParsedAttributeAttributor > (overload, index) +senf::console::ParsedArgumentAttributor:: +ParsedArgumentAttributor(Overload & overload) + : ParsedArgumentAttributorBase< Overload, + ParsedArgumentAttributor > (overload, index) {} /////////////////////////////////////////////////////////////////////////// @@ -256,7 +286,7 @@ namespace { } template -prefix_ senf::console::ParsedAttributeAttributor< +prefix_ senf::console::ParsedArgumentAttributor< senf::console::ParsedCommandOverload< typename senf::console::detail::ParsedCommandTraits::traits> > senf::console::senf_console_add_node(DirectoryNode & node, std::string const & name, @@ -269,7 +299,7 @@ senf::console::senf_console_add_node(DirectoryNode & node, std::string const & n typedef detail::ParsedCommandTraits CmdTraits; typedef ParsedCommandOverload Overload; - typedef ParsedAttributeAttributor Attributor; + typedef ParsedArgumentAttributor Attributor; return Attributor( cmdNode.add( CreateParsedCommandOverload< @@ -277,7 +307,7 @@ senf::console::senf_console_add_node(DirectoryNode & node, std::string const & n } template -prefix_ senf::console::ParsedAttributeAttributor< +prefix_ senf::console::ParsedArgumentAttributor< senf::console::ParsedCommandOverload< typename senf::console::detail::ParsedCommandTraits::traits> > senf::console:: @@ -292,7 +322,7 @@ senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & n typedef detail::ParsedCommandTraits CmdTraits; typedef ParsedCommandOverload Overload; - typedef ParsedAttributeAttributor Attributor; + typedef ParsedArgumentAttributor Attributor; return Attributor( cmdNode.add( CreateParsedCommandOverload< @@ -300,6 +330,23 @@ senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & n senf::membind(fn,&owner)) ) ); } +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::CheckVoidReturn + +template +template +prefix_ void senf::console::detail::CheckVoidReturn::call(Fn fn, std::ostream & os) +{ + ReturnValueTraits::format(fn(),os); + os << "\n"; +} + +template +prefix_ void senf::console::detail::CheckVoidReturn::call(Fn fn, std::ostream & os) +{ + fn(); +} + ///////////////////////////////cti.e/////////////////////////////////////// #undef prefix_ diff --git a/Console/ParsedCommand.hh b/Console/ParsedCommand.hh index 7df4366..9f43d15 100644 --- a/Console/ParsedCommand.hh +++ b/Console/ParsedCommand.hh @@ -37,7 +37,7 @@ #include #include "../config.hh" #include "OverloadedCommand.hh" -#include "ParseParameter.hh" +#include "Traits.hh" #include "../Utils/type_traits.hh" #include "ParsedCommand.ih" @@ -47,6 +47,8 @@ namespace senf { namespace console { + namespace detail { class ArgumentInfoBase; } + /** \brief CommandOverload implementation with automatic argument parsing ParsedCommandOverloadBase implements a CommandOverload implementation supporting automatic @@ -69,7 +71,7 @@ namespace console { \endcode There are quite a number of additional parameters available to be set. These parameters are - documented in ParsedAttributeAttributor. Parameters are set by adding them as additional + documented in ParsedArgumentAttributor. Parameters are set by adding them as additional calls after adding the node: \code @@ -115,13 +117,13 @@ namespace console { used as argument type. However, argument parsing can be configured by specializing - senf::console::detail::ParameterTraits. See that class for more information. + senf::console::ArgumentTraits. See that class for more information. \section overload_format Custom return-value formatters By default, return values are streamed to an ostream. This automatically allows any streamable type to be used as return value. To add new types or customize the formating, the - senf::console::detail::ReturnValueTraits template needs to be specialized for that type. See + senf::console::ReturnValueTraits template needs to be specialized for that type. See that class for more information. \ingroup console_commands @@ -132,8 +134,8 @@ namespace console { public: typedef boost::intrusive_ptr ptr; - detail::ParameterInfoBase & arg(unsigned n) const; - template detail::ParameterInfo & arg(unsigned n) const; + detail::ArgumentInfoBase & arg(unsigned n) const; + template detail::ArgumentInfo & arg(unsigned n) const; void doc(std::string const & d); @@ -148,24 +150,56 @@ namespace console { virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const; virtual std::string v_doc() const; - typedef std::vector Parameters; + typedef std::vector Parameters; Parameters parameters_; std::string doc_; }; + /** \brief Parsed command overload + + ParsedCommandOverload provides the command overload added to an OverloadedCommandNode for an + automatically parsed command. + + This class is normally instantiated automatically when adding a function or member-function + pointer as callback to the tree. Manually instantiation this type of overload is \e not + simple, since the function signature has to be manipulated correctly to support the optional + \c std::ostream first argument. + + \implementation This class is specialized for each supported number of command arguments. + */ template - class ParsedCommandOverload {}; + class ParsedCommandOverload : public ParsedCommandOverloadBase + { + public: + typedef boost::intrusive_ptr ptr; + +#ifdef DOXYGEN + static ptr create(Function fn); +#endif + }; + +#ifndef DOXYGEN # define BOOST_PP_ITERATION_PARAMS_1 (4, (0, SENF_CONSOLE_MAX_COMMAND_ARITY, \ SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), \ 1)) # include BOOST_PP_ITERATE() +#endif + + /** \brief Generic ParsedCommandOverladBase attributes + + Attributes for parsed commands are not set directly on the node. They are set via a special + attributor temporary returned when adding a parsed command to the tree. + + This class is the base class for those attributors. It provides members which do not depend + in any way on the exact type of command added. + */ class ParsedCommandAttributorBase { public: - OverloadedCommandNode & node() const; - operator OverloadedCommandNode & () const; + OverloadedCommandNode & node() const; ///< Return the node object + operator OverloadedCommandNode & () const; ///< Automatically convert to node object protected: ParsedCommandAttributorBase(ParsedCommandOverloadBase & overload, unsigned index); @@ -184,75 +218,133 @@ namespace console { unsigned index_; }; + /** \brief Non argument dependent ParsedCommandBase attributes + + Attributes for parsed commands are not set directly on the node. They are set via a special + attributor temporary returned when adding a parsed command to the tree. + + This class adds all those members, which do depend on the type of command added (and thereby + on that commands signature) but do not depend on the type of any single argument. + + \fixme Implement compile-time checking, that after a defaulted arg only defaulted args are + allowed. + */ template class ParsedCommandAttributor : public ParsedCommandAttributorBase { public: - Overload & overload() const; + Overload & overload() const; ///< Get the command overload protected: ParsedCommandAttributor(Overload & overload, unsigned index); private: }; - + + /** \brief Keyword argument tags + + The tags defined in this namespace are used as keyword arguments via the Boost.Parameter + library. + + For the keyword tags, the standard C++ scoping rules apply: + \li Either qualify them with their complete namespace: arg( senf::console::kw::name = + "name" ) + \li or use a namespace alias: namespace kw = senf::console::kw; arg( kw::name = "name" + ); + \li import the keywords into your namespace: using namespace senf::console::kw; arg( + name = "name"); + + The second alternative is preferred, the using namespace directive may be used as + long as the keyword names do not clash with another visible symbol. + */ namespace kw { - BOOST_PARAMETER_KEYWORD(type, name); - BOOST_PARAMETER_KEYWORD(type, description); - BOOST_PARAMETER_KEYWORD(type, default_value); + BOOST_PARAMETER_KEYWORD(type, name) ///< Argument name + BOOST_PARAMETER_KEYWORD(type, description) ///< One-line Argument description + BOOST_PARAMETER_KEYWORD(type, default_value) ///< Argument default value } + /** \brief Derived class dependent ParsedCommandBase attributes + + Attributes for parsed commands are not set directly on the node. They are set via a special + attributor temporary returned when adding a parsed command to the tree. + + This class adds all those members, which do not depend on any specific argument but which + need to return the correct attributor type. + */ template - class ParsedAttributeAttributorBase + class ParsedArgumentAttributorBase : public ParsedCommandAttributor { public: - Self doc(std::string const & doc) const; - Self overloadDoc(std::string const & doc) const; + Self doc(std::string const & doc) const; ///< Set documentation for all overloads + Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation protected: - ParsedAttributeAttributorBase(Overload & overload, unsigned index); + ParsedArgumentAttributorBase(Overload & overload, unsigned index); private: }; + + /** \brief Argument dependent ParsedCommandBase attributes + + Attributes for parsed commands are not set directly on the node. They are set via a special + attributor temporary returned when adding a parsed command to the tree. + + This class adds all those members, which depend on a specific argument. Each call to \c arg + will advance to the next argument. + */ template < class Overload, unsigned index=0, bool flag=(index < unsigned(Overload::traits::arity)) > - class ParsedAttributeAttributor - : public ParsedAttributeAttributorBase< Overload, - ParsedAttributeAttributor > + class ParsedArgumentAttributor + : public ParsedArgumentAttributorBase< Overload, + ParsedArgumentAttributor > { + typedef boost::parameter::parameters< + kw::type::name, + kw::type::description, + kw::type::default_value> arg_params; + public: + typedef OverloadedCommandNode node_type; + typedef ParsedArgumentAttributor return_type; + typedef typename senf::function_traits_arg_type< typename Overload::traits, int(index) >::type arg_type; typedef typename senf::remove_cvref< arg_type >::type value_type; - typedef ParsedAttributeAttributor next_type; + typedef ParsedArgumentAttributor next_type; - typedef OverloadedCommandNode node_type; - typedef ParsedAttributeAttributor return_type; + next_type arg() const; ///< Set argument attributes + /**< This member changes the attributes for the current + argument. The attributes are passed to arg() as keyword + arguments using the Boost.Parameter + library. The valid keywords are defined in the + senf::console::kw namespace. - typedef boost::parameter::parameters< - kw::type::name, - kw::type::description, - kw::type::default_value> arg_params; + This member is only present, if there is an argument at + the current index. */ - next_type arg() const; +#ifndef DOXYVEN # define BOOST_PP_ITERATION_PARAMS_1 \ (4, (1, 3, SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), 5)) # include BOOST_PP_ITERATE() +#endif + private: - explicit ParsedAttributeAttributor(Overload & overload); + explicit ParsedArgumentAttributor(Overload & overload); template next_type argInfo(ArgumentPack const & args) const; - template void argInfo(Kw const &, ArgumentPack const &, boost::mpl::true_) const; + template void argInfo(boost::parameter::keyword const &, ArgumentPack const & args, boost::mpl::false_) @@ -271,44 +363,50 @@ namespace console { void defaultValue(value_type const & value) const; template - friend class ParsedAttributeAttributor; + friend class ParsedArgumentAttributor; + +#ifndef DOXYGEN template - friend ParsedAttributeAttributor< + friend ParsedArgumentAttributor< ParsedCommandOverload::traits> > senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int); template - friend ParsedAttributeAttributor< + friend ParsedArgumentAttributor< ParsedCommandOverload::traits> > senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name, Function fn, int, typename boost::enable_if_c< detail::ParsedCommandTraits::is_member>::type * = 0); + +#endif }; +#ifndef DOXYGEN + template - class ParsedAttributeAttributor - : public ParsedAttributeAttributorBase< Overload, - ParsedAttributeAttributor > + class ParsedArgumentAttributor + : public ParsedArgumentAttributorBase< Overload, + ParsedArgumentAttributor > { public: typedef OverloadedCommandNode node_type; - typedef ParsedAttributeAttributor return_type; + typedef ParsedArgumentAttributor return_type; private: - explicit ParsedAttributeAttributor(Overload & overload); + explicit ParsedArgumentAttributor(Overload & overload); template - friend class ParsedAttributeAttributor; + friend class ParsedArgumentAttributor; template - friend ParsedAttributeAttributor< + friend ParsedArgumentAttributor< ParsedCommandOverload::traits> > senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int); template - friend ParsedAttributeAttributor< + friend ParsedArgumentAttributor< ParsedCommandOverload::traits> > senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name, Function fn, int, @@ -316,15 +414,13 @@ namespace console { detail::ParsedCommandTraits::is_member>::type * = 0); }; -#ifndef DOXYGEN - template - ParsedAttributeAttributor< + ParsedArgumentAttributor< ParsedCommandOverload::traits> > senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int); template - ParsedAttributeAttributor< + ParsedArgumentAttributor< ParsedCommandOverload::traits> > senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name, Function fn, int, @@ -338,7 +434,7 @@ namespace console { #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedCommandOverload, (class,unsigned)) -BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedAttributeAttributor, (class, unsigned, bool)) +BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedArgumentAttributor, (class, unsigned, bool)) BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function_traits, 1) ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/Console/ParsedCommand.ih b/Console/ParsedCommand.ih index 445d055..d8a72d2 100644 --- a/Console/ParsedCommand.ih +++ b/Console/ParsedCommand.ih @@ -34,10 +34,43 @@ namespace senf { namespace console { namespace detail { +#ifndef DOXYGEN + + struct ArgumentInfoBase + : public intrusive_refcount + { + typedef boost::intrusive_ptr ptr; + + std::string type; + std::string name; + bool hasDefault; + std::string doc; + + ArgumentInfoBase(std::string const & type); + + virtual std::string defaultValueStr() const = 0; + }; + + template + struct ArgumentInfo + : public ArgumentInfoBase + { + typedef boost::intrusive_ptr ptr; + + static ptr create(); + ArgumentInfo(); + + ParameterType defaultValue; + + virtual std::string defaultValueStr() const; + }; + template ::value> struct ParsedCommandTraits {}; + // FirstArgType returns void, if the function has no arguments, otherwise it returns arg1_type + template 0)> struct FirstArgType { @@ -54,10 +87,8 @@ namespace detail { struct ParsedCommandTraits { typedef Function base_type; - typedef typename senf::remove_member_pointer< - typename boost::remove_pointer::type>::type function_type; + typedef typename senf::remove_any_pointer::type function_type; typedef boost::function_traits base_traits; - typedef typename FirstArgType::type first_arg_type; static const bool has_ostream_arg = boost::is_same::value; @@ -73,6 +104,22 @@ namespace detail { typedef typename senf::member_class::type class_type; }; + template + struct CheckVoidReturn + { + template + static void call(Fn fn, std::ostream & os); + }; + + template <> + struct CheckVoidReturn + { + template + static void call(Fn fn, std::ostream & os); + }; + +#endif + }}} ///////////////////////////////ih.e//////////////////////////////////////// diff --git a/Console/ParsedCommand.mpp b/Console/ParsedCommand.mpp index df42e0a..0c0c55c 100644 --- a/Console/ParsedCommand.mpp +++ b/Console/ParsedCommand.mpp @@ -135,14 +135,11 @@ v_execute(std::ostream & os, ParseCommandInfo const & command) # define mpp_l(z,n,d) \ mpp_ArgTypeN(n) mpp_ArgN(n) (arg< mpp_ArgTypeN(n) >( n ).defaultValue); \ if (i != i_end) \ - detail::ParameterTraits< mpp_ArgTypeN(n) >::parse( *(i++), mpp_ArgN(n) ); + ArgumentTraits< mpp_ArgTypeN(n) >::parse( *(i++), mpp_ArgN(n) ); BOOST_PP_REPEAT( BOOST_PP_ITERATION(), mpp_l, _ ) # undef mpp_l - // Now call the function binding the arguments to the values parsed above. callAndWrite is - // specialized to ignore a 'void' return value but automatically write all other values to the - // output stream. - detail::ReturnValueTraits::callAndWrite( + detail::CheckVoidReturn::call( boost::bind(function_, boost::ref(os) mpp_TrailingArgs()), os ); diff --git a/Console/ScopedDirectory.hh b/Console/ScopedDirectory.hh index c226b2e..91909b6 100644 --- a/Console/ScopedDirectory.hh +++ b/Console/ScopedDirectory.hh @@ -163,6 +163,8 @@ namespace console { Owner * owner_; }; +#ifndef DOXYGEN + template <> class ScopedDirectory : public ScopedDirectoryBase { @@ -172,7 +174,6 @@ namespace console { Object const & ob); }; -#ifndef DOXYGEN template SimpleCommandNode & senf_console_add_node( DirectoryNode & node, Owner & owner, std::string const & name, Function const & fn, ...); diff --git a/Console/ParseParameter.cti b/Console/Traits.cti similarity index 54% rename from Console/ParseParameter.cti rename to Console/Traits.cti index a88d7f3..e96392f 100644 --- a/Console/ParseParameter.cti +++ b/Console/Traits.cti @@ -21,9 +21,9 @@ // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \file - \brief ParseParameter inline template implementation */ + \brief Traits inline template implementation */ -//#include "ParseParameter.ih" +//#include "Traits.ih" // Custom includes #include "../Utils/TypeInfo.hh" @@ -32,62 +32,25 @@ ///////////////////////////////cti.p/////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// -// senf::console::detail::ParameterInfoBase - -prefix_ senf::console::detail::ParameterInfoBase::ParameterInfoBase(std::string const & type_) - : type (type_), name (), hasDefault (false) -{} - -/////////////////////////////////////////////////////////////////////////// -// senf::console::detail::ParameterInfo - -template -prefix_ typename senf::console::detail::ParameterInfo::ptr -senf::console::detail::ParameterInfo::create() -{ - return ptr(new ParameterInfo()); -} - -template -prefix_ senf::console::detail::ParameterInfo::ParameterInfo() - : ParameterInfoBase ( ParameterTraits::typeDescription() ), - defaultValue () -{} - -template -prefix_ std::string senf::console::detail::ParameterInfo::defaultValueStr() - const -{ - return hasDefault ? ParameterTraits::dump(defaultValue) : ""; -} - -/////////////////////////////////////////////////////////////////////////// // senf::console::detail::ReturnValueTraits template -template -prefix_ void senf::console::detail::ReturnValueTraits::callAndWrite(Fn const & fn, - std::ostream & os) +prefix_ void senf::console::ReturnValueTraits::format(Type const & value, + std::ostream & os) { - os << fn() << "\n"; -} - -template -prefix_ void senf::console::detail::ReturnValueTraits::callAndWrite(Fn const & fn, - std::ostream & os) -{ - fn(); + os << value; } /////////////////////////////////////////////////////////////////////////// -// senf::console::detail::ParameterTraits +// senf::console::ArgumentTraits template -prefix_ void senf::console::detail::ParameterTraits:: +prefix_ void senf::console::ArgumentTraits:: parse(ParseCommandInfo::TokensRange const & tokens, Type & out) { if (tokens.size() != 1) throw SyntaxErrorException("parameter syntax error"); + try { out = boost::lexical_cast(tokens.begin()[0].value()); } @@ -97,7 +60,7 @@ parse(ParseCommandInfo::TokensRange const & tokens, Type & out) } template -prefix_ std::string senf::console::detail::ParameterTraits::typeDescription() +prefix_ std::string senf::console::ArgumentTraits::description() { std::string type (prettyName(typeid(Type))); std::string::size_type i (type.rfind(':')); @@ -105,7 +68,7 @@ prefix_ std::string senf::console::detail::ParameterTraits::typeDescriptio } template -prefix_ std::string senf::console::detail::ParameterTraits::dump(Type const & value) +prefix_ std::string senf::console::ArgumentTraits::str(Type const & value) { return boost::lexical_cast(value); } diff --git a/Console/Traits.hh b/Console/Traits.hh new file mode 100644 index 0000000..8176fb0 --- /dev/null +++ b/Console/Traits.hh @@ -0,0 +1,114 @@ +// $Id$ +// +// Copyright (C) 2008 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// 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 Traits public header */ + +#ifndef HH_Traits_ +#define HH_Traits_ 1 + +// Custom includes +#include +#include +#include "../Utils/intrusive_refcount.hh" +#include "Parse.hh" +#include "Node.hh" + +//#include "Traits.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { +namespace console { + + /** \brief Customize return value formating + + ReturnValueTraits provides return value formatting. The default implementation provided here + will just write the value to the output stream. + + To customize this behavior for some type, specialize this class for the type. + + The output should \e not end in a newline since one is added automatically. + */ + template + struct ReturnValueTraits + { + typedef Type type; + + static void format(Type const & value, std::ostream & os); + ///< Write \a value to \a os + }; + + /** \brief Customize argument parsing + + ArgumentTraits provides argument parsing, Additionally, this class provides a way to get a + string-description of a type and to convert a value back into it's string representation + used to display default values. + + The default implementation provided here will use \c boost::lexical_cast and thereby \c + iostreams to convert an argument consisting of a single input token into the required + type. Types are named by returning the last component of the fully scoped name (e.g. \c + "string" for \c std::string). Values are formatted again using \c boost::lexical_cast. + + To customize this behavior for some type, specialize this class for the type. + */ + template + struct ArgumentTraits + { + typedef Type type; + + static void parse(ParseCommandInfo::TokensRange const & tokens, Type & out); + ///< Parse token range into value + /**< This function needs to parse \a tokens and write the + parsed value into \a out. This function needs to parse + the \e complete list of tokens, additional tokens must + be considered as syntax error. + \throws SyntaxErrorException + \param[in] tokens tokens to parse + \param[out] out parsed value */ + + static std::string description(); ///< String description of type + /**< Returns the string description of \a Type. Used to + generate online help. */ + static std::string str(Type const & value); ///< Stringify value + /**< To show default values in the online help, this + function converts a value back into a one-line string + representation. */ + }; + +}} + +///////////////////////////////hh.e//////////////////////////////////////// +//#include "Traits.cci" +//#include "Traits.ct" +#include "Traits.cti" +#endif + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Console/ParseParameter.test.cc b/Console/Traits.test.cc similarity index 90% rename from Console/ParseParameter.test.cc rename to Console/Traits.test.cc index d074c1d..83f8af5 100644 --- a/Console/ParseParameter.test.cc +++ b/Console/Traits.test.cc @@ -21,13 +21,13 @@ // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \file - \brief ParseParameter.test unit tests */ + \brief Traits.test unit tests */ -//#include "ParseParameter.test.hh" -//#include "ParseParameter.test.ih" +//#include "Traits.test.hh" +//#include "Traits.test.ih" // Custom includes -#include "ParseParameter.hh" +#include "Traits.hh" #include "../Utils/auto_unit_test.hh" #include diff --git a/Packets/Packet.cti b/Packets/Packet.cti index e16f88e..b824c09 100644 --- a/Packets/Packet.cti +++ b/Packets/Packet.cti @@ -174,6 +174,8 @@ senf::ConcretePacket::create(size_type size, senf::NoInit_t) return ConcretePacket(interpreter::create(size,senf::noinit)); } +#ifndef DOXYGEN + template template prefix_ senf::ConcretePacket senf::ConcretePacket:: @@ -192,6 +194,8 @@ senf::ConcretePacket::createAfter(Packet packet) return ConcretePacket(interpreter::createAfter(packet.ptr())); } +#endif + template prefix_ senf::ConcretePacket senf::ConcretePacket::createAfter(Packet packet, senf::NoInit_t) diff --git a/doclib/Doxyfile.global b/doclib/Doxyfile.global index 5d04e39..bb26ef7 100644 --- a/doclib/Doxyfile.global +++ b/doclib/Doxyfile.global @@ -1165,7 +1165,8 @@ PREDEFINED = DOXYGEN \ "SENF_LOG_CLASS_AREA()=" \ "SENF_LOG_DEFAULT_AREA(area)=" \ "SENF_LOG_DEFAULT_STREAM(stream)=" \ - "BOOST_PP_ITERATE()=" + "BOOST_PP_ITERATE()=" \ + "BOOST_PARAMETER_KEYWORD(ns, name)=unspecified_keyword_type name;" # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/doclib/html-munge.xsl b/doclib/html-munge.xsl index 8636996..11b9e15 100644 --- a/doclib/html-munge.xsl +++ b/doclib/html-munge.xsl @@ -1,5 +1,6 @@ -