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 */
31 #include <boost/shared_ptr.hpp>
32 #include <boost/weak_ptr.hpp>
33 #include <boost/enable_shared_from_this.hpp>
34 #include <boost/utility.hpp>
35 #include <boost/range/iterator_range.hpp>
36 #include <boost/typeof/typeof.hpp>
37 #include <boost/type_traits/remove_reference.hpp>
38 #include "../Utils/Exception.hh"
39 #include "../Utils/mpl.hh"
40 #include "../Utils/Logger/SenfLog.hh"
44 ///////////////////////////////hh.p////////////////////////////////////////
46 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
54 /** \brief Config/console node tree base-class
56 GenericNode is the base class of all node objects. There are two basic node types derived
57 from GenericNode: DirectoryNode and CommandNode.
59 All nodes are dynamically allocated and automatically managed using reference counting.
61 All nodes are normally linked into a single tree which root node is
62 senf::console::root(). Nodes may however be orphaned (not linked to the tree) either
63 directly (the node has no parent) or indirectly (the node has a parent but is part of an
64 orphaned subtree which is not linked to the root node).
66 Every active (non-orphaned) node (except the root() node) has a non-empty node name. This
67 name is assigned to the node when adding the node to the tree.
70 : public boost::enable_shared_from_this<GenericNode>
72 SENF_LOG_CLASS_AREA();
74 ///////////////////////////////////////////////////////////////////////////
77 typedef boost::shared_ptr<GenericNode> ptr;
78 typedef boost::shared_ptr<GenericNode const> cptr;
79 typedef boost::weak_ptr<GenericNode> weak_ptr;
81 ///////////////////////////////////////////////////////////////////////////
83 virtual ~GenericNode();
85 std::string const & name() const; ///< Node name
86 boost::shared_ptr<DirectoryNode> parent() const; ///< Parent node
87 /**< May be null, if the node is the root node or if it is
88 not linked to the tree */
90 std::string path() const; ///< Node path
91 /**< The node path is built by joining the names of all
92 parent nodes with '/' chars. */
94 ptr unlink(); ///< Remove node from it's parent directory
95 /**< You may either discard the return value and thereby
96 dispose the node or may re-attach the node at some
97 other place using DirectoryNode::add(). */
99 bool active() const; ///< \c true, if node is attached to the root() node
101 void help(std::ostream & output) const; /// Write help info to \a output
103 ptr thisptr(); ///< Get smart pointer to node
104 cptr thisptr() const; ///< Get smart pointer to node (const)
109 void name(std::string const & name);
116 virtual void v_help(std::ostream & output) const = 0;
117 ///< Provide help information
118 /**< This member must be implemented in derived classes
119 to provide node specific help information. */
123 DirectoryNode * parent_;
125 friend class DirectoryNode;
128 class SimpleCommandNode;
130 /** \brief Internal: Node creation helper traits
132 This class is used internally to find out the type of node to create for a specific argument
135 template <class Object>
136 struct NodeCreateTraits
138 typedef BOOST_TYPEOF_TPL( senf_console_add_node(
139 * static_cast<DirectoryNode *>(0),
140 * static_cast<std::string const *>(0),
141 * static_cast<Object const *>(0),
144 typedef typename boost::remove_reference<result_type>::type NodeType;
148 static NodeType & create(DirectoryNode & node, std::string const & name,
153 /** \brief Config/console tree directory node
155 This node type provides the internal and root nodes of the tree. It allows to add arbitrary
156 children and supports directory traversal.
158 Nodes are normally not instantiated manually but are created by the DirectoryNode via
159 mkdir() or add(). Special add() members however allow externally allocated node objects.
161 Nodes may be added to the tree only once, otherwise chaos will ensue. Since nodes are always
162 managed dynamically, there is a special ObjectDirectory proxy template which provides a
163 DirectoryNode facade. ObjectDirectory is used if a class wants to manage it's own directory
166 Every node is assigned a (new) name when it is added to a directory. If the directory
167 already has an entry of that name, the name is made unique by appending a suffix of the form
168 '-n' where n is a number starting at 1. If the name is empty, int is set to 'unnamed' and
169 then uniquified as above. Automatically providing unique names simplifies adding
170 configuration/console support to generic components.
172 class DirectoryNode : public GenericNode
174 SENF_LOG_CLASS_AREA();
175 typedef std::map<std::string, GenericNode::ptr> ChildMap;
177 ///////////////////////////////////////////////////////////////////////////
180 typedef boost::shared_ptr<DirectoryNode> ptr;
181 typedef boost::shared_ptr<DirectoryNode const> cptr;
182 typedef boost::weak_ptr<DirectoryNode> weak_ptr;
184 typedef boost::iterator_range<ChildMap::const_iterator> ChildrenRange;
185 typedef ChildMap::const_iterator child_iterator;
187 ///////////////////////////////////////////////////////////////////////////
188 ///\name Structors and default members
191 static ptr create(); ///< Create node object.
192 /**< You should normally use either mkdir() or
193 ObjectDirectory instead of create() */
196 ///////////////////////////////////////////////////////////////////////////
200 template <class NodeType>
201 NodeType & add(std::string const & name, boost::shared_ptr<NodeType> node);
202 ///< Add node to tree
203 /**< Adds the \a node to the tree as a child of \a this
204 node. The node is given the name \a name. If a node of
205 that name already exists, a numeric suffix of the form
206 '-n' is added to the name until the name is unique. If
207 \a name is empty, it is set to 'unnamed'. */
209 template <class Object>
210 typename NodeCreateTraits<Object>::NodeType & add (std::string const & name,
212 ///< Generic child node factory
213 /**< This member is used to create a new child node of the
214 current directory. The type of node created depends on
215 the type of argument passed.
217 The node type is selected by the NodeCreateTraits
218 class. To allow adding a specific node type, you need
219 to provide an overload for
220 <tt>senf_console_add_node</tt> which must be visible at
221 when you register the new node.
223 MyNodeType & senf_console_add_node(
225 std::string const & name,
226 MySpecialObject const & ob,
229 return dir.add(name, MyNodeType::create(ob));
232 (Do not forget the last unnamed 'int' parameter which
233 is not used but serves to disambiguate the
236 GenericNode::ptr remove(std::string const & name);
237 ///< Remove node \a name from the tree
238 /**< The returned pointer may either be discarded, which
239 will automatically dispose the removed node, or it may
240 be saved and/or re-attached at some other place in the
243 DirectoryNode & operator[](std::string const & name) const;
244 ///< Get directory child node
245 /**< \throws UnknownNodeNameException if a child \a name
247 \throws std::bad_cast if the child \a name is not a
250 CommandNode & operator()(std::string const & name) const;
251 ///< Get command child node
252 /**< \throws UnknownNodeNameException if a child \a name
254 \throws std::bad_cast if the child \a name is not a
257 GenericNode & get(std::string const & name) const;
259 /**< \throws UnknownNodeNameException if a child \a name
262 DirectoryNode & mkdir(std::string const & name);
263 ///< Create sub-directory node
265 ChildrenRange children() const;
266 ///< Return iterator range over all children.
267 /**< The returned range is sorted by child name. */
270 ///////////////////////////////////////////////////////////////////////////
272 template <class ForwardRange>
273 GenericNode & traverse(ForwardRange const & range);
274 ///< Traverse node path starting at this node
275 /**< The <tt>FordwareRange::value_type</tt> must be
276 (convertible to) std::string. Each range element
277 constitutes a step along the node traversal.
279 If the range starts with an empty element, the
280 traversal is started at the root() node, otherwise it
281 is started at \a this node. The traversal supports '.',
282 '..' and ignores further empty elements. */
284 DirectoryNode & doc(std::string const & doc);
285 ///< Set node documentation
288 cptr thisptr() const;
294 void add(GenericNode::ptr node);
295 virtual void v_help(std::ostream & output) const;
300 friend DirectoryNode & root();
303 BOOST_TYPEOF_REGISTER_TYPE(DirectoryNode);
305 /// Exception: Unknown node name
306 struct UnknownNodeNameException : public senf::Exception
307 { UnknownNodeNameException() : senf::Exception("Unknown node name") {}};
310 template <class Type>
311 struct NodeCreateTraits< boost::shared_ptr<Type> >
315 /** \brief Config/console tree command node
317 The CommandNode is the base-class for the tree leaf nodes. Concrete command node
318 implementations are derived from this class.
320 To execute a command, CommandNode::operator()() is called. This abstract virtual function
321 must be implemented in a derived class.
323 class CommandNode : public GenericNode
325 SENF_LOG_CLASS_AREA();
327 ///////////////////////////////////////////////////////////////////////////
330 typedef boost::shared_ptr<CommandNode> ptr;
331 typedef boost::shared_ptr<CommandNode const> cptr;
332 typedef boost::weak_ptr<CommandNode> weak_ptr;
334 typedef ParseCommandInfo::ArgumentsRange Arguments;
336 ///////////////////////////////////////////////////////////////////////////
338 virtual void operator()(std::ostream & output, Arguments const & arguments) = 0;
339 ///< Called to execute the command
340 /**< \param[in] output stream where result messages may be
342 \param[in] arguments command arguments. This is a
343 range of ranges of ArgumentToken instances. */
346 cptr thisptr() const;
354 /** \brief Most simple CommandNode implementation
356 This CommandNode implementation simply forwards the \a output and \a arguments arguments to
357 an arbitrary callback.
359 class SimpleCommandNode : public CommandNode
361 SENF_LOG_CLASS_AREA();
363 ///////////////////////////////////////////////////////////////////////////
366 typedef boost::shared_ptr<SimpleCommandNode> ptr;
367 typedef boost::shared_ptr<SimpleCommandNode const> cptr;
368 typedef boost::weak_ptr<SimpleCommandNode> weak_ptr;
370 typedef boost::function<void (std::ostream &, Arguments const &)> Function;
372 ///////////////////////////////////////////////////////////////////////////
373 ///\name Structors and default members
376 static ptr create(Function const & fn);
379 ///////////////////////////////////////////////////////////////////////////
381 virtual void operator()(std::ostream & output, Arguments const & arguments);
384 cptr thisptr() const;
386 SimpleCommandNode & doc(std::string const & doc);
389 SimpleCommandNode(Function const & fn);
392 virtual void v_help(std::ostream & output) const;
399 template <class Function>
400 SimpleCommandNode & senf_console_add_node(DirectoryNode & node, std::string const & name,
401 Function const & fn, ...);
404 BOOST_TYPEOF_REGISTER_TYPE(SimpleCommandNode);
406 DirectoryNode & root();
410 ///////////////////////////////hh.e////////////////////////////////////////
420 // comment-column: 40
421 // c-file-style: "senf"
422 // indent-tabs-mode: nil
423 // ispell-local-dictionary: "american"
424 // compile-command: "scons -u test"