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_ParsedCommand_
27 #define HH_ParsedCommand_ 1
31 #define BOOST_PARAMETER_MAX_ARITY 6
34 #include <boost/type_traits/function_traits.hpp>
35 #include <boost/type_traits/is_member_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 "../config.hh"
41 #include "OverloadedCommand.hh"
43 #include "../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 Adding appropriate callbacks to the tree is very simple: just path a function pointer to
68 DirectoryNode::add() or a member function pointer to ScopedDirectory::add().
70 std::string taskStatus(int id);
72 senf::console::root().add("taskStatus", &taskStatus);
75 There are quite a number of additional parameters available to be set. These parameters are
76 documented in ParsedArgumentAttributor. Parameters are set by adding them as additional
77 calls after adding the node:
80 senf::console::root().add("taskStatus", &taskStatus)
81 .doc("Query the current task status")
83 description = "numeric id of task to check, -1 for the current task."
87 You may also add an additional \c std::ostream & Argument as first argument to the
88 callback. If this argument is present, the stream connected to the console which issued the
89 command will be passed there. This allows writing arbitrary messages to the console.
91 Additionally, overloading is supported by registering multiple commands under the same
92 name. So, elaborating on above example:
94 std::string taskStatus(int id);
95 std::string taskStatus(std::string const & name);
98 .add("taskStatus", static_cast<std::string (*)(int)>(&taskStatus))
99 .doc("Query the current task status")
100 .overloadDoc("Query status by id")
102 description = "numeric id of task to check, -1 for the current task."
103 default_value = -1 );
104 senf::console::root()
105 .add("taskStatus", static_cast<std::string (*)(std::string const &)>(&taskStatus))
106 .overloadDoc("Query status by name")
108 description = "name of task to check" );
111 We can see here, that taking the address of an overloaded function requires a cast. If you
112 can give unique names to each of the C++ overloads (not the overloads in the console), you
113 should do so to make the unwieldy casts unnecessary.
115 \section overload_parse Custom parameter parsers
117 By default, parameters are parsed using \c boost::lexical_cast and therefore using \c
118 iostreams. This means, that any type which can be read from a stream can automatically be
119 used as argument type.
121 However, argument parsing can be configured by specializing
122 senf::console::ArgumentTraits. See that class for more information.
124 \section overload_format Custom return-value formatters
126 By default, return values are streamed to an ostream. This automatically allows any
127 streamable type to be used as return value. To add new types or customize the formating, the
128 senf::console::ReturnValueTraits template needs to be specialized for that type. See
129 that class for more information.
131 \ingroup console_commands
133 class ParsedCommandOverloadBase
134 : public CommandOverload
137 typedef boost::intrusive_ptr<ParsedCommandOverloadBase> ptr;
139 detail::ArgumentInfoBase & arg(unsigned n) const;
140 template <class Type> detail::ArgumentInfo<Type> & arg(unsigned n) const;
142 void doc(std::string const & d);
145 ParsedCommandOverloadBase();
147 template <class Type>
151 virtual unsigned v_numArguments() const;
152 virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const;
153 virtual std::string v_doc() const;
155 typedef std::vector<detail::ArgumentInfoBase::ptr> Parameters;
156 Parameters parameters_;
160 /** \brief Parsed command overload
162 ParsedCommandOverload provides the command overload added to an OverloadedCommandNode for an
163 automatically parsed command.
165 This class is normally instantiated automatically when adding a function or member-function
166 pointer as callback to the tree. Manually instantiation this type of overload is \e not
167 simple, since the function signature has to be manipulated correctly to support the optional
168 \c std::ostream first argument.
170 \implementation This class is specialized for each supported number of command arguments.
172 \todo Implement automatic binding of member functions for parser and formatter
174 template <class FunctionTraits, class ReturnType=typename FunctionTraits::result_type,
175 unsigned arity=FunctionTraits::arity>
176 class ParsedCommandOverload : public ParsedCommandOverloadBase
179 typedef boost::intrusive_ptr<ParsedCommandOverload> ptr;
182 static ptr create(Function fn);
188 # define BOOST_PP_ITERATION_PARAMS_1 (4, (0, SENF_CONSOLE_MAX_COMMAND_ARITY, \
189 SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), \
191 # include BOOST_PP_ITERATE()
195 /** \brief Generic ParsedCommandOverladBase attributes
197 Attributes for parsed commands are not set directly on the node. They are set via a special
198 attributor temporary returned when adding a parsed command to the tree.
200 This class is the base class for those attributors. It provides members which do not depend
201 in any way on the exact type of command added.
203 \see \ref console_autoparse
205 class ParsedCommandAttributorBase
208 OverloadedCommandNode & node() const; ///< Return the node object
209 operator OverloadedCommandNode & () const; ///< Automatically convert to node object
212 ParsedCommandAttributorBase(ParsedCommandOverloadBase & overload, unsigned index);
214 void argName(std::string const & name) const;
215 void argDoc(std::string const & doc) const;
216 template <class Type> void defaultValue(Type const & value) const;
217 void typeName(std::string const & doc) const;
218 void defaultDoc(std::string const & doc) const;
220 ParsedCommandOverloadBase & overload() const;
221 void overloadDoc(std::string const & doc) const;
222 void nodeDoc(std::string const & doc) const;
223 template <class Type, class Fn> void parser(Fn fn) const;
226 ParsedCommandOverloadBase & overload_;
230 /** \brief Non argument dependent ParsedCommandBase attributes
232 Attributes for parsed commands are not set directly on the node. They are set via a special
233 attributor temporary returned when adding a parsed command to the tree.
235 This class adds all those members, which do depend on the type of command added (and thereby
236 on that commands signature) but do not depend on the type of any single argument.
238 \see \ref console_autoparse
240 template <class Overload>
241 class ParsedCommandAttributor
242 : public ParsedCommandAttributorBase
245 Overload & overload() const; ///< Get the command overload
248 ParsedCommandAttributor(Overload & overload, unsigned index);
253 /** \brief Keyword argument tags
255 The tags defined in this namespace are used as keyword arguments via the <a
256 href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
259 For the keyword tags, the standard C++ scoping rules apply
261 // Either qualify them with their complete namespace
263 .arg( senf::console::kw::name = "name" );
265 // Or use a namespace alias
266 namespace kw = senf::console::kw;
268 .arg( kw::name = "name" );
270 // Or import the keywords into the current namespace (beware of name collisions)
271 using namespace senf::console::kw;
273 .arg( name = "name" );
276 The second alternative is preferred, the <tt>using namespace</tt> directive may be used as
277 long as the keyword names do not clash with another visible symbol.
279 \section kw_attributes Argument attribute values
281 The keywords are used to set argument attributes. The keywords \ref default_value and \ref
282 parser influence, how an argument is parsed/interpreted whereas \ref name, \ref description,
283 \ref type_name and \ref default_doc are used to change the arguments documentation:
287 dir.add("command", &command)
288 .arg( kw::name = "name",
289 kw::description = "description",
290 kw::default_value = 1,
291 kw::type_name = "type_name",
292 kw::default_doc = "default_doc" );
294 Will create the following documentation:
298 command [name:type_name]
306 \see \ref senf::console::ParsedArgumentAttributor::arg()
309 BOOST_PARAMETER_KEYWORD(type, name) ///< Argument name
310 /**< Sets the displayed name of the argument. */
311 BOOST_PARAMETER_KEYWORD(type, description) ///< One-line argument description
312 /**< This description is shown in the argument
313 reference. If several overloads have same-named
314 arguments, only one of them should be documented. This
315 documentation then applies to all arguments of that
317 BOOST_PARAMETER_KEYWORD(type, default_value) ///< Argument default value
318 /**< If a default value is specified for an argument, that
319 argument is optional. If an overload is called with
320 fewer arguments than defined, optional values will be
321 used beginning at the last optional argument and going
322 forward until all arguments have values assigned. E.g.,
323 an overload with 5 parameters \a a - \a e with two
326 command a:int [b:int] c:int [d:int] e:int
328 When calling the overload, the arguments will be
329 assigned in the following way:
330 <table class="senf fixedwidth">
332 <td><tt>command 1 2</tt></td>
333 <td>SyntaxErrorException: invalid number of
337 <td><tt>command 1 2 3</tt></td>
339 \a b = \e default, \n
341 \a d = \e default, \n
345 <td><tt>command 1 2 3 4</tt></td>
349 \a d = \e default, \n
353 <td><tt>command 1 2 3 4 5</tt></td>
361 <td><tt>command 1 2 3 4 5 6</tt></td>
362 <td>SyntaxErrorException: invalid number of
366 So, if you assign default values as you are used to
367 they will work like in C++ and most other languages */
368 BOOST_PARAMETER_KEYWORD(type, type_name) ///< Type name of this arguments type
369 /**< By default, the type of an argument is extracted from
370 the C++ type name by taking the last component of the
371 fully scoped name. This value can be changed by setting
373 BOOST_PARAMETER_KEYWORD(type, default_doc) ///< String rep of default value
374 /**< By default, the default value is documented by
375 converting the value to it's string representation
376 using \c boost::lexical_cast / \c iostreams. The
377 displayed value can be changed by setting this
379 BOOST_PARAMETER_KEYWORD(type, parser) ///< Argument parser
380 /**< The argument parser is used to convert the argument
381 token list returned by the console/config parser into
382 the appropriate value. If not set explicitly, this
383 conversion is supplied by the ArgumentTraits
386 Setting the \a parser attribute allows to use a custom
387 parser. The parser is an arbitrary callable object with
390 void parser(senf::console::ParseCommandInfo::TokensRange const & tokens, value_type & out);
392 where \c value_type is the type of the overload
393 parameter. The parser must read and parse the complete
394 \a tokens range and return the parsed value in \a
395 out. If the parser fails, it must raise a
396 senf::console::SyntaxErrorException. */
399 /** \brief Derived class dependent ParsedCommandBase attributes
401 Attributes for parsed commands are not set directly on the node. They are set via a special
402 attributor temporary returned when adding a parsed command to the tree.
404 This class adds all those members, which do not depend on any specific argument but which
405 need to return the correct attributor type.
407 \see \ref console_autoparse
409 template <class Overload, class Self, class ReturnType=typename Overload::traits::result_type>
410 class ParsedArgumentAttributorBase
411 : public ParsedCommandAttributor<Overload>
414 Self doc(std::string const & doc) const; ///< Set documentation for all overloads
415 Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation
416 Self formatter(typename Overload::Formatter f) const; ///< Set return value formatter
419 ParsedArgumentAttributorBase(Overload & overload, unsigned index);
426 template <class Overload, class Self>
427 class ParsedArgumentAttributorBase<Overload, Self, void>
428 : public ParsedCommandAttributor<Overload>
431 Self doc(std::string const & doc) const; ///< Set documentation for all overloads
432 Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation
435 ParsedArgumentAttributorBase(Overload & overload, unsigned index);
442 /** \brief Argument dependent ParsedCommandBase attributes
444 Attributes for parsed commands are not set directly on the node. They are set via a special
445 attributor temporary returned when adding a parsed command to the tree.
447 This class adds all those members, which depend on a specific argument. Each call to \c arg
448 will advance to the next argument.
450 \see \ref console_autoparse
452 template < class Overload,
454 bool flag=(index < unsigned(Overload::traits::arity)) >
455 class ParsedArgumentAttributor
456 : public ParsedArgumentAttributorBase< Overload,
457 ParsedArgumentAttributor<Overload, index, flag> >
459 typedef boost::parameter::parameters<
461 kw::type::description,
462 kw::type::default_value,
464 kw::type::default_doc,
465 kw::type::parser> arg_params;
468 typedef OverloadedCommandNode node_type;
469 typedef ParsedArgumentAttributor return_type;
471 typedef typename senf::function_traits_arg_type<
472 typename Overload::traits, int(index) >::type arg_type;
473 typedef typename senf::remove_cvref< arg_type >::type value_type;
474 typedef ParsedArgumentAttributor<Overload, index+1> next_type;
476 next_type arg() const; ///< Set argument attributes
477 /**< This member changes the attributes for the current
478 argument. The attributes are passed to arg() as keyword
479 arguments using the <a
480 href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
484 .arg( kw::name = "name",
485 kw::default_value = 1 )
488 The valid keywords are defined in the senf::console::kw
491 Each call to arg() will increment the argument index
492 and advance to the next argument. This member is only
493 present, if there is an argument at the current. */
497 # define BOOST_PP_ITERATION_PARAMS_1 \
498 (4, (1, BOOST_PARAMETER_MAX_ARITY, \
499 SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), \
501 # include BOOST_PP_ITERATE()
506 explicit ParsedArgumentAttributor(Overload & overload);
508 template <class ArgumentPack>
509 next_type argInfo(ArgumentPack const & args) const;
510 template <class Kw, class ArgumentPack>
511 void argInfo(Kw const &, ArgumentPack const &, boost::mpl::false_)
514 template <class ArgumentPack>
515 void argInfo(boost::parameter::keyword<kw::type::name> const &,
516 ArgumentPack const & args, boost::mpl::true_)
518 template <class ArgumentPack>
519 void argInfo(boost::parameter::keyword<kw::type::description> const &,
520 ArgumentPack const & args, boost::mpl::true_)
522 template <class ArgumentPack>
523 void argInfo(boost::parameter::keyword<kw::type::default_value> const &,
524 ArgumentPack const & args, boost::mpl::true_)
526 template <class ArgumentPack>
527 void argInfo(boost::parameter::keyword<kw::type::type_name> const &,
528 ArgumentPack const & args, boost::mpl::true_)
530 template <class ArgumentPack>
531 void argInfo(boost::parameter::keyword<kw::type::default_doc> const &,
532 ArgumentPack const & args, boost::mpl::true_)
534 template <class ArgumentPack>
535 void argInfo(boost::parameter::keyword<kw::type::parser> const &,
536 ArgumentPack const & args, boost::mpl::true_)
539 next_type next() const;
541 void defaultValue(value_type const & value) const;
542 template <class Fn> void parser(Fn fn) const;
544 template <class O, unsigned i, bool f>
545 friend class ParsedArgumentAttributor;
549 template <class Function>
550 friend ParsedArgumentAttributor<
551 ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
552 senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
554 template <class Owner, class Function>
555 friend ParsedArgumentAttributor<
556 ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
557 senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
559 typename boost::enable_if_c<
560 detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
567 template <class Overload, unsigned index>
568 class ParsedArgumentAttributor<Overload, index, false>
569 : public ParsedArgumentAttributorBase< Overload,
570 ParsedArgumentAttributor<Overload, index, false> >
573 typedef OverloadedCommandNode node_type;
574 typedef ParsedArgumentAttributor return_type;
577 explicit ParsedArgumentAttributor(Overload & overload);
579 template <class O, unsigned i, bool f>
580 friend class ParsedArgumentAttributor;
582 template <class Function>
583 friend ParsedArgumentAttributor<
584 ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
585 senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
587 template <class Owner, class Function>
588 friend ParsedArgumentAttributor<
589 ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
590 senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
592 typename boost::enable_if_c<
593 detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
596 template <class Function>
597 ParsedArgumentAttributor<
598 ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
599 senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
601 template <class Owner, class Function>
602 ParsedArgumentAttributor<
603 ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
604 senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
606 typename boost::enable_if_c<
607 detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
613 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
615 BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedCommandOverload, (class,unsigned))
616 BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedArgumentAttributor, (class, unsigned, bool))
617 BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function_traits, 1)
619 ///////////////////////////////hh.e////////////////////////////////////////
620 #include "ParsedCommand.cci"
621 #include "ParsedCommand.ct"
622 #include "ParsedCommand.cti"
629 // comment-column: 40
630 // c-file-style: "senf"
631 // indent-tabs-mode: nil
632 // ispell-local-dictionary: "american"
633 // compile-command: "scons -u test"