// $Id$
//
-// Copyright (C) 2008
+// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
#include <vector>
#include <boost/type_traits/function_traits.hpp>
-#include <boost/type_traits/is_member_pointer.hpp>
+#include <boost/type_traits/is_member_function_pointer.hpp>
#include <boost/mpl/if.hpp>
#include <boost/utility.hpp>
#include <boost/parameter/keyword.hpp>
#include <boost/parameter/parameters.hpp>
-#include "../../config.hh"
+#include <senf/config.hh>
#include "OverloadedCommand.hh"
#include "Traits.hh"
-#include "../../Utils/type_traits.hh"
+#include <senf/Utils/type_traits.hh>
#include "ParsedCommand.ih"
#include "ParsedCommand.mpp"
-///////////////////////////////hh.p////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
namespace senf {
namespace console {
\section overload_add Adding argument parsing callbacks to the tree
- Adding appropriate callbacks to the tree is very simple: just path a function pointer to
- DirectoryNode::add() or a member function pointer to ScopedDirectory::add().
+ To add overloads to the tree, use the senf::console::factory::Command factory:
\code
+ namespace fty = senf::console::factory;
+
std::string taskStatus(int id);
- senf::console::root().add("taskStatus", &taskStatus);
+ senf::console::root().add("taskStatus", fty::Command(&taskStatus));
\endcode
There are quite a number of additional parameters available to be set. These parameters are
calls after adding the node:
\code
- senf::console::root().add("taskStatus", &taskStatus)
+ senf::console::root().add("taskStatus", fty::Command(&taskStatus)
.doc("Query the current task status")
.arg( name = "id",
description = "numeric id of task to check, -1 for the current task."
- default_value = -1 );
+ default_value = -1 ) );
\endcode
You may also add an additional \c std::ostream & Argument as first argument to the
std::string taskStatus(std::string const & name);
senf::console::root()
- .add("taskStatus", static_cast<std::string (*)(int)>(&taskStatus))
+ .add("taskStatus", fty::Command(static_cast<std::string (*)(int)>(
+ &taskStatus))
.doc("Query the current task status")
.overloadDoc("Query status by id")
.arg( name = "id",
description = "numeric id of task to check, -1 for the current task."
- default_value = -1 );
+ default_value = -1 ) );
senf::console::root()
- .add("taskStatus", static_cast<std::string (*)(std::string const &)>(&taskStatus))
+ .add("taskStatus", fty::Commande(static_cast<std::string (*)(std::string const &)>(
+ &taskStatus))
.overloadDoc("Query status by name")
.arg( name = "name",
- description = "name of task to check" );
+ description = "name of task to check" ) );
\endcode
We can see here, that taking the address of an overloaded function requires a cast. If you
should do so to make the unwieldy casts unnecessary.
\section overload_parse Custom parameter parsers
-
+
By default, parameters are parsed using \c boost::lexical_cast and therefore using \c
iostreams. This means, that any type which can be read from a stream can automatically be
used as argument type.
{
public:
typedef boost::intrusive_ptr<ParsedCommandOverload> 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(Utils/Console/ParsedCommand.mpp), \
- 1))
+# define BOOST_PP_ITERATION_PARAMS_1 \
+ (4, (0, SENF_CONSOLE_MAX_COMMAND_ARITY, \
+ SENF_ABSOLUTE_INCLUDE_PATH(Utils/Console/ParsedCommand.mpp), \
+ 1))
# include BOOST_PP_ITERATE()
#endif
- /** \brief Generic ParsedCommandOverladBase attributes
+ /** \brief Generic ParsedCommandOverloadBase 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.
\see \ref console_autoparse
*/
class ParsedCommandAttributorBase
+ : public detail::NodeFactory
{
public:
- OverloadedCommandNode & node() const; ///< Return the node object
- operator OverloadedCommandNode & () const; ///< Automatically convert to node object
+ typedef OverloadedCommandNode node_type;
+ typedef OverloadedCommandNode & result_type;
protected:
- ParsedCommandAttributorBase(ParsedCommandOverloadBase & overload, unsigned index);
+ ParsedCommandAttributorBase(ParsedCommandOverloadBase::ptr overload, unsigned index);
+ ParsedCommandAttributorBase(ParsedCommandAttributorBase const & other, unsigned index);
- void argName(std::string const & name) const;
- void argDoc(std::string const & doc) const;
- void typeName(std::string const & doc) const;
- void defaultDoc(std::string const & doc) const;
+ void argName(std::string const & name);
+ void argDoc(std::string const & doc);
+ void typeName(std::string const & doc);
+ void defaultDoc(std::string const & doc);
ParsedCommandOverloadBase & overload() const;
- void overloadDoc(std::string const & doc) const;
- void nodeDoc(std::string const & doc) const;
- void shortDoc(std::string const & doc) const;
-
+ void overloadDoc(std::string const & doc);
+ void nodeDoc(std::string const & doc);
+ void shortDoc(std::string const & doc);
+
private:
- ParsedCommandOverloadBase & overload_;
+ OverloadedCommandNode & create(DirectoryNode & dir, std::string const & name) const;
+
+ ParsedCommandOverloadBase::ptr overload_;
unsigned index_;
+ boost::optional<std::string> doc_;
+ boost::optional<std::string> shortdoc_;
+
+ friend class senf::console::DirectoryNode;
};
- /** \brief Non argument dependent ParsedCommandBase attributes
-
+ /** \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.
Overload & overload() const; ///< Get the command overload
protected:
- ParsedCommandAttributor(Overload & overload, unsigned index);
+ ParsedCommandAttributor(typename Overload::ptr overload, unsigned index);
+ ParsedCommandAttributor(ParsedCommandAttributorBase const & other, unsigned index);
private:
};
/** \brief Keyword argument tags
The tags defined in this namespace are used as keyword arguments via the <a
- href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
+ href="http://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html">Boost.Parameter</a>
library.
For the keyword tags, the standard C++ scoping rules apply
\code
+ namespace fty=senf::console::factory;
+
// Either qualify them with their complete namespace
- dir.add(...)
- .arg( senf::console::kw::name = "name" );
-
+ dir.add(..., fty::Command(...)
+ .arg( senf::console::kw::name = "name" ) );
+
// Or use a namespace alias
namespace kw = senf::console::kw;
- dir.add(...)
- .arg( kw::name = "name" );
+ dir.add(..., fty::Command(...)
+ .arg( kw::name = "name" ) );
// Or import the keywords into the current namespace (beware of name collisions)
using namespace senf::console::kw;
- dir.add(...)
- .arg( name = "name" );
+ dir.add(..., fty::Command(...)
+ .arg( name = "name" ) );
\endcode
The second alternative is preferred, the <tt>using namespace</tt> directive may be used as
\code
void command(int);
- dir.add("command", &command)
+ dir.add("command", fty::Command(&command)
.arg( kw::name = "name",
kw::description = "description",
kw::default_value = 1,
kw::type_name = "type_name",
- kw::default_doc = "default_doc" );
+ kw::default_doc = "default_doc" ) );
\endcode
Will create the following documentation:
\htmlonly
<pre>
Usage:
command [name:type_name]
-
+
With:
name description
default: default_doc
\endhtmlonly
\see \ref senf::console::ParsedArgumentAttributor::arg()
+
+ \ingroup console_commands
*/
namespace kw {
BOOST_PARAMETER_KEYWORD(type, name) ///< Argument name
token list returned by the console/config parser into
the appropriate value. If not set explicitly, this
conversion is supplied by the ArgumentTraits
- class.
+ class.
Setting the \a parser attribute allows to use a custom
parser. The parser is an arbitrary callable object with
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.
: public ParsedCommandAttributor<Overload>
{
public:
- Self doc(std::string const & doc) const; ///< Set documentation for all overloads
- Self shortdoc(std::string const & doc) const; ///< Set short documentation for all overloads
- Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation
- Self formatter(typename Overload::Formatter formatter) const;
+ Self doc(std::string const & doc); ///< Set documentation for all overloads
+ Self shortdoc(std::string const & doc); ///< Set short documentation for all overloads
+ Self overloadDoc(std::string const & doc); ///< Set overload specific documentation
+ Self formatter(typename Overload::Formatter formatter);
///< Set return value formatter
/**< This member is only available, if the \a ReturnType of
the installed callback is not \c void.
value and writes it properly formated to \a os. */
protected:
- ParsedArgumentAttributorBase(Overload & overload, unsigned index);
+ ParsedArgumentAttributorBase(typename Overload::ptr overload, unsigned index);
+ ParsedArgumentAttributorBase(ParsedCommandAttributorBase const & other, unsigned index);
private:
};
: public ParsedCommandAttributor<Overload>
{
public:
- Self doc(std::string const & doc) const; ///< Set documentation for all overloads
- Self shortdoc(std::string const & doc) const; ///< Set short documentation for all overloads
- Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation
+ Self doc(std::string const & doc); ///< Set documentation for all overloads
+ Self shortdoc(std::string const & doc); ///< Set short documentation for all overloads
+ Self overloadDoc(std::string const & doc); ///< Set overload specific documentation
protected:
- ParsedArgumentAttributorBase(Overload & overload, unsigned index);
+ ParsedArgumentAttributorBase(typename Overload::ptr overload, unsigned index);
+ ParsedArgumentAttributorBase(ParsedCommandAttributorBase const & other, unsigned index);
private:
};
#endif
-
+
/** \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.
\see \ref console_autoparse
*/
- template < class Overload, unsigned index, bool flag>
+ template <class Overload, unsigned index, bool flag>
class ParsedArgumentAttributor
- : public ParsedArgumentAttributorBase< Overload,
+ : public ParsedArgumentAttributorBase< Overload,
ParsedArgumentAttributor<Overload, index, flag> >
{
typedef boost::parameter::parameters<
kw::type::parser> arg_params;
public:
- typedef OverloadedCommandNode node_type;
- typedef ParsedArgumentAttributor return_type;
-
- typedef typename senf::function_traits_arg_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 ParsedArgumentAttributor<Overload, index+1> next_type;
/**< This member changes the attributes for the current
argument. The attributes are passed to arg() as keyword
arguments using the <a
- href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
- library.
+ href="http://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html">Boost.Parameter</a>
+ library.
\code
...
- .arg( kw::name = "name",
+ .arg( kw::name = "name",
kw::default_value = 1 )
...
\endcode
The valid keywords are defined in the senf::console::kw
namespace.
-
+
Each call to arg() will increment the argument index
and advance to the next argument. This member is only
present, if there is an argument at the current
#endif
private:
- explicit ParsedArgumentAttributor(Overload & overload);
+ explicit ParsedArgumentAttributor(typename Overload::ptr overload);
+ explicit ParsedArgumentAttributor(ParsedCommandAttributorBase const & other);
template <class ArgumentPack>
- next_type argInfo(ArgumentPack const & args) const;
+ next_type argInfo(ArgumentPack const & args);
template <class Kw, class ArgumentPack>
- void argInfo(Kw const &, ArgumentPack const &, boost::mpl::false_)
- const;
+ void argInfo(Kw const &, ArgumentPack const &, boost::mpl::false_);
template <class ArgumentPack>
- void argInfo(boost::parameter::keyword<kw::type::name> const &,
- ArgumentPack const & args, boost::mpl::true_)
- const;
+ void argInfo(boost::parameter::keyword<kw::type::name> const &,
+ ArgumentPack const & args, boost::mpl::true_);
template <class ArgumentPack>
- void argInfo(boost::parameter::keyword<kw::type::description> const &,
- ArgumentPack const & args, boost::mpl::true_)
- const;
+ void argInfo(boost::parameter::keyword<kw::type::description> const &,
+ ArgumentPack const & args, boost::mpl::true_);
template <class ArgumentPack>
- void argInfo(boost::parameter::keyword<kw::type::default_value> const &,
- ArgumentPack const & args, boost::mpl::true_)
- const;
+ void argInfo(boost::parameter::keyword<kw::type::default_value> const &,
+ ArgumentPack const & args, boost::mpl::true_);
template <class ArgumentPack>
- void argInfo(boost::parameter::keyword<kw::type::type_name> const &,
- ArgumentPack const & args, boost::mpl::true_)
- const;
+ void argInfo(boost::parameter::keyword<kw::type::type_name> const &,
+ ArgumentPack const & args, boost::mpl::true_);
template <class ArgumentPack>
- void argInfo(boost::parameter::keyword<kw::type::default_doc> const &,
- ArgumentPack const & args, boost::mpl::true_)
- const;
+ void argInfo(boost::parameter::keyword<kw::type::default_doc> const &,
+ ArgumentPack const & args, boost::mpl::true_);
template <class ArgumentPack>
- void argInfo(boost::parameter::keyword<kw::type::parser> const &,
- ArgumentPack const & args, boost::mpl::true_)
- const;
+ void argInfo(boost::parameter::keyword<kw::type::parser> const &,
+ ArgumentPack const & args, boost::mpl::true_);
next_type next() const;
- void defaultValue(value_type const & value) const;
- template <class Fn> void parser(Fn fn) const;
+ void defaultValue(value_type const & value);
+ template <class Fn> void parser(Fn fn);
template <class O, unsigned i, bool f>
friend class ParsedArgumentAttributor;
template <class Overload, unsigned index>
class ParsedArgumentAttributor<Overload, index, false>
- : public ParsedArgumentAttributorBase< Overload,
+ : public ParsedArgumentAttributorBase< Overload,
ParsedArgumentAttributor<Overload, index, false> >
{
public:
typedef ParsedArgumentAttributor return_type;
private:
- explicit ParsedArgumentAttributor(Overload & overload);
+ explicit ParsedArgumentAttributor(typename Overload::ptr overload);
+ explicit ParsedArgumentAttributor(ParsedCommandAttributorBase const & other);
template <class O, unsigned i, bool f>
friend class ParsedArgumentAttributor;
friend class detail::ParsedCommandAddNodeAccess;
};
- template <class Function>
- typename detail::ParsedCommandTraits<Function>::Attributor
- senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int,
- typename boost::enable_if_c<
- detail::ParsedCommandTraits<Function>::is_callable>::type * = 0);
+#endif
+
+namespace factory {
+
+#ifdef DOXYGEN
+
+ /** \brief OverloadedCommandNode factory
+
+ This factory will create new OverloadedCommandNode instances <em>or add new overloads</em>
+ to an existing OverloadedCommandNode. The factory supports automatic argument parsing.
+
+ Commands are added to the tree using
+ \code
+ namespace fty = senf::console::factory;
+ node.add("name", fty::Command(function));
+ \endcode
+
+ The Command factory supports the following features:
+ \li Automatic argument parsing
+ \li Automatic binding of member functions. Pass the owning instance as second argument to
+ the factory
+ \li Conversion to a compatible signature. Pass the signature as template argument to the
+ factory
+
+ If the signature of the command added matches
+ \code
+ void (std::ostream &, senf::console::ParsedCommandInfo const &)
+ \endcode
+ The command is added using manual argument parsing, otherwise it is added using automatic
+ argument parsing.
+
+ See the <a href="classsenf_1_1console_1_1factory_1_1Command-members.html">List of all
+ members</a> for additional attributes.
+
+ \note This class is for exposition only, the real interface consists of several overloaded
+ factory functions.
+
+ \see \ref console_manualparse \n
+ \ref console_autoparse
+ */
+ class Command : public ParsedArgumentAttributor
+ {
+ public:
+ typedef OverloadedCommandNode node_type;
+ typedef unspecified result_type;
+
+ Command(unspecified fn); ///< Create a node calling \a fn
+ template <class Signature>
+ Command(unspecified fn); ///< Create a node calling \a fn with signature \a Signature
+ /**< The given \a Signature must be compatible with \a fn
+ for each argument and the return value. */
+
+ Command(member_function_pointer fn, Owner const * owner);
+ ///< Create a node calling member function \a fn on \a owner
+ template <class Signature>
+ Command(member_function_pointer fn, Owner const * owner);
+ ///< Create a node calling member function \a fn on \a owner
+ /// with the given \a Signature
+ /**< The given \a Signature must be compatible with \a fn
+ for each argument and the return value. */
+
+ };
+
+#else
template <class Signature>
- typename detail::ParsedCommandTraits<Signature>::Attributor
- senf_console_add_node(DirectoryNode & node, std::string const & name,
- boost::function<Signature> fn, int);
+ SimpleOverloadAttributor
+ Command(boost::function<Signature> fn,
+ typename boost::enable_if_c<detail::ParsedCommandTraits<Signature>::is_simple>::type * = 0);
- template <class Owner, class Function>
- typename detail::ParsedCommandTraits<Function>::Attributor
- senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
- Function fn, int,
- typename boost::enable_if_c<
- detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
+ template <class Function>
+ SimpleOverloadAttributor
+ Command(Function fn,
+ typename boost::enable_if_c<detail::ParsedCommandTraits<Function>::is_simple>::type * = 0);
+
+ template <class Owner, class Member>
+ SimpleOverloadAttributor
+ Command(Member memfn, Owner * owner,
+ typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0,
+ typename boost::enable_if_c<detail::ParsedCommandTraits<Member>::is_simple>::type * = 0);
+
+ template <class Owner, class Member>
+ SimpleOverloadAttributor
+ Command(Member memfn, Owner const * owner,
+ typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0,
+ typename boost::enable_if_c<detail::ParsedCommandTraits<Member>::is_simple>::type * = 0);
+
+ template <class CastTo, class Signature>
+ typename senf::console::detail::ParsedCommandTraits<CastTo>::Attributor
+ Command(boost::function<Signature> fn);
+
+ template <class CastTo, class Function>
+ typename senf::console::detail::ParsedCommandTraits<CastTo>::Attributor
+ Command(Function fn,
+ typename boost::enable_if_c<detail::ParsedCommandTraits<Function>::is_callable>::type * = 0,
+ typename boost::disable_if<boost::is_member_function_pointer<Function> >::type * = 0);
-#endif
+ template <class Signature>
+ typename senf::console::detail::ParsedCommandTraits<Signature>::Attributor
+ Command(boost::function<Signature> fn);
-}}
+ template <class Function>
+ typename senf::console::detail::ParsedCommandTraits<Function>::Attributor
+ Command(Function fn,
+ typename boost::enable_if_c<detail::ParsedCommandTraits<Function>::is_callable>::type * = 0,
+ typename boost::disable_if<boost::is_member_function_pointer<Function> >::type * = 0);
+
+ template <class Owner, class Member>
+ typename senf::console::detail::ParsedCommandTraits<Member>::Attributor
+ Command(Member memfn, Owner * owner,
+ typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0);
+
+ template <class Owner, class Member>
+ typename senf::console::detail::ParsedCommandTraits<Member>::Attributor
+ Command(Member memfn, Owner const * owner,
+ typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0);
+
+ template <class CastTo, class Owner, class Member>
+ typename senf::console::detail::ParsedCommandTraits<CastTo>::Attributor
+ Command(Member memfn, Owner * owner,
+ typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0);
+
+ template <class CastTo, class Owner, class Member>
+ typename senf::console::detail::ParsedCommandTraits<CastTo>::Attributor
+ Command(Member memfn, Owner const * owner,
+ typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0);
-#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
+#endif
-BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedCommandOverload, (class,unsigned))
-BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedArgumentAttributor, (class, unsigned, bool))
-BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function_traits, 1)
+}}}
-///////////////////////////////hh.e////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
#include "ParsedCommand.cci"
#include "ParsedCommand.ct"
#include "ParsedCommand.cti"