replaced some tabs with spaces
[senf.git] / Scheduler / 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_SENF_Scheduler_Console_ParsedCommand_
27 #define HH_SENF_Scheduler_Console_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
141         void doc(std::string const & d);
142
143     protected:
144         ParsedCommandOverloadBase();
145
146         template <class Type> void addParameter();
147
148     private:
149         virtual unsigned v_numArguments() const;
150         virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const;
151         virtual std::string v_doc() const;
152
153         typedef std::vector<detail::ArgumentInfoBase::ptr> Parameters;
154         Parameters parameters_;
155         std::string doc_;
156     };
157
158     /** \brief Parsed command overload
159
160         ParsedCommandOverload provides the command overload added to an OverloadedCommandNode for an
161         automatically parsed command.
162
163         This class is normally instantiated automatically when adding a function or member-function
164         pointer as callback to the tree. Manually instantiation this type of overload is \e not
165         simple, since the function signature has to be manipulated correctly to support the optional
166         \c std::ostream first argument.
167
168         \implementation This class is specialized for each supported number of command arguments.
169
170         \todo Implement automatic binding of member functions for parser and formatter
171      */
172     template <class FunctionTraits, class ReturnType, unsigned 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(Scheduler/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         void typeName(std::string const & doc) const;
214         void defaultDoc(std::string const & doc) const;
215
216         ParsedCommandOverloadBase & overload() const;
217         void overloadDoc(std::string const & doc) const;
218         void nodeDoc(std::string const & doc) const;
219         
220     private:
221         ParsedCommandOverloadBase & overload_;
222         unsigned index_;
223     };
224
225     /** \brief Non argument dependent ParsedCommandBase attributes 
226         
227         Attributes for parsed commands are not set directly on the node. They are set via a special
228         attributor temporary returned when adding a parsed command to the tree.
229
230         This class adds all those members, which do depend on the type of command added (and thereby
231         on that commands signature) but do not depend on the type of any single argument.
232
233         \see \ref console_autoparse
234      */
235     template <class Overload>
236     class ParsedCommandAttributor
237         : public ParsedCommandAttributorBase
238     {
239     public:
240         Overload & overload() const;    ///< Get the command overload
241
242     protected:
243         ParsedCommandAttributor(Overload & overload, unsigned index);
244
245     private:
246     };
247
248     /** \brief Keyword argument tags
249
250         The tags defined in this namespace are used as keyword arguments via the <a
251         href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
252         library.
253
254         For the keyword tags, the standard C++ scoping rules apply
255         \code
256         // Either qualify them with their complete namespace
257         dir.add(...)
258             .arg( senf::console::kw::name = "name" );
259         
260         // Or use a namespace alias
261         namespace kw = senf::console::kw;
262         dir.add(...)
263             .arg( kw::name = "name" );
264
265         // Or import the keywords into the current namespace (beware of name collisions)
266         using namespace senf::console::kw;
267         dir.add(...)
268             .arg( name = "name" );
269         \endcode
270
271         The second alternative is preferred, the <tt>using namespace</tt> directive may be used as
272         long as the keyword names do not clash with another visible symbol.
273
274         \section kw_attributes Argument attribute values
275
276         The keywords are used to set argument attributes.  The keywords \ref default_value and \ref
277         parser influence, how an argument is parsed/interpreted whereas \ref name, \ref description,
278         \ref type_name and \ref default_doc are used to change the arguments documentation:
279         \code
280         void command(int);
281
282         dir.add("command", &command)
283             .arg( kw::name          = "name",
284                   kw::description   = "description",
285                   kw::default_value = 1,
286                   kw::type_name     = "type_name",
287                   kw::default_doc   = "default_doc" );
288         \endcode
289         Will create the following documentation:
290         \htmlonly
291         <pre>
292         Usage:
293             command [name:type_name]
294         
295         With:
296             name      description
297                 default: default_doc
298         </pre>
299         \endhtmlonly
300
301         \see \ref senf::console::ParsedArgumentAttributor::arg()
302      */
303     namespace kw {
304         BOOST_PARAMETER_KEYWORD(type, name) ///< Argument name
305                                         /**< Sets the displayed name of the argument. */
306         BOOST_PARAMETER_KEYWORD(type, description) ///< One-line argument description
307                                         /**< This description is shown in the argument
308                                              reference. If several overloads have same-named
309                                              arguments, only one of them should be documented. This
310                                              documentation then applies to all arguments of that
311                                              name. */
312         BOOST_PARAMETER_KEYWORD(type, default_value) ///< Argument default value
313                                         /**< If a default value is specified for an argument, that
314                                              argument is optional. If an overload is called with
315                                              fewer arguments than defined, optional values will be
316                                              used beginning at the last optional argument and going
317                                              forward until all arguments have values assigned. E.g.,
318                                              an overload with 5 parameters \a a - \a e with two
319                                              defaults attached:
320                                              <pre>
321                                              command a:int [b:int] c:int [d:int] e:int
322                                              </pre>
323                                              When calling the overload, the arguments will be
324                                              assigned in the following way:
325                                              <table class="senf fixedwidth">
326                                              <tr>
327                                                <td style="whitespace:no-wrap"><tt>command 1 2</tt></td>
328                                                <td colspan="5">SyntaxErrorException: invalid number of
329                                                  arguments</td>
330                                              </tr>
331                                              <tr>
332                                                <td style="white-space:nowrap"><tt>command 1 2 3</tt></td>
333                                                <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>
334                                              </tr>
335                                              <tr>
336                                                <td style="white-space:nowrap"><tt>command 1 2 3 4</tt></td>
337                                                <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>
338                                              </tr>
339                                              <tr>
340                                                <td style="white-space:nowrap"><tt>command 1 2 3 4 5</tt></td>
341                                                <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>
342                                              </tr>
343                                              <tr>
344                                                <td style="white-space:nowrap"><tt>command 1 2 3 4 5 6</tt></td>
345                                                <td colspan="5">SyntaxErrorException: invalid number of
346                                                  arguments</td>
347                                              </tr>
348                                              </table>
349                                              So, if you use default values as you are used to,
350                                              assigning default values to consecutive trailing
351                                              arguments, they work like they do in C++ and most other
352                                              languages */
353         BOOST_PARAMETER_KEYWORD(type, type_name) ///< Type name of this arguments type
354                                         /**< By default, the type of an argument is extracted from
355                                              the C++ type name by taking the last component of the
356                                              fully scoped name. This value can be changed by setting
357                                              this attribute. */
358         BOOST_PARAMETER_KEYWORD(type, default_doc) ///< String rep of default value
359                                         /**< By default, the default value is documented by
360                                              converting the value to it's string representation
361                                              using the corresponding return value formatter which by
362                                              default uses \c boost::lexical_cast / \c iostreams. The
363                                              displayed value can be changed by setting this
364                                              attribute. */
365         BOOST_PARAMETER_KEYWORD(type, parser) ///< Argument parser
366                                         /**< The argument parser is used to convert the argument
367                                              token list returned by the console/config parser into
368                                              the appropriate value. If not set explicitly, this
369                                              conversion is supplied by the ArgumentTraits
370                                              class. 
371
372                                              Setting the \a parser attribute allows to use a custom
373                                              parser. The parser is an arbitrary callable object with
374                                              the signature
375                                              \code
376                                              void parser(senf::console::ParseCommandInfo::TokensRange const & tokens, value_type & out);
377                                              \endcode
378                                              where \c value_type is the type of the overload
379                                              parameter. The parser must read and parse the complete
380                                              \a tokens range and return the parsed value in \a
381                                              out. If the parser fails, it must raise a
382                                              senf::console::SyntaxErrorException. */
383     }
384
385     /** \brief Derived class dependent ParsedCommandBase attributes
386
387         Attributes for parsed commands are not set directly on the node. They are set via a special
388         attributor temporary returned when adding a parsed command to the tree.
389         
390         This class adds all those members, which do not depend on any specific argument but which
391         need to return the correct attributor type.
392
393         \see \ref console_autoparse
394      */
395     template <class Overload, class Self, class ReturnType=typename Overload::traits::result_type>
396     class ParsedArgumentAttributorBase
397         : public ParsedCommandAttributor<Overload>
398     {
399     public:
400         Self doc(std::string const & doc) const; ///< Set documentation for all overloads
401         Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation
402         Self formatter(typename Overload::Formatter formatter) const; 
403                                         ///< Set return value formatter
404                                         /**< This member is only available, if the \a ReturnType of
405                                              the installed callback is not \c void.
406
407                                              If \a ReturnType is not \c void, the \a formatter must
408                                              be a callable with a signature compatible with
409                                              \code
410                                              void formatter(ReturnType const & value, std::ostream & os);
411                                              \endcode
412                                              The \a formatter takes the return value of the call \a
413                                              value and writes it properly formated to \a os. */
414
415     protected:
416         ParsedArgumentAttributorBase(Overload & overload, unsigned index);
417
418     private:
419     };
420
421 #ifndef DOXYGEN
422
423     template <class Overload, class Self>
424     class ParsedArgumentAttributorBase<Overload, Self, void>
425         : public ParsedCommandAttributor<Overload>
426     {
427     public:
428         Self doc(std::string const & doc) const; ///< Set documentation for all overloads
429         Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation
430
431     protected:
432         ParsedArgumentAttributorBase(Overload & overload, unsigned index);
433
434     private:
435     };
436
437 #endif
438     
439     /** \brief Argument dependent ParsedCommandBase attributes
440
441         Attributes for parsed commands are not set directly on the node. They are set via a special
442         attributor temporary returned when adding a parsed command to the tree.
443         
444         This class adds all those members, which depend on a specific argument. Each call to \c arg
445         will advance to the next argument.
446
447         \see \ref console_autoparse
448      */
449     template < class Overload, unsigned index, bool flag>
450     class ParsedArgumentAttributor
451         : public ParsedArgumentAttributorBase< Overload, 
452                                                 ParsedArgumentAttributor<Overload, index, flag> >
453     {
454         typedef boost::parameter::parameters<
455             kw::type::name,
456             kw::type::description,
457             kw::type::default_value,
458             kw::type::type_name,
459             kw::type::default_doc,
460             kw::type::parser> arg_params;
461
462     public:
463         typedef OverloadedCommandNode node_type;
464         typedef ParsedArgumentAttributor return_type;
465
466         typedef typename senf::function_traits_arg_type< 
467             typename Overload::traits, int(index) >::type arg_type;
468         typedef typename senf::remove_cvref< arg_type >::type value_type;
469         typedef ParsedArgumentAttributor<Overload, index+1> next_type;
470
471         next_type arg() const;          ///< Set argument attributes
472                                         /**< This member changes the attributes for the current
473                                              argument. The attributes are passed to arg() as keyword
474                                              arguments using the <a
475                                              href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
476                                              library. 
477                                              \code
478                                              ...
479                                                  .arg( kw::name          = "name", 
480                                                        kw::default_value = 1 )
481                                              ...
482                                              \endcode
483                                              The valid keywords are defined in the senf::console::kw
484                                              namespace.
485                                              
486                                              Each call to arg() will increment the argument index
487                                              and advance to the next argument. This member is only
488                                              present, if there is an argument at the current
489                                              index. */
490
491 #ifndef DOXYVEN
492
493 #       define BOOST_PP_ITERATION_PARAMS_1                                                        \
494             (4, (1, BOOST_PARAMETER_MAX_ARITY,                                                    \
495                  SENF_ABSOLUTE_INCLUDE_PATH(Scheduler/Console/ParsedCommand.mpp),                 \
496                  5))
497 #       include BOOST_PP_ITERATE()
498
499 #endif
500
501     private:
502         explicit ParsedArgumentAttributor(Overload & overload);
503
504         template <class ArgumentPack>
505         next_type argInfo(ArgumentPack const & args) const;
506         template <class Kw, class ArgumentPack>
507         void argInfo(Kw const &, ArgumentPack const &, boost::mpl::false_) 
508             const;
509
510         template <class ArgumentPack>
511         void argInfo(boost::parameter::keyword<kw::type::name> const &, 
512                      ArgumentPack const & args, boost::mpl::true_) 
513             const;
514         template <class ArgumentPack>
515         void argInfo(boost::parameter::keyword<kw::type::description> const &, 
516                      ArgumentPack const & args, boost::mpl::true_) 
517             const;
518         template <class ArgumentPack>
519         void argInfo(boost::parameter::keyword<kw::type::default_value> const &, 
520                      ArgumentPack const & args, boost::mpl::true_) 
521             const;
522         template <class ArgumentPack>
523         void argInfo(boost::parameter::keyword<kw::type::type_name> const &, 
524                      ArgumentPack const & args, boost::mpl::true_) 
525             const;
526         template <class ArgumentPack>
527         void argInfo(boost::parameter::keyword<kw::type::default_doc> const &, 
528                      ArgumentPack const & args, boost::mpl::true_) 
529             const;
530         template <class ArgumentPack>
531         void argInfo(boost::parameter::keyword<kw::type::parser> const &, 
532                      ArgumentPack const & args, boost::mpl::true_) 
533             const;
534
535         next_type next() const;
536
537         void defaultValue(value_type const & value) const;
538         template <class Fn> void parser(Fn fn) const;
539
540         template <class O, unsigned i, bool f>
541         friend class ParsedArgumentAttributor;
542
543         friend class detail::ParsedCommandAddNodeAccess;
544     };
545
546 #ifndef DOXYGEN
547
548     template <class Overload, unsigned index>
549     class ParsedArgumentAttributor<Overload, index, false>
550         : public ParsedArgumentAttributorBase< Overload, 
551                                                 ParsedArgumentAttributor<Overload, index, false> >
552     {
553     public:
554         typedef OverloadedCommandNode node_type;
555         typedef ParsedArgumentAttributor return_type;
556
557     private:
558         explicit ParsedArgumentAttributor(Overload & overload);
559
560         template <class O, unsigned i, bool f>
561         friend class ParsedArgumentAttributor;
562
563         friend class detail::ParsedCommandAddNodeAccess;
564     };
565
566     template <class Function>
567     typename detail::ParsedCommandTraits<Function>::Attributor
568     senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int,
569                           typename boost::enable_if_c<
570                               detail::ParsedCommandTraits<Function>::is_callable>::type * = 0);
571
572     template <class Signature>
573     typename detail::ParsedCommandTraits<Signature>::Attributor
574     senf_console_add_node(DirectoryNode & node, std::string const & name, boost::function<Signature> fn, int);
575
576     template <class Owner, class Function>
577     typename detail::ParsedCommandTraits<Function>::Attributor
578     senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
579                           Function fn, int,
580                           typename boost::enable_if_c<
581                               detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
582
583 #endif
584
585 }}
586
587 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
588
589 BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedCommandOverload, (class,unsigned))
590 BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedArgumentAttributor, (class, unsigned, bool))
591 BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function_traits, 1)
592
593 ///////////////////////////////hh.e////////////////////////////////////////
594 #include "ParsedCommand.cci"
595 #include "ParsedCommand.ct"
596 #include "ParsedCommand.cti"
597 #endif
598
599 \f
600 // Local Variables:
601 // mode: c++
602 // fill-column: 100
603 // comment-column: 40
604 // c-file-style: "senf"
605 // indent-tabs-mode: nil
606 // ispell-local-dictionary: "american"
607 // compile-command: "scons -u test"
608 // End: