Utils: Refactor hexdump() helper to move code out of template function
[senf.git] / Console / Node.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 Node public header */
25
26 /** \defgroup node_tree The node tree
27     
28     The console/config node tree is the central data-structure of the library. Into this tree, all
29     commands and parameters are entered. The tree is then exposed using a file-system like
30     interface.
31     
32     \autotoc
33
34     \section console_tree The tree
35
36     We will start by giving a more complete example. This example contains most of the stuff needed
37     for using the console/config library.
38
39     \code
40     // Define callback function.
41     void mycommand(std::ostream & os, senf::console::ParseCommandInfo const & command)
42     {
43         // ...
44         os << "!! Important message ...\n";
45     }
46
47     class SomeClass
48     {
49     public:
50         // Declare a directory node (proxy) for use by this class. This must be public so we can add
51         // it to the node tree later.
52         senf::console::ScopedDirectory<SomeClass> dir;
53
54         SomeClass() : dir(this) 
55         {
56             // You may document the directory here or later when adding it to the tree
57             dir.doc("Manager for something");
58
59             // Add a member function (the pointer-to-member is automatically bound to this instance)
60             dir.add("member", &SomeClass::member)
61                 .doc("Do the member operation");
62         }
63
64         void member(std::ostream & os, senf::console::ParseCommandInfo const & command)
65         {
66             // ...
67         }
68     };
69
70     int main(int, char**)
71     {
72         // Provide global documentation
73         senf::console::root()
74             .doc("This is someServer server");
75
76         // Add a new directory to the root and document it. All the mutators return the node object
77         // itself so operations can be chained.
78         senf::console::DirectoryNode & mydir (
79                 .mkdir("myserver")
80                 .doc("My server specific directory"));
81
82         // Add a command to that directory
83         mydir.add("mycommand", &mycommand)
84             .doc("mycommand <foo> [<bar>]\n\n"
85                  "If <bar> is given, flurgle the <foo>, otherwise burgle it");
86
87         // Create a SomeClass instance and add it's directory.
88         SomeClass someClass;
89         mydir.add("someClass", someClass.dir);
90
91         // Start the interactive console server
92         senf::console::Server::start(senf::INet4SocketAddress(senf::INet4Address::None, 23232u))
93             .name("someServer");
94     }
95     \endcode
96
97     \subsection console_nodes Node types
98
99     The console/config library tree consists of two basic node types:
100     
101     \li senf::console::DirectoryNode provides internal nodes with an arbitrary number of children
102     \li senf::console::CommandNode describes a command entry in the tree
103
104     senf::console::CommandNode is the base-class of all command nodes of which there are several,
105     depending on the type of command.
106
107     There is a single root node, the senf::console::DirectoryNode called senf::console::root(). From
108     this node, the tree is traversed.
109
110     All nodes are allocated on the heap and are managed using a smart pointer.
111     
112     \subsection console_manipulate Manipulating the node tree
113
114     There are several ways to add nodes to the tree:
115
116     \li A senf::console::DirectoryNode can be added using senf::console::DirectoryNode::mkdir().
117     \li An arbitrary node can be created and then (possibly later) added to the tree using the
118         corresponding senf::console::DirectoryNode::add() overload.
119     \li A senf::console::CommandNode is normally added to the tree by directly adding a callback
120         using one of the overloaded senf::console::DirectoryNode::add() members. See \ref
121         console_commands.
122
123     When directly adding a node callback, the type of node added depends on the type of
124     callback. The callback types which can be added are listed at \ref console_callbacks.
125     
126     \code
127     void callback(std::ostream & os, senf::console::ParseCommandInfo const & command) { ... }
128     // ...
129     myDirectory.add("foo",&callback);
130     \endcode
131
132     Every node is identified among it's siblings by it's name. The name of the node is set when
133     adding the node to the tree. If the name is empty or non-unique, a unique name will be
134     automatically provided.
135
136     To remove a node from the tree, just use the nodes senf::console::GenericNode::unlink() or the
137     parents senf::console::DirectoryNode::remove() member. This call removes the node from it's
138     parent and returns a (smart) node pointer.
139
140     \li If you ignore the return value, the node (and it's children) will be deleted.
141     \li Alternatively, you may store away the node and re-attach it later.
142     \li An node (or subtree) can be moved to a different place by unlinking the node at it's old
143         place and re-adding it at it's new location.
144     \li To rename a node, unlink and re-add it with a different name.
145
146     \code
147     myDirectory.add("bar", myDirectory.remove("foo"));
148     \endcode
149
150     \subsection console_node_param Assigning additional node parameters
151
152     Depending on the node type added, additional node parameters may be set. For example, every node
153     has a documentation parameter which is used by the online-help system. To assign these
154     parameters, the node exposes corresponding member functions. Since
155     senf::console::DirectoryNode::add() returns the newly added node by reference, additional
156     parameters may just be added to the end of the add command:
157     \code
158     myDirectory.add("foo",&fooCallback).doc("The foo method");
159     \endcode
160     Since the parameter setters all return the node reference, additional parameters may just be
161     added to the end of the command.
162     
163     \subsection console_tree_traverse Traversing the tree
164
165     The simplest way to access tree elements is to save the return value of the
166     senf::console::DirectoryNode::add() members. However, saving the reference will not ensure, that
167     the node is not removed. If the node might be removed from the tree, you should use a smart
168     pointer (either <tt>ptr</tt> or <tt>weak_ptr</tt>) to hold the node.
169
170     Another possibility is to traverse the tree explicitly. For this purpose, the operators '[]' and
171     '()' have been overloaded in senf::console::DirectoryNode.
172     \code
173     senf::console::root().getDirectory("myDirectory").getCommand("foo")
174     \\ or more concise but otherwise completely identical
175     senf::console::root()["myDirectory"]("foo")
176     \endcode
177
178     getDirectory and the '[]' operator will return a senf::console::DirectoryNode whereas getCommand
179     and the '()' operator will return a senf::console::CommandNode. If the node is not found or is
180     not of the correct type, an exception will be raised.
181
182     \section console_object_dir Assigning a directory to an object instance
183
184     Most objects will register several commands. So it makes sense for these objects to manage their
185     own directory. Since directories are however allocated on the heap, they cannot be directly
186     added to a class. To facilitate this usage, the senf::console::ScopedDirectory is used. This
187     class provides a senf::console::DirectoryNode facade. Internally, it automatically creates a
188     senf::console::DirectoryNode to which all calls are forwarded.
189
190     The senf::console::ScopedDirectory member should be declared public. This allows the user of the
191     class to add the node to the tree.
192  */
193
194 #ifndef HH_Node_
195 #define HH_Node_ 1
196
197 // Custom includes
198 #include <map>
199 #include <boost/shared_ptr.hpp>
200 #include <boost/weak_ptr.hpp>
201 #include <boost/enable_shared_from_this.hpp>
202 #include <boost/utility.hpp>
203 #include <boost/range/iterator_range.hpp>
204 #include <boost/typeof/typeof.hpp>
205 #include <boost/type_traits/remove_reference.hpp>
206 #include "../Utils/Exception.hh"
207 #include "../Utils/mpl.hh"
208 #include "../Utils/Logger/SenfLog.hh"
209 #include "../Utils/type_traits.hh"
210 #include "Parse.hh"
211
212 //#include "Node.mpp"
213 ///////////////////////////////hh.p////////////////////////////////////////
214
215 namespace senf {
216 namespace console {
217
218     class DirectoryNode;
219     class CommandNode;
220
221     DirectoryNode & root();
222
223     /** \brief Config/console node tree base-class
224
225         GenericNode is the base class of all node objects. There are two basic node types derived
226         from GenericNode:  DirectoryNode and CommandNode.
227
228         All nodes are dynamically allocated and automatically managed using reference counting.
229
230         All nodes are normally linked into a single tree which root node is
231         senf::console::root(). Nodes may however be orphaned (not linked to the tree) either
232         directly (the node has no parent) or indirectly (the node has a parent but is part of an
233         orphaned subtree which is not linked to the root node).
234
235         Every active (non-orphaned) node (except the root() node) has a non-empty node name. This
236         name is assigned to the node when adding the node to the tree.
237
238         \ingroup node_tree
239       */
240     class GenericNode 
241         : public boost::enable_shared_from_this<GenericNode>
242     {
243         SENF_LOG_CLASS_AREA();
244     public:
245         ///////////////////////////////////////////////////////////////////////////
246         // Types
247
248         typedef boost::shared_ptr<GenericNode> ptr;
249         typedef boost::shared_ptr<GenericNode const> cptr;
250         typedef boost::weak_ptr<GenericNode> weak_ptr;
251
252         ///////////////////////////////////////////////////////////////////////////
253
254         virtual ~GenericNode();
255
256         std::string const & name() const; ///< Node name
257         boost::shared_ptr<DirectoryNode> parent() const; ///< Parent node
258                                         /**< May be null, if the node is the root node or if it is
259                                              not linked to the tree */
260
261         std::string path() const;       ///< Node path
262                                         /**< The node path is built by joining the names of all
263                                              parent nodes with '/' chars. */
264         std::string path(DirectoryNode const & root) const;       
265                                         ///< Node path up to \a root
266                                         /**< The node path is built by joining the names of all
267                                              parent nodes up to \a root with '/' chars. */
268
269         ptr unlink();                   ///< Remove node from it's parent directory
270                                         /**< You may either discard the return value and thereby
271                                              dispose the node or may re-attach the node at some
272                                              other place using DirectoryNode::add(). */
273
274         bool active() const;            ///< \c true, if node is attached to the root() node
275
276         void help(std::ostream & output) const; /// Write help info to \a output
277
278         ptr thisptr();                  ///< Get smart pointer to node
279         cptr thisptr() const;           ///< Get smart pointer to node (const)
280
281         bool isChildOf(DirectoryNode & parent) const;
282                                         ///< \c true, if node is a child of \a parent
283                                         /**< Will also return \c true, if \a parent is the current
284                                              node. */
285
286         bool operator== (GenericNode & other) const;
287                                         /// \c true, if this and \a other are the same node
288         bool operator!= (GenericNode & other) const;
289                                         /// \c true, if this and \a other are different nodes
290
291     protected:
292         GenericNode();
293
294         void name(std::string const & name);
295
296 #ifndef DOXYGEN
297     private:
298 #else
299     public:
300 #endif
301         virtual void v_help(std::ostream & output) const = 0;
302                                         ///< Provide help information
303                                         /**< This member must be implemented in derived classes
304                                              to provide node specific help information. */
305
306     private:
307         std::string name_;
308         DirectoryNode * parent_;
309
310         friend class DirectoryNode;
311     };
312
313     class SimpleCommandNode;
314
315     /** \brief Internal: Node creation helper traits
316         
317         This class is used internally to find out the type of node to create for a specific argument
318         type. 
319      */
320     template <class Object>
321     struct NodeCreateTraits
322     {
323         typedef BOOST_TYPEOF_TPL( senf_console_add_node( 
324                                       * static_cast<DirectoryNode *>(0),
325                                       * static_cast<std::string const *>(0),
326                                       * static_cast<Object *>(0),
327                                       0) ) base_type;
328         typedef typename senf::remove_cvref<base_type>::type value_type;
329
330         typedef typename value_type::node_type NodeType;
331         typedef typename value_type::return_type result_type;
332
333         /// Internal
334         struct Creator {
335             static result_type create(DirectoryNode & node, std::string const & name, 
336                                       Object & ob);
337         };
338     };
339
340     /** \brief Config/console tree directory node
341
342         This node type provides the internal and root nodes of the tree. It allows to add arbitrary
343         children and supports directory traversal.
344         
345         Nodes are normally not instantiated manually but are created by the DirectoryNode via
346         mkdir() or add(). Special add() members however allow externally allocated node objects.
347
348         Nodes may be added to the tree only once, otherwise chaos will ensue. Since nodes are always
349         managed dynamically, there is a special ScopedDirectory proxy template which provides a
350         DirectoryNode facade. ScopedDirectory is used if a class wants to manage it's own directory
351         as a data member.
352
353         Every node is assigned a (new) name when it is added to a directory. If the directory
354         already has an entry of that name, the name is made unique by appending a suffix of the form
355         '-n' where n is a number starting at 1. If the name is empty, int is set to 'unnamed' and
356         then uniquified as above. Automatically providing unique names simplifies adding
357         configuration/console support to generic components.
358
359         \ingroup node_tree
360       */
361     class DirectoryNode : public GenericNode
362     {
363         SENF_LOG_CLASS_AREA();
364         typedef std::map<std::string, GenericNode::ptr> ChildMap;
365     public:
366         ///////////////////////////////////////////////////////////////////////////
367         // Types
368
369         typedef boost::shared_ptr<DirectoryNode> ptr;
370         typedef boost::shared_ptr<DirectoryNode const> cptr;
371         typedef boost::weak_ptr<DirectoryNode> weak_ptr;
372
373         typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
374         typedef ChildMap::const_iterator child_iterator;
375
376         typedef DirectoryNode node_type;
377         typedef DirectoryNode & return_type;
378
379         ///////////////////////////////////////////////////////////////////////////
380         ///\name Structors and default members
381         ///\{
382
383         static ptr create();            ///< Create node object.
384                                         /**< You should normally use either mkdir() or
385                                              ScopedDirectory instead of create() */
386
387         ///\}
388         ///////////////////////////////////////////////////////////////////////////
389         ///\name Children
390         ///\{
391
392         template <class NodeType>
393         NodeType & add(std::string const & name, boost::shared_ptr<NodeType> node);
394                                         ///< Add node to tree
395                                         /**< Adds the \a node to the tree as a child of \a this
396                                              node. The node is given the name \a name. If a node of
397                                              that name already exists, a numeric suffix of the form
398                                              '-n' is added to the name until the name is unique. If
399                                              \a name is empty, it is set to 'unnamed'. */
400
401         template <class Object>
402         typename NodeCreateTraits<Object>::result_type add(std::string const & name, 
403                                                            Object const & ob);
404                                         ///< Generic child node factory
405                                         /**< This member is used to create a new child node of the
406                                              current directory. The type of node created depends on
407                                              the type of argument passed.
408
409                                              The node type is selected by the NodeCreateTraits
410                                              class. To allow adding a specific node type, you need
411                                              to provide an overload for
412                                              <tt>senf_console_add_node</tt> which must be visible at
413                                              when you register the new node.
414                                              \code
415                                              MyNodeType & senf_console_add_node(
416                                                  DirectoryNode & dir,
417                                                  std::string const & name,
418                                                  MySpecialObject const & ob,
419                                                  int)
420                                              {
421                                                  return dir.add(name, MyNodeType::create(ob));
422                                              }
423                                              \endcode
424                                              (Do not forget the last unnamed 'int' parameter which
425                                              is not used but serves to disambiguate the
426                                              overloads). */
427
428         template <class Object>
429         typename NodeCreateTraits<Object>::result_type add(std::string const & name, 
430                                                            Object & ob);
431                                         ///< Generic child node factory
432                                         /**< \see add() */
433
434         GenericNode::ptr remove(std::string const & name);
435                                         ///< Remove node \a name from the tree
436                                         /**< The returned pointer may either be discarded, which
437                                              will automatically dispose the removed node, or it may
438                                              be saved and/or re-attached at some other place in the
439                                              tree. */
440
441         bool hasChild(std::string const & name) const;
442                                         ///< \c true, if there is a child with name \a name
443
444         GenericNode & get(std::string const & name) const;
445                                         ///< Get child node
446                                         /**< \throws UnknownNodeNameException if a child \a name
447                                                  does not exist */
448
449         DirectoryNode & getDirectory(std::string const & name) const;
450                                         ///< Get directory child node
451                                         /**< Same as operator[]
452                                              \throws UnknownNodeNameException if a child \a name
453                                                  does not exist. 
454                                              \throws std::bad_cast if the child \a name is not a
455                                                  directory node. */
456         
457         DirectoryNode & operator[](std::string const & name) const;
458                                         ///< Get directory child node
459                                         /**< Same as getDirectory
460                                              \throws UnknownNodeNameException if a child \a name
461                                                  does not exist. 
462                                              \throws std::bad_cast if the child \a name is not a
463                                                  directory node. */
464
465         CommandNode & getCommand(std::string const & name) const;
466                                         ///< Get command child node
467                                         /**< Same as operator()
468                                              \throws UnknownNodeNameException if a child \a name
469                                                  does not exist
470                                              \throws std::bad_cast if the child \a name is not a
471                                                  command node. */
472
473         CommandNode & operator()(std::string const & name) const;
474                                         ///< Get command child node
475                                         /**< Same as getCommand()
476                                              \throws UnknownNodeNameException if a child \a name
477                                                  does not exist
478                                              \throws std::bad_cast if the child \a name is not a
479                                                  command node. */
480
481         DirectoryNode & mkdir(std::string const & name);
482                                         ///< Create sub-directory node
483         
484         ChildrenRange children() const; ///< Return iterator range over all children.
485                                         /**< The returned range is sorted by child name. */
486
487         ChildrenRange completions(std::string const & s) const;
488                                         ///< Return iterator range of completions for \a s
489                                         /**< The returned range is sorted by child name. */
490
491         ///\}
492         ///////////////////////////////////////////////////////////////////////////
493
494         template <class ForwardRange>
495         GenericNode & traverse(ForwardRange const & range, bool autocomplete=false,
496                                DirectoryNode & root = root());
497                                         ///< Traverse node path starting at this node
498                                         /**< The <tt>ForwardRange::value_type</tt> must be
499                                              (convertible to) std::string. Each range element
500                                              constitutes a step along the node traversal.
501
502                                              If the range starts with an empty element, the
503                                              traversal is started at the root() node, otherwise it
504                                              is started at \a this node. The traversal supports '.',
505                                              '..' and ignores further empty elements. 
506
507                                              If \a autocomplete is set to \c true, invalid path
508                                              components which can be uniquely completed will be
509                                              completed automatically while traversing the tree. */
510
511         DirectoryNode & doc(std::string const & doc);
512                                         ///< Set node documentation
513
514         ptr thisptr();
515         cptr thisptr() const;
516
517     protected:
518         DirectoryNode();
519
520     private:
521         void add(GenericNode::ptr node);
522         virtual void v_help(std::ostream & output) const;
523
524         ChildMap children_;
525         std::string doc_;
526
527         friend DirectoryNode & root();
528     };
529
530     /// Exception: Unknown node name
531     struct UnknownNodeNameException : public senf::Exception
532     { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
533
534 #ifndef DOXYGEN
535     template <class Type>
536     struct NodeCreateTraits< boost::shared_ptr<Type> >
537     {};
538 #endif
539
540     /** \brief Config/console tree command node
541
542         The CommandNode is the base-class for the tree leaf nodes. Concrete command node
543         implementations are derived from this class.
544
545         To execute a command, CommandNode::operator()() or CommandNode::execute() is called.
546
547         Subclass instances of this node type are automatically created when adding commands to the
548         tree. See \ref console_commands.
549
550         \ingroup node_tree
551       */
552     class CommandNode : public GenericNode
553     {
554         SENF_LOG_CLASS_AREA();
555     public:
556         ///////////////////////////////////////////////////////////////////////////
557         // Types
558
559         typedef boost::shared_ptr<CommandNode> ptr;
560         typedef boost::shared_ptr<CommandNode const> cptr;
561         typedef boost::weak_ptr<CommandNode> weak_ptr;
562
563         ///////////////////////////////////////////////////////////////////////////
564
565         void execute(std::ostream & output, ParseCommandInfo const & command) const;
566                                         ///< Execute the command
567                                         /**< Same as operator()()
568                                              \param[in] output stream where result messages may be
569                                                  written to
570                                              \param[in] arguments command arguments. This is a
571                                                  range of ranges of ArgumentToken instances. */
572
573         void operator()(std::ostream & output, ParseCommandInfo const & command) const;
574                                         ///< Execute the command
575                                         /**< Same as execute()
576                                              \param[in] output stream where result messages may be
577                                                  written to
578                                              \param[in] arguments command arguments. This is a
579                                                  range of ranges of ArgumentToken instances. */
580
581         ptr thisptr();
582         cptr thisptr() const;
583
584     protected:
585         CommandNode();
586
587 #ifndef DOXYGEN
588     private:
589 #endif
590         virtual void v_execute(std::ostream & output, ParseCommandInfo const & command) const = 0;
591                                         ///< Called to execute the command
592                                         /**< \param[in] output stream where result messages may be
593                                                  written to
594                                              \param[in] arguments command arguments. This is a
595                                                  range of ranges of ArgumentToken instances. */
596
597     private:
598     };
599
600     /** \brief Most simple CommandNode implementation
601
602         This CommandNode implementation simply forwards the \a output and \a arguments arguments to
603         an arbitrary callback. Thus, it allows to add callbacks with the signature
604         \code
605         void callback(std::ostream & os, senf::console::ParseCommandInfo const & command)
606         { ... }
607         \endcode
608         to the tree.
609  
610         \ingroup console_commands
611      */
612     class SimpleCommandNode : public CommandNode
613     {
614         SENF_LOG_CLASS_AREA();
615     public:
616         ///////////////////////////////////////////////////////////////////////////
617         // Types
618
619         typedef boost::shared_ptr<SimpleCommandNode> ptr;
620         typedef boost::shared_ptr<SimpleCommandNode const> cptr;
621         typedef boost::weak_ptr<SimpleCommandNode> weak_ptr;
622
623         typedef boost::function<void (std::ostream &, ParseCommandInfo const &)> Function;
624
625         typedef SimpleCommandNode node_type;
626         typedef SimpleCommandNode & return_type;
627
628         ///////////////////////////////////////////////////////////////////////////
629         ///\name Structors and default members
630         ///\{
631
632         static ptr create(Function const & fn);
633
634         ///\}
635         ///////////////////////////////////////////////////////////////////////////
636
637         ptr thisptr();
638         cptr thisptr() const;
639
640         SimpleCommandNode & doc(std::string const & doc);
641
642     protected:
643         SimpleCommandNode(Function const & fn);
644
645     private:
646         virtual void v_help(std::ostream & output) const;
647         virtual void v_execute(std::ostream & output, ParseCommandInfo const & command) const;
648         
649
650         Function fn_;
651         std::string doc_;
652     };
653
654 #ifndef DOXYGEN
655
656     SimpleCommandNode & senf_console_add_node(DirectoryNode & node, std::string const & name, 
657                                               SimpleCommandNode::Function fn, int);
658
659 #endif
660
661 }}
662
663 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
664
665 BOOST_TYPEOF_REGISTER_TYPE(senf::console::DirectoryNode)
666 BOOST_TYPEOF_REGISTER_TYPE(senf::console::SimpleCommandNode)
667
668
669 ///////////////////////////////hh.e////////////////////////////////////////
670 #include "Node.cci"
671 #include "Node.ct"
672 #include "Node.cti"
673 #endif
674
675 \f
676 // Local Variables:
677 // mode: c++
678 // fill-column: 100
679 // comment-column: 40
680 // c-file-style: "senf"
681 // indent-tabs-mode: nil
682 // ispell-local-dictionary: "american"
683 // compile-command: "scons -u test"
684 // End: