Console: More extensible keyword parameter dispatching in arg() attribute
[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 "ParseParameter.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     /** \brief CommandOverload implementation with automatic argument parsing
51
52         ParsedCommandOverloadBase implements a CommandOverload implementation supporting automatic
53         parsing of arguments. This is \e not a node, it's a CommandOverload which is then added to
54         an OverloadedCommandNode instance.
55
56         Automatic argument parsing and return value processing consists of several components:
57         \li \ref overload_add Adding overload instances to the tree
58         \li (Advanced) \ref overload_parse
59         \li (Advanced) \ref overload_format
60
61         \section overload_add Adding argument parsing callbacks to the tree
62
63         Adding appropriate callbacks to the tree is very simple: just path a function pointer to
64         DirectoryNode::add() or a member function pointer to ScopedDirectory::add().
65         \code
66         std::string taskStatus(int id);
67
68         senf::console::root().add("taskStatus", &taskStatus);
69         \endcode
70
71         There are quite a number of additional parameters available to be set. These parameters are
72         documented in ParsedAttributeAttributor. Parameters are set by adding them as additional
73         calls after adding the node:
74
75         \code
76         senf::console::root().add("taskStatus", &taskStatus)
77             .doc("Query the current task status")
78             .arg( name = "id",
79                   description = "numeric id of task to check, -1 for the current task."
80                   default_value = -1 );
81         \endcode
82
83         You may also add an additional \c std::ostream & Argument as first argument to the
84         callback. If this argument is present, the stream connected to the console which issued the
85         command will be passed there. This allows writing arbitrary messages to the console.
86
87         Additionally, overloading is supported by registering multiple commands under the same
88         name. So, elaborating on above example:
89         \code
90         std::string taskStatus(int id);
91         std::string taskStatus(std::string const & name);
92
93         senf::console::root()
94             .add("taskStatus", static_cast<std::string (*)(int)>(&taskStatus))
95             .doc("Query the current task status")
96             .overloadDoc("Query status by id")
97             .arg( name = "id",
98                   description = "numeric id of task to check, -1 for the current task."
99                   default_value = -1 );
100         senf::console::root()
101             .add("taskStatus", static_cast<std::string (*)(std::string const &)>(&taskStatus))
102             .overloadDoc("Query status by name")
103             .arg( name = "name",
104                   description = "name of task to check" );
105         \endcode
106
107         We can see here, that taking the address of an overloaded function requires a cast. If you
108         can give unique names to each of the C++ overloads (not the overloads in the console), you
109         should do so to make the unwieldy casts unnecessary.
110
111         \section overload_parse Custom parameter parsers
112         
113         By default, parameters are parsed using \c boost::lexical_cast and therefore using \c
114         iostreams. This means, that any type which can be read from a stream can automatically be
115         used as argument type.
116
117         However, argument parsing can be configured by specializing
118         senf::console::detail::ParameterTraits. See that class for more information.
119
120         \section overload_format Custom return-value formatters
121
122         By default, return values are streamed to an ostream. This automatically allows any
123         streamable type to be used as return value. To add new types or customize the formating, the
124         senf::console::detail::ReturnValueTraits template needs to be specialized for that type. See
125         that class for more information.
126
127         \ingroup console_commands
128      */
129     class ParsedCommandOverloadBase
130         : public CommandOverload
131     {
132     public:
133         typedef boost::intrusive_ptr<ParsedCommandOverloadBase> ptr;
134
135         detail::ParameterInfoBase & arg(unsigned n) const;
136         template <class Type> detail::ParameterInfo<Type> & arg(unsigned n) const;
137
138         void doc(std::string const & d);
139
140     protected:
141         ParsedCommandOverloadBase();
142
143         template <class Type>
144         void addParameter();
145
146     private:
147         virtual unsigned v_numArguments() const;
148         virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const;
149         virtual std::string v_doc() const;
150
151         typedef std::vector<detail::ParameterInfoBase::ptr> Parameters;
152         Parameters parameters_;
153         std::string doc_;
154     };
155
156     template <class FunctionTraits, unsigned arity=FunctionTraits::arity>
157     class ParsedCommandOverload {};
158
159 #   define BOOST_PP_ITERATION_PARAMS_1 (4, (0, SENF_CONSOLE_MAX_COMMAND_ARITY,                     \
160                                             SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), \
161                                             1))
162 #   include BOOST_PP_ITERATE()
163
164     class ParsedCommandAttributorBase
165     {
166     public:
167         OverloadedCommandNode & node() const;
168         operator OverloadedCommandNode & () const;
169
170     protected:
171         ParsedCommandAttributorBase(ParsedCommandOverloadBase & overload, unsigned index);
172
173         void argName(std::string const & name) const;
174         void argDoc(std::string const & doc) const;
175         template <class Type> void defaultValue(Type const & value) const;
176
177         ParsedCommandOverloadBase & overload() const;
178         void overloadDoc(std::string const & doc) const;
179
180         void nodeDoc(std::string const & doc) const;
181         
182     private:
183         ParsedCommandOverloadBase & overload_;
184         unsigned index_;
185     };
186
187     template <class Overload>
188     class ParsedCommandAttributor
189         : public ParsedCommandAttributorBase
190     {
191     public:
192         Overload & overload() const;
193
194     protected:
195         ParsedCommandAttributor(Overload & overload, unsigned index);
196
197     private:
198     };
199     
200     namespace kw {
201         BOOST_PARAMETER_KEYWORD(type, name);
202         BOOST_PARAMETER_KEYWORD(type, description);
203         BOOST_PARAMETER_KEYWORD(type, default_value);
204     }
205
206     template <class Overload, class Self>
207     class ParsedAttributeAttributorBase
208         : public ParsedCommandAttributor<Overload>
209     {
210     public:
211         Self doc(std::string const & doc) const;
212         Self overloadDoc(std::string const & doc) const;
213
214     protected:
215         ParsedAttributeAttributorBase(Overload & overload, unsigned index);
216
217     private:
218     };
219
220     template < class Overload, 
221                unsigned index=0, 
222                bool flag=(index < unsigned(Overload::traits::arity)) >
223     class ParsedAttributeAttributor
224         : public ParsedAttributeAttributorBase< Overload, 
225                                                 ParsedAttributeAttributor<Overload, index, flag> >
226     {
227     public:
228         typedef typename senf::function_traits_arg_type< 
229             typename Overload::traits, int(index) >::type arg_type;
230         typedef typename senf::remove_cvref< arg_type >::type value_type;
231         typedef ParsedAttributeAttributor<Overload, index+1> next_type;
232
233         typedef OverloadedCommandNode node_type;
234         typedef ParsedAttributeAttributor return_type;
235
236         typedef boost::parameter::parameters<
237             kw::type::name,
238             kw::type::description,
239             kw::type::default_value> arg_params;
240
241         next_type arg() const;
242
243 #       define BOOST_PP_ITERATION_PARAMS_1 \
244             (4, (1, 3, SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), 5))
245 #       include BOOST_PP_ITERATE()
246
247     private:
248         explicit ParsedAttributeAttributor(Overload & overload);
249
250         template <class ArgumentPack>
251         next_type argInfo(ArgumentPack const & args) const;
252
253         template <class Kw, class ArgumentPack>
254         void argInfo(Kw const &, ArgumentPack const &, boost::mpl::true_) 
255             const;
256         template <class ArgumentPack>
257         void argInfo(boost::parameter::keyword<kw::type::name> const &, 
258                      ArgumentPack const & args, boost::mpl::false_) 
259             const;
260         template <class ArgumentPack>
261         void argInfo(boost::parameter::keyword<kw::type::description> const &, 
262                      ArgumentPack const & args, boost::mpl::false_) 
263             const;
264         template <class ArgumentPack>
265         void argInfo(boost::parameter::keyword<kw::type::default_value> const &, 
266                      ArgumentPack const & args, boost::mpl::false_) 
267             const;
268
269         next_type next() const;
270
271         void defaultValue(value_type const & value) const;
272
273         template <class O, unsigned i, bool f>
274         friend class ParsedAttributeAttributor;
275         
276         template <class Function>
277         friend ParsedAttributeAttributor<
278             ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
279         senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
280         
281         template <class Owner, class Function>
282         friend ParsedAttributeAttributor<
283             ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
284         senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
285                               Function fn, int,
286                               typename boost::enable_if_c<
287                                   detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
288     };
289
290     template <class Overload, unsigned index>
291     class ParsedAttributeAttributor<Overload, index, false>
292         : public ParsedAttributeAttributorBase< Overload, 
293                                                 ParsedAttributeAttributor<Overload, index, false> >
294     {
295     public:
296         typedef OverloadedCommandNode node_type;
297         typedef ParsedAttributeAttributor return_type;
298
299     private:
300         explicit ParsedAttributeAttributor(Overload & overload);
301
302         template <class O, unsigned i, bool f>
303         friend class ParsedAttributeAttributor;
304         
305         template <class Function>
306         friend ParsedAttributeAttributor<
307             ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
308         senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
309         
310         template <class Owner, class Function>
311         friend ParsedAttributeAttributor<
312             ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
313         senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
314                               Function fn, int,
315                               typename boost::enable_if_c<
316                                   detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
317     };
318
319 #ifndef DOXYGEN
320
321     template <class Function>
322     ParsedAttributeAttributor<
323         ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
324     senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
325
326     template <class Owner, class Function>
327     ParsedAttributeAttributor<
328         ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
329     senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
330                           Function fn, int,
331                           typename boost::enable_if_c<
332                               detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
333
334 #endif
335
336 }}
337
338 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
339
340 BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedCommandOverload, (class,unsigned))
341 BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedAttributeAttributor, (class, unsigned, bool))
342 BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function_traits, 1)
343
344 ///////////////////////////////hh.e////////////////////////////////////////
345 #include "ParsedCommand.cci"
346 #include "ParsedCommand.ct"
347 #include "ParsedCommand.cti"
348 #endif
349
350 \f
351 // Local Variables:
352 // mode: c++
353 // fill-column: 100
354 // comment-column: 40
355 // c-file-style: "senf"
356 // indent-tabs-mode: nil
357 // ispell-local-dictionary: "american"
358 // compile-command: "scons -u test"
359 // End: