9f43d157be19f8ba6bb68d5f49db700849a021ce
[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 #include <vector>
31 #include <boost/type_traits/function_traits.hpp>
32 #include <boost/type_traits/is_member_pointer.hpp>
33 #include <boost/type_traits/is_same.hpp>
34 #include <boost/mpl/if.hpp>
35 #include <boost/utility.hpp>
36 #include <boost/parameter/keyword.hpp>
37 #include <boost/parameter/parameters.hpp>
38 #include "../config.hh"
39 #include "OverloadedCommand.hh"
40 #include "Traits.hh"
41 #include "../Utils/type_traits.hh"
42
43 #include "ParsedCommand.ih"
44 #include "ParsedCommand.mpp"
45 ///////////////////////////////hh.p////////////////////////////////////////
46
47 namespace senf {
48 namespace console {
49
50     namespace detail { class ArgumentInfoBase; }
51
52     /** \brief CommandOverload implementation with automatic argument parsing
53
54         ParsedCommandOverloadBase implements a CommandOverload implementation supporting automatic
55         parsing of arguments. This is \e not a node, it's a CommandOverload which is then added to
56         an OverloadedCommandNode instance.
57
58         Automatic argument parsing and return value processing consists of several components:
59         \li \ref overload_add Adding overload instances to the tree
60         \li (Advanced) \ref overload_parse
61         \li (Advanced) \ref overload_format
62
63         \section overload_add Adding argument parsing callbacks to the tree
64
65         Adding appropriate callbacks to the tree is very simple: just path a function pointer to
66         DirectoryNode::add() or a member function pointer to ScopedDirectory::add().
67         \code
68         std::string taskStatus(int id);
69
70         senf::console::root().add("taskStatus", &taskStatus);
71         \endcode
72
73         There are quite a number of additional parameters available to be set. These parameters are
74         documented in ParsedArgumentAttributor. Parameters are set by adding them as additional
75         calls after adding the node:
76
77         \code
78         senf::console::root().add("taskStatus", &taskStatus)
79             .doc("Query the current task status")
80             .arg( name = "id",
81                   description = "numeric id of task to check, -1 for the current task."
82                   default_value = -1 );
83         \endcode
84
85         You may also add an additional \c std::ostream & Argument as first argument to the
86         callback. If this argument is present, the stream connected to the console which issued the
87         command will be passed there. This allows writing arbitrary messages to the console.
88
89         Additionally, overloading is supported by registering multiple commands under the same
90         name. So, elaborating on above example:
91         \code
92         std::string taskStatus(int id);
93         std::string taskStatus(std::string const & name);
94
95         senf::console::root()
96             .add("taskStatus", static_cast<std::string (*)(int)>(&taskStatus))
97             .doc("Query the current task status")
98             .overloadDoc("Query status by id")
99             .arg( name = "id",
100                   description = "numeric id of task to check, -1 for the current task."
101                   default_value = -1 );
102         senf::console::root()
103             .add("taskStatus", static_cast<std::string (*)(std::string const &)>(&taskStatus))
104             .overloadDoc("Query status by name")
105             .arg( name = "name",
106                   description = "name of task to check" );
107         \endcode
108
109         We can see here, that taking the address of an overloaded function requires a cast. If you
110         can give unique names to each of the C++ overloads (not the overloads in the console), you
111         should do so to make the unwieldy casts unnecessary.
112
113         \section overload_parse Custom parameter parsers
114         
115         By default, parameters are parsed using \c boost::lexical_cast and therefore using \c
116         iostreams. This means, that any type which can be read from a stream can automatically be
117         used as argument type.
118
119         However, argument parsing can be configured by specializing
120         senf::console::ArgumentTraits. See that class for more information.
121
122         \section overload_format Custom return-value formatters
123
124         By default, return values are streamed to an ostream. This automatically allows any
125         streamable type to be used as return value. To add new types or customize the formating, the
126         senf::console::ReturnValueTraits template needs to be specialized for that type. See
127         that class for more information.
128
129         \ingroup console_commands
130      */
131     class ParsedCommandOverloadBase
132         : public CommandOverload
133     {
134     public:
135         typedef boost::intrusive_ptr<ParsedCommandOverloadBase> ptr;
136
137         detail::ArgumentInfoBase & arg(unsigned n) const;
138         template <class Type> detail::ArgumentInfo<Type> & arg(unsigned n) const;
139
140         void doc(std::string const & d);
141
142     protected:
143         ParsedCommandOverloadBase();
144
145         template <class Type>
146         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     template <class FunctionTraits, unsigned arity=FunctionTraits::arity>
171     class ParsedCommandOverload : public ParsedCommandOverloadBase
172     {
173     public:
174         typedef boost::intrusive_ptr<ParsedCommandOverload> ptr;
175
176 #ifdef DOXYGEN
177         static ptr create(Function fn);
178 #endif
179     };
180
181 #ifndef DOXYGEN
182
183 #   define BOOST_PP_ITERATION_PARAMS_1 (4, (0, SENF_CONSOLE_MAX_COMMAND_ARITY,                     \
184                                             SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), \
185                                             1))
186 #   include BOOST_PP_ITERATE()
187
188 #endif
189
190     /** \brief Generic ParsedCommandOverladBase attributes
191
192         Attributes for parsed commands are not set directly on the node. They are set via a special
193         attributor temporary returned when adding a parsed command to the tree.
194         
195         This class is the base class for those attributors. It provides members which do not depend
196         in any way on the exact type of command added.
197      */
198     class ParsedCommandAttributorBase
199     {
200     public:
201         OverloadedCommandNode & node() const; ///< Return the node object
202         operator OverloadedCommandNode & () const; ///< Automatically convert to node object
203
204     protected:
205         ParsedCommandAttributorBase(ParsedCommandOverloadBase & overload, unsigned index);
206
207         void argName(std::string const & name) const;
208         void argDoc(std::string const & doc) const;
209         template <class Type> void defaultValue(Type const & value) const;
210
211         ParsedCommandOverloadBase & overload() const;
212         void overloadDoc(std::string const & doc) const;
213
214         void nodeDoc(std::string const & doc) const;
215         
216     private:
217         ParsedCommandOverloadBase & overload_;
218         unsigned index_;
219     };
220
221     /** \brief Non argument dependent ParsedCommandBase attributes 
222         
223         Attributes for parsed commands are not set directly on the node. They are set via a special
224         attributor temporary returned when adding a parsed command to the tree.
225
226         This class adds all those members, which do depend on the type of command added (and thereby
227         on that commands signature) but do not depend on the type of any single argument.
228         
229         \fixme Implement compile-time checking, that after a defaulted arg only defaulted args are
230             allowed.
231      */
232     template <class Overload>
233     class ParsedCommandAttributor
234         : public ParsedCommandAttributorBase
235     {
236     public:
237         Overload & overload() const;    ///< Get the command overload
238
239     protected:
240         ParsedCommandAttributor(Overload & overload, unsigned index);
241
242     private:
243     };
244
245     /** \brief Keyword argument tags
246
247         The tags defined in this namespace are used as keyword arguments via the <a
248         href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
249         library.
250
251         For the keyword tags, the standard C++ scoping rules apply:
252         \li Either qualify them with their complete namespace: <tt>arg( senf::console::kw::name =
253             "name" )</tt>
254         \li or use a namespace alias: <tt>namespace kw = senf::console::kw; arg( kw::name = "name"
255             );</tt>
256         \li import the keywords into your namespace: <tt>using namespace senf::console::kw; arg(
257             name = "name");</tt>
258
259         The second alternative is preferred, the <tt>using namespace</tt> directive may be used as
260         long as the keyword names do not clash with another visible symbol.
261      */
262     namespace kw {
263         BOOST_PARAMETER_KEYWORD(type, name) ///< Argument name
264         BOOST_PARAMETER_KEYWORD(type, description) ///< One-line Argument description
265         BOOST_PARAMETER_KEYWORD(type, default_value) ///< Argument default value
266     }
267
268     /** \brief Derived class dependent ParsedCommandBase attributes
269
270         Attributes for parsed commands are not set directly on the node. They are set via a special
271         attributor temporary returned when adding a parsed command to the tree.
272         
273         This class adds all those members, which do not depend on any specific argument but which
274         need to return the correct attributor type.
275      */
276     template <class Overload, class Self>
277     class ParsedArgumentAttributorBase
278         : public ParsedCommandAttributor<Overload>
279     {
280     public:
281         Self doc(std::string const & doc) const; ///< Set documentation for all overloads
282         Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation
283
284     protected:
285         ParsedArgumentAttributorBase(Overload & overload, unsigned index);
286
287     private:
288     };
289
290     
291     /** \brief Argument dependent ParsedCommandBase attributes
292
293         Attributes for parsed commands are not set directly on the node. They are set via a special
294         attributor temporary returned when adding a parsed command to the tree.
295         
296         This class adds all those members, which depend on a specific argument. Each call to \c arg
297         will advance to the next argument.
298      */
299     template < class Overload, 
300                unsigned index=0, 
301                bool flag=(index < unsigned(Overload::traits::arity)) >
302     class ParsedArgumentAttributor
303         : public ParsedArgumentAttributorBase< Overload, 
304                                                 ParsedArgumentAttributor<Overload, index, flag> >
305     {
306         typedef boost::parameter::parameters<
307             kw::type::name,
308             kw::type::description,
309             kw::type::default_value> arg_params;
310
311     public:
312         typedef OverloadedCommandNode node_type;
313         typedef ParsedArgumentAttributor return_type;
314
315         typedef typename senf::function_traits_arg_type< 
316             typename Overload::traits, int(index) >::type arg_type;
317         typedef typename senf::remove_cvref< arg_type >::type value_type;
318         typedef ParsedArgumentAttributor<Overload, index+1> next_type;
319
320         next_type arg() const;          ///< Set argument attributes
321                                         /**< This member changes the attributes for the current
322                                              argument. The attributes are passed to arg() as keyword
323                                              arguments using the <a
324                                              href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
325                                              library. The valid keywords are defined in the
326                                              senf::console::kw namespace. 
327
328                                              This member is only present, if there is an argument at
329                                              the current index. */
330
331 #ifndef DOXYVEN
332
333 #       define BOOST_PP_ITERATION_PARAMS_1 \
334             (4, (1, 3, SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), 5))
335 #       include BOOST_PP_ITERATE()
336
337 #endif
338
339     private:
340         explicit ParsedArgumentAttributor(Overload & overload);
341
342         template <class ArgumentPack>
343         next_type argInfo(ArgumentPack const & args) const;
344         template <class Kw, class ArgumentPack>
345         void argInfo(Kw const &, ArgumentPack const &, boost::mpl::true_) 
346             const;
347
348         template <class ArgumentPack>
349         void argInfo(boost::parameter::keyword<kw::type::name> const &, 
350                      ArgumentPack const & args, boost::mpl::false_) 
351             const;
352         template <class ArgumentPack>
353         void argInfo(boost::parameter::keyword<kw::type::description> const &, 
354                      ArgumentPack const & args, boost::mpl::false_) 
355             const;
356         template <class ArgumentPack>
357         void argInfo(boost::parameter::keyword<kw::type::default_value> const &, 
358                      ArgumentPack const & args, boost::mpl::false_) 
359             const;
360
361         next_type next() const;
362
363         void defaultValue(value_type const & value) const;
364
365         template <class O, unsigned i, bool f>
366         friend class ParsedArgumentAttributor;
367
368 #ifndef DOXYGEN
369         
370         template <class Function>
371         friend ParsedArgumentAttributor<
372             ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
373         senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
374         
375         template <class Owner, class Function>
376         friend ParsedArgumentAttributor<
377             ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
378         senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
379                               Function fn, int,
380                               typename boost::enable_if_c<
381                                   detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
382
383 #endif
384     };
385
386 #ifndef DOXYGEN
387
388     template <class Overload, unsigned index>
389     class ParsedArgumentAttributor<Overload, index, false>
390         : public ParsedArgumentAttributorBase< Overload, 
391                                                 ParsedArgumentAttributor<Overload, index, false> >
392     {
393     public:
394         typedef OverloadedCommandNode node_type;
395         typedef ParsedArgumentAttributor return_type;
396
397     private:
398         explicit ParsedArgumentAttributor(Overload & overload);
399
400         template <class O, unsigned i, bool f>
401         friend class ParsedArgumentAttributor;
402         
403         template <class Function>
404         friend ParsedArgumentAttributor<
405             ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
406         senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
407         
408         template <class Owner, class Function>
409         friend ParsedArgumentAttributor<
410             ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
411         senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
412                               Function fn, int,
413                               typename boost::enable_if_c<
414                                   detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
415     };
416
417     template <class Function>
418     ParsedArgumentAttributor<
419         ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
420     senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
421
422     template <class Owner, class Function>
423     ParsedArgumentAttributor<
424         ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
425     senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
426                           Function fn, int,
427                           typename boost::enable_if_c<
428                               detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
429
430 #endif
431
432 }}
433
434 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
435
436 BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedCommandOverload, (class,unsigned))
437 BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedArgumentAttributor, (class, unsigned, bool))
438 BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function_traits, 1)
439
440 ///////////////////////////////hh.e////////////////////////////////////////
441 #include "ParsedCommand.cci"
442 #include "ParsedCommand.ct"
443 #include "ParsedCommand.cti"
444 #endif
445
446 \f
447 // Local Variables:
448 // mode: c++
449 // fill-column: 100
450 // comment-column: 40
451 // c-file-style: "senf"
452 // indent-tabs-mode: nil
453 // ispell-local-dictionary: "american"
454 // compile-command: "scons -u test"
455 // End: