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