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