4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
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.
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.
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.
24 \brief Node public header */
26 /** \defgroup node_tree The node tree
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
34 \section console_tree The tree
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.
40 // Define callback function.
41 void mycommand(std::ostream & os, senf::console::ParseCommandInfo const & command)
44 os << "!! Important message ...\n";
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;
54 SomeClass() : dir(this)
56 // You may document the directory here or later when adding it to the tree
57 dir.doc("Manager for something");
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");
64 void member(std::ostream & os, senf::console::ParseCommandInfo const & command)
72 // Provide global documentation
74 .doc("This is someServer server");
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 (
80 .doc("My server specific directory"));
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");
87 // Create a SomeClass instance and add it's directory.
89 mydir.add("someClass", someClass.dir);
91 // Start the interactive console server
92 senf::console::Server::start(senf::INet4SocketAddress(senf::INet4Address::None, 23232u))
97 \subsection console_nodes Node types
99 The console/config library tree consists of two basic node types:
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
104 senf::console::CommandNode is the base-class of all command nodes of which there are several,
105 depending on the type of command.
107 There is a single root node, the senf::console::DirectoryNode called senf::console::root(). From
108 this node, the tree is traversed.
110 All nodes are allocated on the heap and are managed using a smart pointer.
112 \subsection console_manipulate Manipulating the node tree
114 There are several ways to add nodes to the tree:
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
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.
127 void callback(std::ostream & os, senf::console::ParseCommandInfo const & command) { ... }
129 myDirectory.add("foo",&callback);
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.
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.
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.
147 myDirectory.add("bar", myDirectory.remove("foo"));
150 \subsection console_node_param Assigning additional node parameters
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:
158 myDirectory.add("foo",&fooCallback).doc("The foo method");
160 Since the parameter setters all return the node reference, additional parameters may just be
161 added to the end of the command.
163 \subsection console_tree_traverse Traversing the tree
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.
170 Another possibility is to traverse the tree explicitly. For this purpose, the operators '[]' and
171 '()' have been overloaded in senf::console::DirectoryNode.
173 senf::console::root().getDirectory("myDirectory").getCommand("foo")
174 \\ or more concise but otherwise completely identical
175 senf::console::root()["myDirectory"]("foo")
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.
182 \section console_object_dir Assigning a directory to an object instance
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.
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.
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"
212 //#include "Node.mpp"
213 ///////////////////////////////hh.p////////////////////////////////////////
221 DirectoryNode & root();
223 /** \brief Config/console node tree base-class
225 GenericNode is the base class of all node objects. There are two basic node types derived
226 from GenericNode: DirectoryNode and CommandNode.
228 All nodes are dynamically allocated and automatically managed using reference counting.
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).
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.
241 : public boost::enable_shared_from_this<GenericNode>
243 SENF_LOG_CLASS_AREA();
245 ///////////////////////////////////////////////////////////////////////////
248 typedef boost::shared_ptr<GenericNode> ptr;
249 typedef boost::shared_ptr<GenericNode const> cptr;
250 typedef boost::weak_ptr<GenericNode> weak_ptr;
252 ///////////////////////////////////////////////////////////////////////////
254 virtual ~GenericNode();
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 */
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. */
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(). */
274 bool active() const; ///< \c true, if node is attached to the root() node
276 void help(std::ostream & output) const; /// Write help info to \a output
278 ptr thisptr(); ///< Get smart pointer to node
279 cptr thisptr() const; ///< Get smart pointer to node (const)
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
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
294 void name(std::string const & name);
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. */
308 DirectoryNode * parent_;
310 friend class DirectoryNode;
313 class SimpleCommandNode;
315 /** \brief Internal: Node creation helper traits
317 This class is used internally to find out the type of node to create for a specific argument
320 template <class Object>
321 struct NodeCreateTraits
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),
328 typedef typename senf::remove_cvref<base_type>::type value_type;
330 typedef typename value_type::node_type NodeType;
331 typedef typename value_type::return_type result_type;
335 static result_type create(DirectoryNode & node, std::string const & name,
340 /** \brief Config/console tree directory node
342 This node type provides the internal and root nodes of the tree. It allows to add arbitrary
343 children and supports directory traversal.
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.
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
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.
361 class DirectoryNode : public GenericNode
363 SENF_LOG_CLASS_AREA();
364 typedef std::map<std::string, GenericNode::ptr> ChildMap;
366 ///////////////////////////////////////////////////////////////////////////
369 typedef boost::shared_ptr<DirectoryNode> ptr;
370 typedef boost::shared_ptr<DirectoryNode const> cptr;
371 typedef boost::weak_ptr<DirectoryNode> weak_ptr;
373 typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
374 typedef ChildMap::const_iterator child_iterator;
376 typedef DirectoryNode node_type;
377 typedef DirectoryNode & return_type;
379 ///////////////////////////////////////////////////////////////////////////
380 ///\name Structors and default members
383 static ptr create(); ///< Create node object.
384 /**< You should normally use either mkdir() or
385 ScopedDirectory instead of create() */
388 ///////////////////////////////////////////////////////////////////////////
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'. */
401 template <class Object>
402 typename NodeCreateTraits<Object>::result_type add(std::string const & name,
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.
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.
415 MyNodeType & senf_console_add_node(
417 std::string const & name,
418 MySpecialObject const & ob,
421 return dir.add(name, MyNodeType::create(ob));
424 (Do not forget the last unnamed 'int' parameter which
425 is not used but serves to disambiguate the
428 template <class Object>
429 typename NodeCreateTraits<Object>::result_type add(std::string const & name,
431 ///< Generic child node factory
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
441 bool hasChild(std::string const & name) const;
442 ///< \c true, if there is a child with name \a name
444 GenericNode & get(std::string const & name) const;
446 /**< \throws UnknownNodeNameException if a child \a name
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
454 \throws std::bad_cast if the child \a name is not a
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
462 \throws std::bad_cast if the child \a name is not a
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
470 \throws std::bad_cast if the child \a name is not a
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
478 \throws std::bad_cast if the child \a name is not a
481 DirectoryNode & mkdir(std::string const & name);
482 ///< Create sub-directory node
484 ChildrenRange children() const; ///< Return iterator range over all children.
485 /**< The returned range is sorted by child name. */
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. */
492 ///////////////////////////////////////////////////////////////////////////
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.
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.
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. */
511 DirectoryNode & doc(std::string const & doc);
512 ///< Set node documentation
515 cptr thisptr() const;
521 void add(GenericNode::ptr node);
522 virtual void v_help(std::ostream & output) const;
527 friend DirectoryNode & root();
530 /// Exception: Unknown node name
531 struct UnknownNodeNameException : public senf::Exception
532 { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
535 template <class Type>
536 struct NodeCreateTraits< boost::shared_ptr<Type> >
540 /** \brief Config/console tree command node
542 The CommandNode is the base-class for the tree leaf nodes. Concrete command node
543 implementations are derived from this class.
545 To execute a command, CommandNode::operator()() or CommandNode::execute() is called.
547 Subclass instances of this node type are automatically created when adding commands to the
548 tree. See \ref console_commands.
552 class CommandNode : public GenericNode
554 SENF_LOG_CLASS_AREA();
556 ///////////////////////////////////////////////////////////////////////////
559 typedef boost::shared_ptr<CommandNode> ptr;
560 typedef boost::shared_ptr<CommandNode const> cptr;
561 typedef boost::weak_ptr<CommandNode> weak_ptr;
563 ///////////////////////////////////////////////////////////////////////////
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
570 \param[in] arguments command arguments. This is a
571 range of ranges of ArgumentToken instances. */
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
578 \param[in] arguments command arguments. This is a
579 range of ranges of ArgumentToken instances. */
582 cptr thisptr() const;
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
594 \param[in] arguments command arguments. This is a
595 range of ranges of ArgumentToken instances. */
600 /** \brief Most simple CommandNode implementation
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
605 void callback(std::ostream & os, senf::console::ParseCommandInfo const & command)
610 \ingroup console_commands
612 class SimpleCommandNode : public CommandNode
614 SENF_LOG_CLASS_AREA();
616 ///////////////////////////////////////////////////////////////////////////
619 typedef boost::shared_ptr<SimpleCommandNode> ptr;
620 typedef boost::shared_ptr<SimpleCommandNode const> cptr;
621 typedef boost::weak_ptr<SimpleCommandNode> weak_ptr;
623 typedef boost::function<void (std::ostream &, ParseCommandInfo const &)> Function;
625 typedef SimpleCommandNode node_type;
626 typedef SimpleCommandNode & return_type;
628 ///////////////////////////////////////////////////////////////////////////
629 ///\name Structors and default members
632 static ptr create(Function const & fn);
635 ///////////////////////////////////////////////////////////////////////////
638 cptr thisptr() const;
640 SimpleCommandNode & doc(std::string const & doc);
643 SimpleCommandNode(Function const & fn);
646 virtual void v_help(std::ostream & output) const;
647 virtual void v_execute(std::ostream & output, ParseCommandInfo const & command) const;
656 SimpleCommandNode & senf_console_add_node(DirectoryNode & node, std::string const & name,
657 SimpleCommandNode::Function fn, int);
663 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
665 BOOST_TYPEOF_REGISTER_TYPE(senf::console::DirectoryNode)
666 BOOST_TYPEOF_REGISTER_TYPE(senf::console::SimpleCommandNode)
669 ///////////////////////////////hh.e////////////////////////////////////////
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"