4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 \brief ParsedCommand public header */
26 #ifndef HH_SENF_Scheduler_Console_ParsedCommand_
27 #define HH_SENF_Scheduler_Console_ParsedCommand_ 1
31 #define BOOST_PARAMETER_MAX_ARITY 6
34 #include <boost/type_traits/function_traits.hpp>
35 #include <boost/type_traits/is_member_function_pointer.hpp>
36 #include <boost/mpl/if.hpp>
37 #include <boost/utility.hpp>
38 #include <boost/parameter/keyword.hpp>
39 #include <boost/parameter/parameters.hpp>
40 #include <senf/config.hh>
41 #include "OverloadedCommand.hh"
43 #include <senf/Utils/type_traits.hh>
45 #include "ParsedCommand.ih"
46 #include "ParsedCommand.mpp"
47 ///////////////////////////////hh.p////////////////////////////////////////
52 namespace detail { class ArgumentInfoBase; }
54 /** \brief CommandOverload implementation with automatic argument parsing
56 ParsedCommandOverloadBase implements a CommandOverload implementation supporting automatic
57 parsing of arguments. This is \e not a node, it's a CommandOverload which is then added to
58 an OverloadedCommandNode instance.
60 Automatic argument parsing and return value processing consists of several components:
61 \li \ref overload_add Adding overload instances to the tree
62 \li (Advanced) \ref overload_parse
63 \li (Advanced) \ref overload_format
65 \section overload_add Adding argument parsing callbacks to the tree
67 To add overloads to the tree, use the senf::console::factory::Command factory:
69 namespace fty = senf::console::factory;
71 std::string taskStatus(int id);
73 senf::console::root().add("taskStatus", fty::Command(&taskStatus));
76 There are quite a number of additional parameters available to be set. These parameters are
77 documented in ParsedArgumentAttributor. Parameters are set by adding them as additional
78 calls after adding the node:
81 senf::console::root().add("taskStatus", fty::Command(&taskStatus)
82 .doc("Query the current task status")
84 description = "numeric id of task to check, -1 for the current task."
85 default_value = -1 ) );
88 You may also add an additional \c std::ostream & Argument as first argument to the
89 callback. If this argument is present, the stream connected to the console which issued the
90 command will be passed there. This allows writing arbitrary messages to the console.
92 Additionally, overloading is supported by registering multiple commands under the same
93 name. So, elaborating on above example:
95 std::string taskStatus(int id);
96 std::string taskStatus(std::string const & name);
99 .add("taskStatus", fty::Command(static_cast<std::string (*)(int)>(
101 .doc("Query the current task status")
102 .overloadDoc("Query status by id")
104 description = "numeric id of task to check, -1 for the current task."
105 default_value = -1 ) );
106 senf::console::root()
107 .add("taskStatus", fty::Commande(static_cast<std::string (*)(std::string const &)>(
109 .overloadDoc("Query status by name")
111 description = "name of task to check" ) );
114 We can see here, that taking the address of an overloaded function requires a cast. If you
115 can give unique names to each of the C++ overloads (not the overloads in the console), you
116 should do so to make the unwieldy casts unnecessary.
118 \section overload_parse Custom parameter parsers
120 By default, parameters are parsed using \c boost::lexical_cast and therefore using \c
121 iostreams. This means, that any type which can be read from a stream can automatically be
122 used as argument type.
124 However, argument parsing can be configured by specializing
125 senf::console::ArgumentTraits. See that class for more information.
127 \section overload_format Custom return-value formatters
129 By default, return values are streamed to an ostream. This automatically allows any
130 streamable type to be used as return value. To add new types or customize the formating, the
131 senf::console::ReturnValueTraits template needs to be specialized for that type. See
132 that class for more information.
134 \ingroup console_commands
136 class ParsedCommandOverloadBase
137 : public CommandOverload
140 typedef boost::intrusive_ptr<ParsedCommandOverloadBase> ptr;
142 detail::ArgumentInfoBase & arg(unsigned n) const;
144 void doc(std::string const & d);
147 ParsedCommandOverloadBase();
149 template <class Type> void addParameter();
152 virtual unsigned v_numArguments() const;
153 virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const;
154 virtual std::string v_doc() const;
156 typedef std::vector<detail::ArgumentInfoBase::ptr> Parameters;
157 Parameters parameters_;
161 /** \brief Parsed command overload
163 ParsedCommandOverload provides the command overload added to an OverloadedCommandNode for an
164 automatically parsed command.
166 This class is normally instantiated automatically when adding a function or member-function
167 pointer as callback to the tree. Manually instantiation this type of overload is \e not
168 simple, since the function signature has to be manipulated correctly to support the optional
169 \c std::ostream first argument.
171 \implementation This class is specialized for each supported number of command arguments.
173 \todo Implement automatic binding of member functions for parser and formatter
175 template <class FunctionTraits, class ReturnType, unsigned arity>
176 class ParsedCommandOverload : public ParsedCommandOverloadBase
179 typedef boost::intrusive_ptr<ParsedCommandOverload> ptr;
184 # define BOOST_PP_ITERATION_PARAMS_1 \
185 (4, (0, SENF_CONSOLE_MAX_COMMAND_ARITY, \
186 SENF_ABSOLUTE_INCLUDE_PATH(Utils/Console/ParsedCommand.mpp), \
188 # include BOOST_PP_ITERATE()
192 /** \brief Generic ParsedCommandOverloadBase attributes
194 Attributes for parsed commands are not set directly on the node. They are set via a special
195 attributor temporary returned when adding a parsed command to the tree.
197 This class is the base class for those attributors. It provides members which do not depend
198 in any way on the exact type of command added.
200 \see \ref console_autoparse
202 class ParsedCommandAttributorBase
203 : public detail::NodeFactory
206 typedef OverloadedCommandNode node_type;
207 typedef OverloadedCommandNode & result_type;
210 ParsedCommandAttributorBase(ParsedCommandOverloadBase::ptr overload, unsigned index);
211 ParsedCommandAttributorBase(ParsedCommandAttributorBase const & other, unsigned index);
213 void argName(std::string const & name);
214 void argDoc(std::string const & doc);
215 void typeName(std::string const & doc);
216 void defaultDoc(std::string const & doc);
218 ParsedCommandOverloadBase & overload() const;
219 void overloadDoc(std::string const & doc);
220 void nodeDoc(std::string const & doc);
221 void shortDoc(std::string const & doc);
224 OverloadedCommandNode & create(DirectoryNode & dir, std::string const & name) const;
226 ParsedCommandOverloadBase::ptr overload_;
228 boost::optional<std::string> doc_;
229 boost::optional<std::string> shortdoc_;
231 friend class senf::console::DirectoryNode;
234 /** \brief Non argument dependent ParsedCommandBase attributes
236 Attributes for parsed commands are not set directly on the node. They are set via a special
237 attributor temporary returned when adding a parsed command to the tree.
239 This class adds all those members, which do depend on the type of command added (and thereby
240 on that commands signature) but do not depend on the type of any single argument.
242 \see \ref console_autoparse
244 template <class Overload>
245 class ParsedCommandAttributor
246 : public ParsedCommandAttributorBase
249 Overload & overload() const; ///< Get the command overload
252 ParsedCommandAttributor(typename Overload::ptr overload, unsigned index);
253 ParsedCommandAttributor(ParsedCommandAttributorBase const & other, unsigned index);
258 /** \brief Keyword argument tags
260 The tags defined in this namespace are used as keyword arguments via the <a
261 href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
264 For the keyword tags, the standard C++ scoping rules apply
266 namespace fty=senf::console::factory;
268 // Either qualify them with their complete namespace
269 dir.add(..., fty::Command(...)
270 .arg( senf::console::kw::name = "name" ) );
272 // Or use a namespace alias
273 namespace kw = senf::console::kw;
274 dir.add(..., fty::Command(...)
275 .arg( kw::name = "name" ) );
277 // Or import the keywords into the current namespace (beware of name collisions)
278 using namespace senf::console::kw;
279 dir.add(..., fty::Command(...)
280 .arg( name = "name" ) );
283 The second alternative is preferred, the <tt>using namespace</tt> directive may be used as
284 long as the keyword names do not clash with another visible symbol.
286 \section kw_attributes Argument attribute values
288 The keywords are used to set argument attributes. The keywords \ref default_value and \ref
289 parser influence, how an argument is parsed/interpreted whereas \ref name, \ref description,
290 \ref type_name and \ref default_doc are used to change the arguments documentation:
294 dir.add("command", fty::Command(&command)
295 .arg( kw::name = "name",
296 kw::description = "description",
297 kw::default_value = 1,
298 kw::type_name = "type_name",
299 kw::default_doc = "default_doc" ) );
301 Will create the following documentation:
305 command [name:type_name]
313 \see \ref senf::console::ParsedArgumentAttributor::arg()
316 BOOST_PARAMETER_KEYWORD(type, name) ///< Argument name
317 /**< Sets the displayed name of the argument. */
318 BOOST_PARAMETER_KEYWORD(type, description) ///< One-line argument description
319 /**< This description is shown in the argument
320 reference. If several overloads have same-named
321 arguments, only one of them should be documented. This
322 documentation then applies to all arguments of that
324 BOOST_PARAMETER_KEYWORD(type, default_value) ///< Argument default value
325 /**< If a default value is specified for an argument, that
326 argument is optional. If an overload is called with
327 fewer arguments than defined, optional values will be
328 used beginning at the last optional argument and going
329 forward until all arguments have values assigned. E.g.,
330 an overload with 5 parameters \a a - \a e with two
333 command a:int [b:int] c:int [d:int] e:int
335 When calling the overload, the arguments will be
336 assigned in the following way:
337 <table class="senf fixedwidth">
339 <td style="whitespace:no-wrap"><tt>command 1 2</tt></td>
340 <td colspan="5">SyntaxErrorException: invalid number of
344 <td style="white-space:nowrap"><tt>command 1 2 3</tt></td>
345 <td style="width:6em">\a a = 1</td><td style="width:6em">\a b = \e default</td><td style="width:6em">\a c = 2</td><td style="width:6em">\a d = \e default</td><td style="width:6em">\a e = 3</td>
348 <td style="white-space:nowrap"><tt>command 1 2 3 4</tt></td>
349 <td>\a a = 1</td><td>\a b = 2</td><td>\a c = 3</td><td>\a d = \e default</td><td>\a e = 4</td>
352 <td style="white-space:nowrap"><tt>command 1 2 3 4 5</tt></td>
353 <td>\a a = 1</td><td>\a b = 2</td><td>\a c = 3</td><td>\a d = 4</td><td>\a e = 5</td>
356 <td style="white-space:nowrap"><tt>command 1 2 3 4 5 6</tt></td>
357 <td colspan="5">SyntaxErrorException: invalid number of
361 So, if you use default values as you are used to,
362 assigning default values to consecutive trailing
363 arguments, they work like they do in C++ and most other
365 BOOST_PARAMETER_KEYWORD(type, type_name) ///< Type name of this arguments type
366 /**< By default, the type of an argument is extracted from
367 the C++ type name by taking the last component of the
368 fully scoped name. This value can be changed by setting
370 BOOST_PARAMETER_KEYWORD(type, default_doc) ///< String rep of default value
371 /**< By default, the default value is documented by
372 converting the value to it's string representation
373 using the corresponding return value formatter which by
374 default uses \c boost::lexical_cast / \c iostreams. The
375 displayed value can be changed by setting this
377 BOOST_PARAMETER_KEYWORD(type, parser) ///< Argument parser
378 /**< The argument parser is used to convert the argument
379 token list returned by the console/config parser into
380 the appropriate value. If not set explicitly, this
381 conversion is supplied by the ArgumentTraits
384 Setting the \a parser attribute allows to use a custom
385 parser. The parser is an arbitrary callable object with
388 void parser(senf::console::ParseCommandInfo::TokensRange const & tokens, value_type & out);
390 where \c value_type is the type of the overload
391 parameter. The parser must read and parse the complete
392 \a tokens range and return the parsed value in \a
393 out. If the parser fails, it must raise a
394 senf::console::SyntaxErrorException. */
397 /** \brief Derived class dependent ParsedCommandBase attributes
399 Attributes for parsed commands are not set directly on the node. They are set via a special
400 attributor temporary returned when adding a parsed command to the tree.
402 This class adds all those members, which do not depend on any specific argument but which
403 need to return the correct attributor type.
405 \see \ref console_autoparse
407 template <class Overload, class Self, class ReturnType=typename Overload::traits::result_type>
408 class ParsedArgumentAttributorBase
409 : public ParsedCommandAttributor<Overload>
412 Self doc(std::string const & doc); ///< Set documentation for all overloads
413 Self shortdoc(std::string const & doc); ///< Set short documentation for all overloads
414 Self overloadDoc(std::string const & doc); ///< Set overload specific documentation
415 Self formatter(typename Overload::Formatter formatter);
416 ///< Set return value formatter
417 /**< This member is only available, if the \a ReturnType of
418 the installed callback is not \c void.
420 If \a ReturnType is not \c void, the \a formatter must
421 be a callable with a signature compatible with
423 void formatter(ReturnType const & value, std::ostream & os);
425 The \a formatter takes the return value of the call \a
426 value and writes it properly formated to \a os. */
429 ParsedArgumentAttributorBase(typename Overload::ptr overload, unsigned index);
430 ParsedArgumentAttributorBase(ParsedCommandAttributorBase const & other, unsigned index);
437 template <class Overload, class Self>
438 class ParsedArgumentAttributorBase<Overload, Self, void>
439 : public ParsedCommandAttributor<Overload>
442 Self doc(std::string const & doc); ///< Set documentation for all overloads
443 Self shortdoc(std::string const & doc); ///< Set short documentation for all overloads
444 Self overloadDoc(std::string const & doc); ///< Set overload specific documentation
447 ParsedArgumentAttributorBase(typename Overload::ptr overload, unsigned index);
448 ParsedArgumentAttributorBase(ParsedCommandAttributorBase const & other, unsigned index);
455 /** \brief Argument dependent ParsedCommandBase attributes
457 Attributes for parsed commands are not set directly on the node. They are set via a special
458 attributor temporary returned when adding a parsed command to the tree.
460 This class adds all those members, which depend on a specific argument. Each call to \c arg
461 will advance to the next argument.
463 \see \ref console_autoparse
465 template <class Overload, unsigned index, bool flag>
466 class ParsedArgumentAttributor
467 : public ParsedArgumentAttributorBase< Overload,
468 ParsedArgumentAttributor<Overload, index, flag> >
470 typedef boost::parameter::parameters<
472 kw::type::description,
473 kw::type::default_value,
475 kw::type::default_doc,
476 kw::type::parser> arg_params;
479 typedef typename senf::function_traits_arg_type<
480 typename Overload::traits, int(index) >::type arg_type;
481 typedef typename senf::remove_cvref< arg_type >::type value_type;
482 typedef ParsedArgumentAttributor<Overload, index+1> next_type;
484 next_type arg() const; ///< Set argument attributes
485 /**< This member changes the attributes for the current
486 argument. The attributes are passed to arg() as keyword
487 arguments using the <a
488 href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
492 .arg( kw::name = "name",
493 kw::default_value = 1 )
496 The valid keywords are defined in the senf::console::kw
499 Each call to arg() will increment the argument index
500 and advance to the next argument. This member is only
501 present, if there is an argument at the current
506 # define BOOST_PP_ITERATION_PARAMS_1 \
507 (4, (1, BOOST_PARAMETER_MAX_ARITY, \
508 SENF_ABSOLUTE_INCLUDE_PATH(Utils/Console/ParsedCommand.mpp), \
510 # include BOOST_PP_ITERATE()
515 explicit ParsedArgumentAttributor(typename Overload::ptr overload);
516 explicit ParsedArgumentAttributor(ParsedCommandAttributorBase const & other);
518 template <class ArgumentPack>
519 next_type argInfo(ArgumentPack const & args);
520 template <class Kw, class ArgumentPack>
521 void argInfo(Kw const &, ArgumentPack const &, boost::mpl::false_);
523 template <class ArgumentPack>
524 void argInfo(boost::parameter::keyword<kw::type::name> const &,
525 ArgumentPack const & args, boost::mpl::true_);
526 template <class ArgumentPack>
527 void argInfo(boost::parameter::keyword<kw::type::description> const &,
528 ArgumentPack const & args, boost::mpl::true_);
529 template <class ArgumentPack>
530 void argInfo(boost::parameter::keyword<kw::type::default_value> const &,
531 ArgumentPack const & args, boost::mpl::true_);
532 template <class ArgumentPack>
533 void argInfo(boost::parameter::keyword<kw::type::type_name> const &,
534 ArgumentPack const & args, boost::mpl::true_);
535 template <class ArgumentPack>
536 void argInfo(boost::parameter::keyword<kw::type::default_doc> const &,
537 ArgumentPack const & args, boost::mpl::true_);
538 template <class ArgumentPack>
539 void argInfo(boost::parameter::keyword<kw::type::parser> const &,
540 ArgumentPack const & args, boost::mpl::true_);
542 next_type next() const;
544 void defaultValue(value_type const & value);
545 template <class Fn> void parser(Fn fn);
547 template <class O, unsigned i, bool f>
548 friend class ParsedArgumentAttributor;
550 friend class detail::ParsedCommandAddNodeAccess;
555 template <class Overload, unsigned index>
556 class ParsedArgumentAttributor<Overload, index, false>
557 : public ParsedArgumentAttributorBase< Overload,
558 ParsedArgumentAttributor<Overload, index, false> >
561 typedef OverloadedCommandNode node_type;
562 typedef ParsedArgumentAttributor return_type;
565 explicit ParsedArgumentAttributor(typename Overload::ptr overload);
566 explicit ParsedArgumentAttributor(ParsedCommandAttributorBase const & other);
568 template <class O, unsigned i, bool f>
569 friend class ParsedArgumentAttributor;
571 friend class detail::ParsedCommandAddNodeAccess;
580 /** \brief OverloadedCommandNode factory
582 This factory will create new OverloadedCommandNode instances <em>or add new overloads</em>
583 to an existing OverloadedCommandNode. The factory supports automatic argument parsing.
585 Commands are added to the tree using
587 namespace fty = senf::console::factory;
588 node.add("name", fty::Command(function));
591 The Command factory supports the following features:
592 \li Automatic argument parsing
593 \li Automatic binding of member functions. Pass the owning instance as second argument to
595 \li Conversion to a compatible signature. Pass the signature as template argument to the
598 If the signature of the command added matches
600 void (std::ostream &, senf::console::ParsedCommandInfo const &)
602 The command is added using manual argument parsing, otherwise it is added using automatic
605 See the <a href="classsenf_1_1console_1_1factory_1_1Command-members.html">List of all
606 members</a> for additional attributes.
608 \note This class is for exposition only, the real interface consists of several overloaded
611 \see \ref console_manualparse \n
612 \ref console_autoparse
614 class Command : public ParsedArgumentAttributor
617 typedef OverloadedCommandNode node_type;
618 typedef unspecified result_type;
620 Command(unspecified fn); ///< Create a node calling \a fn
621 template <class Signature>
622 Command(unspecified fn); ///< Create a node calling \a fn with signature \a Signature
623 /**< The given \a Signature must be compatible with \a fn
624 for each argument and the return value. */
626 Command(member_function_pointer fn, Owner const * owner);
627 ///< Create a node calling member function \a fn on \a owner
628 template <class Signature>
629 Command(member_function_pointer fn, Owner const * owner);
630 ///< Create a node calling member function \a fn on \a owner
631 /// with the given \a Signature
632 /**< The given \a Signature must be compatible with \a fn
633 for each argument and the return value. */
639 template <class Signature>
640 SimpleOverloadAttributor
641 Command(boost::function<Signature> fn,
642 typename boost::enable_if_c<detail::ParsedCommandTraits<Signature>::is_simple>::type * = 0);
644 template <class Function>
645 SimpleOverloadAttributor
647 typename boost::enable_if_c<detail::ParsedCommandTraits<Function>::is_simple>::type * = 0);
649 template <class Owner, class Member>
650 SimpleOverloadAttributor
651 Command(Member memfn, Owner * owner,
652 typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0,
653 typename boost::enable_if_c<detail::ParsedCommandTraits<Member>::is_simple>::type * = 0);
655 template <class Owner, class Member>
656 SimpleOverloadAttributor
657 Command(Member memfn, Owner const * owner,
658 typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0,
659 typename boost::enable_if_c<detail::ParsedCommandTraits<Member>::is_simple>::type * = 0);
661 template <class CastTo, class Signature>
662 typename senf::console::detail::ParsedCommandTraits<CastTo>::Attributor
663 Command(boost::function<Signature> fn);
665 template <class CastTo, class Function>
666 typename senf::console::detail::ParsedCommandTraits<CastTo>::Attributor
668 typename boost::enable_if_c<detail::ParsedCommandTraits<Function>::is_callable>::type * = 0,
669 typename boost::disable_if<boost::is_member_function_pointer<Function> >::type * = 0);
671 template <class Signature>
672 typename senf::console::detail::ParsedCommandTraits<Signature>::Attributor
673 Command(boost::function<Signature> fn);
675 template <class Function>
676 typename senf::console::detail::ParsedCommandTraits<Function>::Attributor
678 typename boost::enable_if_c<detail::ParsedCommandTraits<Function>::is_callable>::type * = 0,
679 typename boost::disable_if<boost::is_member_function_pointer<Function> >::type * = 0);
681 template <class Owner, class Member>
682 typename senf::console::detail::ParsedCommandTraits<Member>::Attributor
683 Command(Member memfn, Owner * owner,
684 typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0);
686 template <class Owner, class Member>
687 typename senf::console::detail::ParsedCommandTraits<Member>::Attributor
688 Command(Member memfn, Owner const * owner,
689 typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0);
691 template <class CastTo, class Owner, class Member>
692 typename senf::console::detail::ParsedCommandTraits<CastTo>::Attributor
693 Command(Member memfn, Owner * owner,
694 typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0);
696 template <class CastTo, class Owner, class Member>
697 typename senf::console::detail::ParsedCommandTraits<CastTo>::Attributor
698 Command(Member memfn, Owner const * owner,
699 typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0);
705 ///////////////////////////////hh.e////////////////////////////////////////
706 #include "ParsedCommand.cci"
707 #include "ParsedCommand.ct"
708 #include "ParsedCommand.cti"
715 // comment-column: 40
716 // c-file-style: "senf"
717 // indent-tabs-mode: nil
718 // ispell-local-dictionary: "american"
719 // compile-command: "scons -u test"