Console: Overhaul documentation
[senf.git] / Console / ParsedCommand.hh
1 // $Id$
2 //
3 // Copyright (C) 2008 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
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.
12 //
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.
17 //
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.
22
23 /** \file
24     \brief ParsedCommand public header */
25
26 #ifndef HH_ParsedCommand_
27 #define HH_ParsedCommand_ 1
28
29 // Custom includes
30
31 #define BOOST_PARAMETER_MAX_ARITY 6
32
33 #include <vector>
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"
42 #include "Traits.hh"
43 #include "../Utils/type_traits.hh"
44
45 #include "ParsedCommand.ih"
46 #include "ParsedCommand.mpp"
47 ///////////////////////////////hh.p////////////////////////////////////////
48
49 namespace senf {
50 namespace console {
51
52     namespace detail { class ArgumentInfoBase; }
53
54     /** \brief CommandOverload implementation with automatic argument parsing
55
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.
59
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
64
65         \section overload_add Adding argument parsing callbacks to the tree
66
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().
69         \code
70         std::string taskStatus(int id);
71
72         senf::console::root().add("taskStatus", &taskStatus);
73         \endcode
74
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:
78
79         \code
80         senf::console::root().add("taskStatus", &taskStatus)
81             .doc("Query the current task status")
82             .arg( name = "id",
83                   description = "numeric id of task to check, -1 for the current task."
84                   default_value = -1 );
85         \endcode
86
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.
90
91         Additionally, overloading is supported by registering multiple commands under the same
92         name. So, elaborating on above example:
93         \code
94         std::string taskStatus(int id);
95         std::string taskStatus(std::string const & name);
96
97         senf::console::root()
98             .add("taskStatus", static_cast<std::string (*)(int)>(&taskStatus))
99             .doc("Query the current task status")
100             .overloadDoc("Query status by id")
101             .arg( name = "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")
107             .arg( name = "name",
108                   description = "name of task to check" );
109         \endcode
110
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.
114
115         \section overload_parse Custom parameter parsers
116         
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.
120
121         However, argument parsing can be configured by specializing
122         senf::console::ArgumentTraits. See that class for more information.
123
124         \section overload_format Custom return-value formatters
125
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.
130
131         \ingroup console_commands
132      */
133     class ParsedCommandOverloadBase
134         : public CommandOverload
135     {
136     public:
137         typedef boost::intrusive_ptr<ParsedCommandOverloadBase> ptr;
138
139         detail::ArgumentInfoBase & arg(unsigned n) const;
140         template <class Type> detail::ArgumentInfo<Type> & arg(unsigned n) const;
141
142         void doc(std::string const & d);
143
144     protected:
145         ParsedCommandOverloadBase();
146
147         template <class Type>
148         void addParameter();
149
150     private:
151         virtual unsigned v_numArguments() const;
152         virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const;
153         virtual std::string v_doc() const;
154
155         typedef std::vector<detail::ArgumentInfoBase::ptr> Parameters;
156         Parameters parameters_;
157         std::string doc_;
158     };
159
160     /** \brief Parsed command overload
161
162         ParsedCommandOverload provides the command overload added to an OverloadedCommandNode for an
163         automatically parsed command.
164
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.
169
170         \implementation This class is specialized for each supported number of command arguments.
171      */
172     template <class FunctionTraits, unsigned arity=FunctionTraits::arity>
173     class ParsedCommandOverload : public ParsedCommandOverloadBase
174     {
175     public:
176         typedef boost::intrusive_ptr<ParsedCommandOverload> ptr;
177
178 #ifdef DOXYGEN
179         static ptr create(Function fn);
180 #endif
181     };
182
183 #ifndef DOXYGEN
184
185 #   define BOOST_PP_ITERATION_PARAMS_1 (4, (0, SENF_CONSOLE_MAX_COMMAND_ARITY,                     \
186                                             SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), \
187                                             1))
188 #   include BOOST_PP_ITERATE()
189
190 #endif
191
192     /** \brief Generic ParsedCommandOverladBase attributes
193
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.
196         
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.
199
200         \see \ref console_autoparse
201      */
202     class ParsedCommandAttributorBase
203     {
204     public:
205         OverloadedCommandNode & node() const; ///< Return the node object
206         operator OverloadedCommandNode & () const; ///< Automatically convert to node object
207
208     protected:
209         ParsedCommandAttributorBase(ParsedCommandOverloadBase & overload, unsigned index);
210
211         void argName(std::string const & name) const;
212         void argDoc(std::string const & doc) const;
213         template <class Type> void defaultValue(Type const & value) const;
214         void typeName(std::string const & doc) const;
215         void defaultDoc(std::string const & doc) const;
216         template <class Type, class Fn> void parser(Fn fn) const;
217
218         ParsedCommandOverloadBase & overload() const;
219         void overloadDoc(std::string const & doc) const;
220
221         void nodeDoc(std::string const & doc) const;
222         
223     private:
224         ParsedCommandOverloadBase & overload_;
225         unsigned index_;
226     };
227
228     /** \brief Non argument dependent ParsedCommandBase attributes 
229         
230         Attributes for parsed commands are not set directly on the node. They are set via a special
231         attributor temporary returned when adding a parsed command to the tree.
232
233         This class adds all those members, which do depend on the type of command added (and thereby
234         on that commands signature) but do not depend on the type of any single argument.
235
236         \see \ref console_autoparse
237      */
238     template <class Overload>
239     class ParsedCommandAttributor
240         : public ParsedCommandAttributorBase
241     {
242     public:
243         Overload & overload() const;    ///< Get the command overload
244
245     protected:
246         ParsedCommandAttributor(Overload & overload, unsigned index);
247
248     private:
249     };
250
251     /** \brief Keyword argument tags
252
253         The tags defined in this namespace are used as keyword arguments via the <a
254         href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
255         library.
256
257         For the keyword tags, the standard C++ scoping rules apply
258         \code
259         // Either qualify them with their complete namespace
260         dir.add(...)
261             .arg( senf::console::kw::name = "name" );
262         
263         // Or use a namespace alias
264         namespace kw = senf::console::kw;
265         dir.add(...)
266             .arg( kw::name = "name" );
267
268         // Or import the keywords into the current namespace (beware of name collisions)
269         using namespace senf::console::kw;
270         dir.add(...)
271             .arg( name = "name" );
272         \endcode
273
274         The second alternative is preferred, the <tt>using namespace</tt> directive may be used as
275         long as the keyword names do not clash with another visible symbol.
276
277         \section kw_attributes Argument attribute values
278
279         The keywords are used to set argument attributes.  The keywords \ref default_value and \ref
280         parser influence, how an argument is parsed/interpreted whereas \ref name, \ref description,
281         \ref type_name and \ref default_doc are used to change the arguments documentation:
282         \code
283         void command(int);
284
285         dir.add("command", &command)
286             .arg( kw::name          = "name",
287                   kw::description   = "description",
288                   kw::default_value = 1,
289                   kw::type_name     = "type_name",
290                   kw::default_doc   = "default_doc" );
291         \endcode
292         Will create the following documentation:
293         \htmlonly
294         <pre>
295         Usage:
296             command [name:type_name]
297         
298         With:
299             name      description
300                 default: default_doc
301         </pre>
302         \endhtmlonly
303
304         \see \ref senf::console::ParsedArgumentAttributor::arg()
305      */
306     namespace kw {
307         BOOST_PARAMETER_KEYWORD(type, name) ///< Argument name
308                                         /**< Sets the displayed name of the argument. */
309         BOOST_PARAMETER_KEYWORD(type, description) ///< One-line argument description
310                                         /**< This description is shown in the argument
311                                              reference. If several overloads have same-named
312                                              arguments, only one of them should be documented. This
313                                              documentation then applies to all arguments of that
314                                              name. */
315         BOOST_PARAMETER_KEYWORD(type, default_value) ///< Argument default value
316                                         /**< If a default value is specified for an argument, that
317                                              argument is optional. If an overload is called with
318                                              fewer arguments than defined, optional values will be
319                                              used beginning at the last optional argument and going
320                                              forward until all arguments have values assigned. E.g.,
321                                              an overload with 5 parameters \a a - \a e with two
322                                              defaults attached:
323                                              <pre>
324                                              command a:int [b:int] c:int [d:int] e:int
325                                              </pre>
326                                              When calling the overload, the arguments will be
327                                              assigned in the following way:
328                                              <table class="senf fixedwidth">
329                                              <tr>
330                                                <td><tt>command 1 2</tt></td>
331                                                <td>SyntaxErrorException: invalid number of
332                                                  arguments</td>
333                                              </tr>
334                                              <tr>
335                                                <td><tt>command 1 2 3</tt></td>
336                                                <td>\a a = 1, \n
337                                                    \a b = \e default, \n
338                                                    \a c = 2, \n
339                                                    \a d = \e default, \n
340                                                    \a e = 3</td>
341                                              </tr>
342                                              <tr>
343                                                <td><tt>command 1 2 3 4</tt></td>
344                                                <td>\a a = 1, \n
345                                                    \a b = 2, \n
346                                                    \a c = 3, \n
347                                                    \a d = \e default, \n
348                                                    \a e = 4</td>
349                                              </tr>
350                                              <tr>
351                                                <td><tt>command 1 2 3 4 5</tt></td>
352                                                <td>\a a = 1, \n
353                                                    \a b = 2, \n
354                                                    \a c = 3, \n
355                                                    \a d = 4, \n
356                                                    \a e = 5</td>
357                                              </tr>
358                                              <tr>
359                                                <td><tt>command 1 2 3 4 5 6</tt></td>
360                                                <td>SyntaxErrorException: invalid number of
361                                                  arguments</td>
362                                              </tr>
363                                              </table>
364                                              So, if you assign default values as you are used to
365                                              they will work like in C++ and most other languages */
366         BOOST_PARAMETER_KEYWORD(type, type_name) ///< Type name of this arguments type
367                                         /**< By default, the type of an argument is extracted from
368                                              the C++ type name by taking the last component of the
369                                              fully scoped name. This value can be changed by setting
370                                              this attribute. */
371         BOOST_PARAMETER_KEYWORD(type, default_doc) ///< String rep of default value
372                                         /**< By default, the default value is documented by
373                                              converting the value to it's string representation
374                                              using \c boost::lexical_cast / \c iostreams. The
375                                              displayed value can be changed by setting this
376                                              attribute. */
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
382                                              class. 
383
384                                              Setting the \a parser attribute allows to use a custom
385                                              parser. The parser is an arbitrary callable object with
386                                              the signature
387                                              \code
388                                              void parser(senf::console::ParseCommandInfo::TokensRange const & tokens, value_type & out);
389                                              \endcode
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. */
395     }
396
397     /** \brief Derived class dependent ParsedCommandBase attributes
398
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.
401         
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.
404
405         \see \ref console_autoparse
406      */
407     template <class Overload, class Self>
408     class ParsedArgumentAttributorBase
409         : public ParsedCommandAttributor<Overload>
410     {
411     public:
412         Self doc(std::string const & doc) const; ///< Set documentation for all overloads
413         Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation
414
415     protected:
416         ParsedArgumentAttributorBase(Overload & overload, unsigned index);
417
418     private:
419     };
420
421     
422     /** \brief Argument dependent ParsedCommandBase attributes
423
424         Attributes for parsed commands are not set directly on the node. They are set via a special
425         attributor temporary returned when adding a parsed command to the tree.
426         
427         This class adds all those members, which depend on a specific argument. Each call to \c arg
428         will advance to the next argument.
429
430         \see \ref console_autoparse
431      */
432     template < class Overload, 
433                unsigned index=0, 
434                bool flag=(index < unsigned(Overload::traits::arity)) >
435     class ParsedArgumentAttributor
436         : public ParsedArgumentAttributorBase< Overload, 
437                                                 ParsedArgumentAttributor<Overload, index, flag> >
438     {
439         typedef boost::parameter::parameters<
440             kw::type::name,
441             kw::type::description,
442             kw::type::default_value,
443             kw::type::type_name,
444             kw::type::default_doc,
445             kw::type::parser> arg_params;
446
447     public:
448         typedef OverloadedCommandNode node_type;
449         typedef ParsedArgumentAttributor return_type;
450
451         typedef typename senf::function_traits_arg_type< 
452             typename Overload::traits, int(index) >::type arg_type;
453         typedef typename senf::remove_cvref< arg_type >::type value_type;
454         typedef ParsedArgumentAttributor<Overload, index+1> next_type;
455
456         next_type arg() const;          ///< Set argument attributes
457                                         /**< This member changes the attributes for the current
458                                              argument. The attributes are passed to arg() as keyword
459                                              arguments using the <a
460                                              href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
461                                              library. 
462                                              \code
463                                              ...
464                                                  .arg( kw::name          = "name", 
465                                                        kw::default_value = 1 )
466                                              ...
467                                              \endcode
468                                              The valid keywords are defined in the senf::console::kw
469                                              namespace.
470                                              
471                                              Each call to arg() will increment the argument index
472                                              and advance to the next argument. This member is only
473                                              present, if there is an argument at the current. */
474
475 #ifndef DOXYVEN
476
477 #       define BOOST_PP_ITERATION_PARAMS_1                                                        \
478             (4, (1, BOOST_PARAMETER_MAX_ARITY,                                                    \
479                  SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp),                           \
480                  5))
481 #       include BOOST_PP_ITERATE()
482
483 #endif
484
485     private:
486         explicit ParsedArgumentAttributor(Overload & overload);
487
488         template <class ArgumentPack>
489         next_type argInfo(ArgumentPack const & args) const;
490         template <class Kw, class ArgumentPack>
491         void argInfo(Kw const &, ArgumentPack const &, boost::mpl::false_) 
492             const;
493
494         template <class ArgumentPack>
495         void argInfo(boost::parameter::keyword<kw::type::name> const &, 
496                      ArgumentPack const & args, boost::mpl::true_) 
497             const;
498         template <class ArgumentPack>
499         void argInfo(boost::parameter::keyword<kw::type::description> const &, 
500                      ArgumentPack const & args, boost::mpl::true_) 
501             const;
502         template <class ArgumentPack>
503         void argInfo(boost::parameter::keyword<kw::type::default_value> const &, 
504                      ArgumentPack const & args, boost::mpl::true_) 
505             const;
506         template <class ArgumentPack>
507         void argInfo(boost::parameter::keyword<kw::type::type_name> const &, 
508                      ArgumentPack const & args, boost::mpl::true_) 
509             const;
510         template <class ArgumentPack>
511         void argInfo(boost::parameter::keyword<kw::type::default_doc> const &, 
512                      ArgumentPack const & args, boost::mpl::true_) 
513             const;
514         template <class ArgumentPack>
515         void argInfo(boost::parameter::keyword<kw::type::parser> const &, 
516                      ArgumentPack const & args, boost::mpl::true_) 
517             const;
518
519         next_type next() const;
520
521         void defaultValue(value_type const & value) const;
522         template <class Fn> void parser(Fn fn) const;
523
524         template <class O, unsigned i, bool f>
525         friend class ParsedArgumentAttributor;
526
527 #ifndef DOXYGEN
528         
529         template <class Function>
530         friend ParsedArgumentAttributor<
531             ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
532         senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
533         
534         template <class Owner, class Function>
535         friend ParsedArgumentAttributor<
536             ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
537         senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
538                               Function fn, int,
539                               typename boost::enable_if_c<
540                                   detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
541
542 #endif
543     };
544
545 #ifndef DOXYGEN
546
547     template <class Overload, unsigned index>
548     class ParsedArgumentAttributor<Overload, index, false>
549         : public ParsedArgumentAttributorBase< Overload, 
550                                                 ParsedArgumentAttributor<Overload, index, false> >
551     {
552     public:
553         typedef OverloadedCommandNode node_type;
554         typedef ParsedArgumentAttributor return_type;
555
556     private:
557         explicit ParsedArgumentAttributor(Overload & overload);
558
559         template <class O, unsigned i, bool f>
560         friend class ParsedArgumentAttributor;
561         
562         template <class Function>
563         friend ParsedArgumentAttributor<
564             ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
565         senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
566         
567         template <class Owner, class Function>
568         friend ParsedArgumentAttributor<
569             ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
570         senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
571                               Function fn, int,
572                               typename boost::enable_if_c<
573                                   detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
574     };
575
576     template <class Function>
577     ParsedArgumentAttributor<
578         ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
579     senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
580
581     template <class Owner, class Function>
582     ParsedArgumentAttributor<
583         ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
584     senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
585                           Function fn, int,
586                           typename boost::enable_if_c<
587                               detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
588
589 #endif
590
591 }}
592
593 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
594
595 BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedCommandOverload, (class,unsigned))
596 BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedArgumentAttributor, (class, unsigned, bool))
597 BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function_traits, 1)
598
599 ///////////////////////////////hh.e////////////////////////////////////////
600 #include "ParsedCommand.cci"
601 #include "ParsedCommand.ct"
602 #include "ParsedCommand.cti"
603 #endif
604
605 \f
606 // Local Variables:
607 // mode: c++
608 // fill-column: 100
609 // comment-column: 40
610 // c-file-style: "senf"
611 // indent-tabs-mode: nil
612 // ispell-local-dictionary: "american"
613 // compile-command: "scons -u test"
614 // End: