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 console/config file-system 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::Arguments const & args)
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::Arguments const & args)
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.
122 When directly adding a node callback, the type of node added depends on the type of
123 callback. The callback types which can be added are listed at \ref console_callbacks.
126 void callback(std::ostream & os, senf::console::Arguments const & args) { ... }
128 myDirectory.add("foo",&callback);
131 Every node is identified among it's siblings by it's name. The name of the node is set when
132 adding the node to the tree. If the name is empty or non-unique, a unique name will be
133 automatically provided.
135 To remove a node from the tree, just use the nodes senf::console::GenericNode::unlink()
136 member. This call removes the node from it's parent and returns a (smart) node pointer.
138 \li If you ignore the return value, the node (and it's children) will be deleted.
139 \li Alternatively, you may store away the node and re-attach it later.
140 \li An node (or subtree) can be moved to a different place by unlinking the node at it's old
141 place and re-adding it at it's new location.
142 \li To rename a node, unlink and re-add it with a different name.
145 myDirectory.add("bar", myDirectory("foo").unlink());
148 \subsection console_node_param Assigning additional node parameters
150 Depending on the node type added, additional node parameters may be set. For example, every node
151 has a documentation parameter which is used by the online-help system. To assign these
152 parameters, the node exposes corresponding member functions. Since
153 senf::console::DirectoryNode::add() returns the newly added node by reference, additional
154 parameters may just be added to the end of the add command:
156 myDirectory.add("foo",&fooCallback).doc("The foo method");
158 Since the parameter setters all return the node reference, additional parameters may just be
159 added to the end of the command.
161 \subsection console_tree_traverse Traversing the tree
163 The simplest way to access tree elements is to save the return value of the
164 senf::console::DirectoryNode::add() members. However, saving the reference will not ensure, that
165 the node is not removed. If the node might be removed from the tree, you should use a smart
166 pointer (either <tt>ptr</tt> or <tt>weak_ptr</tt>) to hold the node.
168 Another possibility is to traverse the tree explicitly. For this purpose, the operators '[]' and
169 '()' have been overloaded in senf::console::DirectoryNode.
171 senf::console::root()["myDirectory"]("foo")
173 The '[]' operator will return a senf::console::DirectoryNode whereas '()' will return a
174 senf::console::CommandNode. If the node is not found or is not of the correct type, an exception
177 \section console_object_dir Assigning a directory to an object instance
179 Most objects will register several commands. So it makes sense for these objects to manage their
180 own directory. Since directories are however allocated on the heap, they cannot be directly
181 added to a class. To facilitate this usage, the senf::console::ScopedDirectory is used. This
182 class provides a senf::console::DirectoryNode facade. Internally, it automatically creates a
183 senf::console::DirectoryNode to which all calls are forwarded.
185 The senf::console::ScopedDirectory member should be declared public. This allows the user of the
186 class to add the node to the tree.
194 #include <boost/shared_ptr.hpp>
195 #include <boost/weak_ptr.hpp>
196 #include <boost/enable_shared_from_this.hpp>
197 #include <boost/utility.hpp>
198 #include <boost/range/iterator_range.hpp>
199 #include <boost/typeof/typeof.hpp>
200 #include <boost/type_traits/remove_reference.hpp>
201 #include "../Utils/Exception.hh"
202 #include "../Utils/mpl.hh"
203 #include "../Utils/Logger/SenfLog.hh"
206 //#include "Node.mpp"
207 ///////////////////////////////hh.p////////////////////////////////////////
209 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
217 /** \brief Config/console node tree base-class
219 GenericNode is the base class of all node objects. There are two basic node types derived
220 from GenericNode: DirectoryNode and CommandNode.
222 All nodes are dynamically allocated and automatically managed using reference counting.
224 All nodes are normally linked into a single tree which root node is
225 senf::console::root(). Nodes may however be orphaned (not linked to the tree) either
226 directly (the node has no parent) or indirectly (the node has a parent but is part of an
227 orphaned subtree which is not linked to the root node).
229 Every active (non-orphaned) node (except the root() node) has a non-empty node name. This
230 name is assigned to the node when adding the node to the tree.
235 : public boost::enable_shared_from_this<GenericNode>
237 SENF_LOG_CLASS_AREA();
239 ///////////////////////////////////////////////////////////////////////////
242 typedef boost::shared_ptr<GenericNode> ptr;
243 typedef boost::shared_ptr<GenericNode const> cptr;
244 typedef boost::weak_ptr<GenericNode> weak_ptr;
246 ///////////////////////////////////////////////////////////////////////////
248 virtual ~GenericNode();
250 std::string const & name() const; ///< Node name
251 boost::shared_ptr<DirectoryNode> parent() const; ///< Parent node
252 /**< May be null, if the node is the root node or if it is
253 not linked to the tree */
255 std::string path() const; ///< Node path
256 /**< The node path is built by joining the names of all
257 parent nodes with '/' chars. */
259 ptr unlink(); ///< Remove node from it's parent directory
260 /**< You may either discard the return value and thereby
261 dispose the node or may re-attach the node at some
262 other place using DirectoryNode::add(). */
264 bool active() const; ///< \c true, if node is attached to the root() node
266 void help(std::ostream & output) const; /// Write help info to \a output
268 ptr thisptr(); ///< Get smart pointer to node
269 cptr thisptr() const; ///< Get smart pointer to node (const)
274 void name(std::string const & name);
281 virtual void v_help(std::ostream & output) const = 0;
282 ///< Provide help information
283 /**< This member must be implemented in derived classes
284 to provide node specific help information. */
288 DirectoryNode * parent_;
290 friend class DirectoryNode;
293 class SimpleCommandNode;
295 /** \brief Internal: Node creation helper traits
297 This class is used internally to find out the type of node to create for a specific argument
300 template <class Object>
301 struct NodeCreateTraits
303 typedef BOOST_TYPEOF_TPL( senf_console_add_node(
304 * static_cast<DirectoryNode *>(0),
305 * static_cast<std::string const *>(0),
306 * static_cast<Object const *>(0),
309 typedef typename boost::remove_reference<result_type>::type NodeType;
313 static NodeType & create(DirectoryNode & node, std::string const & name,
318 /** \brief Config/console tree directory node
320 This node type provides the internal and root nodes of the tree. It allows to add arbitrary
321 children and supports directory traversal.
323 Nodes are normally not instantiated manually but are created by the DirectoryNode via
324 mkdir() or add(). Special add() members however allow externally allocated node objects.
326 Nodes may be added to the tree only once, otherwise chaos will ensue. Since nodes are always
327 managed dynamically, there is a special ScopedDirectory proxy template which provides a
328 DirectoryNode facade. ScopedDirectory is used if a class wants to manage it's own directory
331 Every node is assigned a (new) name when it is added to a directory. If the directory
332 already has an entry of that name, the name is made unique by appending a suffix of the form
333 '-n' where n is a number starting at 1. If the name is empty, int is set to 'unnamed' and
334 then uniquified as above. Automatically providing unique names simplifies adding
335 configuration/console support to generic components.
339 class DirectoryNode : public GenericNode
341 SENF_LOG_CLASS_AREA();
342 typedef std::map<std::string, GenericNode::ptr> ChildMap;
344 ///////////////////////////////////////////////////////////////////////////
347 typedef boost::shared_ptr<DirectoryNode> ptr;
348 typedef boost::shared_ptr<DirectoryNode const> cptr;
349 typedef boost::weak_ptr<DirectoryNode> weak_ptr;
351 typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
352 typedef ChildMap::const_iterator child_iterator;
354 ///////////////////////////////////////////////////////////////////////////
355 ///\name Structors and default members
358 static ptr create(); ///< Create node object.
359 /**< You should normally use either mkdir() or
360 ScopedDirectory instead of create() */
363 ///////////////////////////////////////////////////////////////////////////
367 template <class NodeType>
368 NodeType & add(std::string const & name, boost::shared_ptr<NodeType> node);
369 ///< Add node to tree
370 /**< Adds the \a node to the tree as a child of \a this
371 node. The node is given the name \a name. If a node of
372 that name already exists, a numeric suffix of the form
373 '-n' is added to the name until the name is unique. If
374 \a name is empty, it is set to 'unnamed'. */
376 template <class Object>
377 typename NodeCreateTraits<Object>::NodeType & add (std::string const & name,
379 ///< Generic child node factory
380 /**< This member is used to create a new child node of the
381 current directory. The type of node created depends on
382 the type of argument passed.
384 The node type is selected by the NodeCreateTraits
385 class. To allow adding a specific node type, you need
386 to provide an overload for
387 <tt>senf_console_add_node</tt> which must be visible at
388 when you register the new node.
390 MyNodeType & senf_console_add_node(
392 std::string const & name,
393 MySpecialObject const & ob,
396 return dir.add(name, MyNodeType::create(ob));
399 (Do not forget the last unnamed 'int' parameter which
400 is not used but serves to disambiguate the
403 GenericNode::ptr remove(std::string const & name);
404 ///< Remove node \a name from the tree
405 /**< The returned pointer may either be discarded, which
406 will automatically dispose the removed node, or it may
407 be saved and/or re-attached at some other place in the
410 DirectoryNode & operator[](std::string const & name) const;
411 ///< Get directory child node
412 /**< \throws UnknownNodeNameException if a child \a name
414 \throws std::bad_cast if the child \a name is not a
417 CommandNode & operator()(std::string const & name) const;
418 ///< Get command child node
419 /**< \throws UnknownNodeNameException if a child \a name
421 \throws std::bad_cast if the child \a name is not a
424 GenericNode & get(std::string const & name) const;
426 /**< \throws UnknownNodeNameException if a child \a name
429 DirectoryNode & mkdir(std::string const & name);
430 ///< Create sub-directory node
432 ChildrenRange children() const;
433 ///< Return iterator range over all children.
434 /**< The returned range is sorted by child name. */
437 ///////////////////////////////////////////////////////////////////////////
439 template <class ForwardRange>
440 GenericNode & traverse(ForwardRange const & range);
441 ///< Traverse node path starting at this node
442 /**< The <tt>FordwareRange::value_type</tt> must be
443 (convertible to) std::string. Each range element
444 constitutes a step along the node traversal.
446 If the range starts with an empty element, the
447 traversal is started at the root() node, otherwise it
448 is started at \a this node. The traversal supports '.',
449 '..' and ignores further empty elements. */
451 DirectoryNode & doc(std::string const & doc);
452 ///< Set node documentation
455 cptr thisptr() const;
461 void add(GenericNode::ptr node);
462 virtual void v_help(std::ostream & output) const;
467 friend DirectoryNode & root();
470 BOOST_TYPEOF_REGISTER_TYPE(DirectoryNode);
472 /// Exception: Unknown node name
473 struct UnknownNodeNameException : public senf::Exception
474 { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
477 template <class Type>
478 struct NodeCreateTraits< boost::shared_ptr<Type> >
482 struct SyntaxErrorException : public senf::Exception
484 explicit SyntaxErrorException(std::string const & msg = "");
486 virtual char const * what() const throw();
489 /** \brief Config/console tree command node
491 The CommandNode is the base-class for the tree leaf nodes. Concrete command node
492 implementations are derived from this class.
494 To execute a command, CommandNode::operator()() is called. This abstract virtual function
495 must be implemented in a derived class.
499 class CommandNode : public GenericNode
501 SENF_LOG_CLASS_AREA();
503 ///////////////////////////////////////////////////////////////////////////
506 typedef boost::shared_ptr<CommandNode> ptr;
507 typedef boost::shared_ptr<CommandNode const> cptr;
508 typedef boost::weak_ptr<CommandNode> weak_ptr;
510 typedef ParseCommandInfo::ArgumentsRange Arguments;
512 ///////////////////////////////////////////////////////////////////////////
514 void operator()(std::ostream & output, Arguments const & arguments) const;
515 ///< Execute the command
516 /**< \param[in] output stream where result messages may be
518 \param[in] arguments command arguments. This is a
519 range of ranges of ArgumentToken instances. */
522 cptr thisptr() const;
530 virtual void v_execute(std::ostream & output, Arguments const & arguments) const = 0;
531 ///< Called to execute the command
532 /**< \param[in] output stream where result messages may be
534 \param[in] arguments command arguments. This is a
535 range of ranges of ArgumentToken instances. */
540 typedef CommandNode::Arguments Arguments;
542 /** \brief Most simple CommandNode implementation
544 This CommandNode implementation simply forwards the \a output and \a arguments arguments to
545 an arbitrary callback.
549 class SimpleCommandNode : public CommandNode
551 SENF_LOG_CLASS_AREA();
553 ///////////////////////////////////////////////////////////////////////////
556 typedef boost::shared_ptr<SimpleCommandNode> ptr;
557 typedef boost::shared_ptr<SimpleCommandNode const> cptr;
558 typedef boost::weak_ptr<SimpleCommandNode> weak_ptr;
560 typedef boost::function<void (std::ostream &, Arguments const &)> Function;
562 ///////////////////////////////////////////////////////////////////////////
563 ///\name Structors and default members
566 static ptr create(Function const & fn);
569 ///////////////////////////////////////////////////////////////////////////
572 cptr thisptr() const;
574 SimpleCommandNode & doc(std::string const & doc);
577 SimpleCommandNode(Function const & fn);
580 virtual void v_help(std::ostream & output) const;
581 virtual void v_execute(std::ostream & output, Arguments const & arguments) const;
589 template <class Function>
590 SimpleCommandNode & senf_console_add_node(DirectoryNode & node, std::string const & name,
591 Function const & fn, ...);
594 BOOST_TYPEOF_REGISTER_TYPE(SimpleCommandNode);
596 DirectoryNode & root();
600 ///////////////////////////////hh.e////////////////////////////////////////
610 // comment-column: 40
611 // c-file-style: "senf"
612 // indent-tabs-mode: nil
613 // ispell-local-dictionary: "american"
614 // compile-command: "scons -u test"