X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Console%2FNode.hh;h=939113b4210fd00d72bbaaeab957335723648660;hb=9e7071473642404359c8b7a88c78fe02f00baf16;hp=961a1b8bc38867a7a14fae0cf1bb14a6f5c030d9;hpb=30c1daf8a1c404209210f76a9a54bcfde443603b;p=senf.git diff --git a/Console/Node.hh b/Console/Node.hh index 961a1b8..939113b 100644 --- a/Console/Node.hh +++ b/Console/Node.hh @@ -23,7 +23,7 @@ /** \file \brief Node public header */ -/** \defgroup node_tree The console/config file-system node tree +/** \defgroup node_tree The node tree The console/config node tree is the central data-structure of the library. Into this tree, all commands and parameters are entered. The tree is then exposed using a file-system like @@ -38,7 +38,7 @@ \code // Define callback function. - void mycommand(std::ostream & os, senf::console::Arguments const & args) + void mycommand(std::ostream & os, senf::console::ParseCommandInfo const & command) { // ... os << "!! Important message ...\n"; @@ -61,7 +61,7 @@ .doc("Do the member operation"); } - void member(std::ostream & os, senf::console::Arguments const & args) + void member(std::ostream & os, senf::console::ParseCommandInfo const & command) { // ... } @@ -117,13 +117,14 @@ \li An arbitrary node can be created and then (possibly later) added to the tree using the corresponding senf::console::DirectoryNode::add() overload. \li A senf::console::CommandNode is normally added to the tree by directly adding a callback - using one of the overloaded senf::console::DirectoryNode::add() members. + using one of the overloaded senf::console::DirectoryNode::add() members. See \ref + console_commands. When directly adding a node callback, the type of node added depends on the type of callback. The callback types which can be added are listed at \ref console_callbacks. \code - void callback(std::ostream & os, senf::console::Arguments const & args) { ... } + void callback(std::ostream & os, senf::console::ParseCommandInfo const & command) { ... } // ... myDirectory.add("foo",&callback); \endcode @@ -132,8 +133,9 @@ adding the node to the tree. If the name is empty or non-unique, a unique name will be automatically provided. - To remove a node from the tree, just use the nodes senf::console::GenericNode::unlink() - member. This call removes the node from it's parent and returns a (smart) node pointer. + To remove a node from the tree, just use the nodes senf::console::GenericNode::unlink() or the + parents senf::console::DirectoryNode::remove() member. This call removes the node from it's + parent and returns a (smart) node pointer. \li If you ignore the return value, the node (and it's children) will be deleted. \li Alternatively, you may store away the node and re-attach it later. @@ -142,7 +144,7 @@ \li To rename a node, unlink and re-add it with a different name. \code - myDirectory.add("bar", myDirectory("foo").unlink()); + myDirectory.add("bar", myDirectory.remove("foo")); \endcode \subsection console_node_param Assigning additional node parameters @@ -168,11 +170,14 @@ Another possibility is to traverse the tree explicitly. For this purpose, the operators '[]' and '()' have been overloaded in senf::console::DirectoryNode. \code + senf::console::root().getDirectory("myDirectory").getCommand("foo") + \\ or more concise but otherwise completely identical senf::console::root()["myDirectory"]("foo") \endcode - The '[]' operator will return a senf::console::DirectoryNode whereas '()' will return a - senf::console::CommandNode. If the node is not found or is not of the correct type, an exception - will be raised. + + getDirectory and the '[]' operator will return a senf::console::DirectoryNode whereas getCommand + and the '()' operator will return a senf::console::CommandNode. If the node is not found or is + not of the correct type, an exception will be raised. \section console_object_dir Assigning a directory to an object instance @@ -201,19 +206,21 @@ #include "../Utils/Exception.hh" #include "../Utils/mpl.hh" #include "../Utils/Logger/SenfLog.hh" +#include "../Utils/type_traits.hh" #include "Parse.hh" //#include "Node.mpp" ///////////////////////////////hh.p//////////////////////////////////////// -#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() - namespace senf { namespace console { + class LinkNode; class DirectoryNode; class CommandNode; + DirectoryNode & root(); + /** \brief Config/console node tree base-class GenericNode is the base class of all node objects. There are two basic node types derived @@ -255,6 +262,10 @@ namespace console { std::string path() const; ///< Node path /**< The node path is built by joining the names of all parent nodes with '/' chars. */ + std::string path(DirectoryNode const & root) const; + ///< Node path up to \a root + /**< The node path is built by joining the names of all + parent nodes up to \a root with '/' chars. */ ptr unlink(); ///< Remove node from it's parent directory /**< You may either discard the return value and thereby @@ -268,6 +279,20 @@ namespace console { ptr thisptr(); ///< Get smart pointer to node cptr thisptr() const; ///< Get smart pointer to node (const) + bool isChildOf(DirectoryNode & parent) const; + ///< \c true, if node is a child of \a parent + /**< Will also return \c true, if \a parent is the current + node. */ + + bool operator== (GenericNode & other) const; + /// \c true, if this and \a other are the same node + bool operator!= (GenericNode & other) const; + /// \c true, if this and \a other are different nodes + + bool isDirectory() const; ///< \c true, if this is a drectory node + bool isLink() const; ///< \c true, if this is a link node + bool isCommand() const; ///< \c true, if this is a command node + protected: GenericNode(); @@ -290,6 +315,47 @@ namespace console { friend class DirectoryNode; }; + /** \brief Config/console tree link node + + A LinkNode references another node and provides an additional alias name for that node. A + LinkNode works like a mixture of UNIX symlinks and hardlinks: It is an explicit link like a + UNIX symlink but references another node directly (not via it's path) like a UNIX + hardlink. Therefore, a LinkNode works across chroot(). + */ + class LinkNode + : public GenericNode + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + typedef boost::shared_ptr ptr; + typedef boost::shared_ptr cptr; + typedef boost::weak_ptr weak_ptr; + + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + static ptr create(GenericNode & node); ///< Create new link node. + /**< You should normally use DirectoryNode::link() to + create a link node. */ + + ///@} + /////////////////////////////////////////////////////////////////////////// + + GenericNode & follow() const; ///< Access the referenced node + + protected: + + private: + explicit LinkNode(GenericNode & node); + + virtual void v_help(std::ostream &) const; + + GenericNode::ptr node_; + }; + class SimpleCommandNode; /** \brief Internal: Node creation helper traits @@ -303,15 +369,17 @@ namespace console { typedef BOOST_TYPEOF_TPL( senf_console_add_node( * static_cast(0), * static_cast(0), - * static_cast(0), - 0) ) result_type; + * static_cast(0), + 0) ) base_type; + typedef typename senf::remove_cvref::type value_type; - typedef typename boost::remove_reference::type NodeType; + typedef typename value_type::node_type NodeType; + typedef typename value_type::return_type result_type; /// Internal struct Creator { - static NodeType & create(DirectoryNode & node, std::string const & name, - Object const & ob); + static result_type create(DirectoryNode & node, std::string const & name, + Object & ob); }; }; @@ -351,6 +419,9 @@ namespace console { typedef boost::iterator_range ChildrenRange; typedef ChildMap::const_iterator child_iterator; + typedef DirectoryNode node_type; + typedef DirectoryNode & return_type; + /////////////////////////////////////////////////////////////////////////// ///\name Structors and default members ///\{ @@ -374,7 +445,7 @@ namespace console { \a name is empty, it is set to 'unnamed'. */ template - typename NodeCreateTraits::NodeType & add (std::string const & name, + typename NodeCreateTraits::result_type add(std::string const & name, Object const & ob); ///< Generic child node factory /**< This member is used to create a new child node of the @@ -400,6 +471,12 @@ namespace console { is not used but serves to disambiguate the overloads). */ + template + typename NodeCreateTraits::result_type add(std::string const & name, + Object & ob); + ///< Generic child node factory + /**< \see add() */ + GenericNode::ptr remove(std::string const & name); ///< Remove node \a name from the tree /**< The returned pointer may either be discarded, which @@ -407,49 +484,66 @@ namespace console { be saved and/or re-attached at some other place in the tree. */ + bool hasChild(std::string const & name) const; + ///< \c true, if there is a child with name \a name + + GenericNode & get(std::string const & name) const; + ///< Get child node + /**< \throws UnknownNodeNameException if a child \a name + does not exist */ + GenericNode & getLink(std::string const & name) const; + ///< Get child node without dereferencing links + /**< \throws UnknownNodeNameException if a child \a name + does not exist */ + + DirectoryNode & getDirectory(std::string const & name) const; + ///< Get directory child node + /**< Same as operator[] + \throws UnknownNodeNameException if a child \a name + does not exist. + \throws std::bad_cast if the child \a name is not a + directory node. */ + DirectoryNode & operator[](std::string const & name) const; ///< Get directory child node - /**< \throws UnknownNodeNameException if a child \a name + /**< Same as getDirectory + \throws UnknownNodeNameException if a child \a name does not exist. \throws std::bad_cast if the child \a name is not a directory node. */ - CommandNode & operator()(std::string const & name) const; + CommandNode & getCommand(std::string const & name) const; ///< Get command child node - /**< \throws UnknownNodeNameException if a child \a name + /**< Same as operator() + \throws UnknownNodeNameException if a child \a name does not exist \throws std::bad_cast if the child \a name is not a command node. */ - GenericNode & get(std::string const & name) const; - ///< Get child node - /**< \throws UnknownNodeNameException if a child \a name - does not exist */ + CommandNode & operator()(std::string const & name) const; + ///< Get command child node + /**< Same as getCommand() + \throws UnknownNodeNameException if a child \a name + does not exist + \throws std::bad_cast if the child \a name is not a + command node. */ DirectoryNode & mkdir(std::string const & name); ///< Create sub-directory node - ChildrenRange children() const; - ///< Return iterator range over all children. + ChildrenRange children() const; ///< Return iterator range over all children. /**< The returned range is sorted by child name. */ - ///\} - /////////////////////////////////////////////////////////////////////////// + ChildrenRange completions(std::string const & s) const; + ///< Return iterator range of completions for \a s + /**< The returned range is sorted by child name. */ - template - GenericNode & traverse(ForwardRange const & range); - ///< Traverse node path starting at this node - /**< The FordwareRange::value_type must be - (convertible to) std::string. Each range element - constitutes a step along the node traversal. + void link(std::string const & name, GenericNode & target); - If the range starts with an empty element, the - traversal is started at the root() node, otherwise it - is started at \a this node. The traversal supports '.', - '..' and ignores further empty elements. */ + ///\} + /////////////////////////////////////////////////////////////////////////// - DirectoryNode & doc(std::string const & doc); - ///< Set node documentation + DirectoryNode & doc(std::string const & doc); ///< Set node documentation ptr thisptr(); cptr thisptr() const; @@ -467,8 +561,6 @@ namespace console { friend DirectoryNode & root(); }; - BOOST_TYPEOF_REGISTER_TYPE(DirectoryNode); - /// Exception: Unknown node name struct UnknownNodeNameException : public senf::Exception { UnknownNodeNameException() : senf::Exception("Unknown node name") {}}; @@ -479,20 +571,15 @@ namespace console { {}; #endif - struct SyntaxErrorException : public senf::Exception - { - explicit SyntaxErrorException(std::string const & msg = ""); - - virtual char const * what() const throw(); - }; - /** \brief Config/console tree command node The CommandNode is the base-class for the tree leaf nodes. Concrete command node implementations are derived from this class. - To execute a command, CommandNode::operator()() is called. This abstract virtual function - must be implemented in a derived class. + To execute a command, CommandNode::operator()() or CommandNode::execute() is called. + + Subclass instances of this node type are automatically created when adding commands to the + tree. See \ref console_commands. \ingroup node_tree */ @@ -507,16 +594,23 @@ namespace console { typedef boost::shared_ptr cptr; typedef boost::weak_ptr weak_ptr; - typedef ParseCommandInfo::ArgumentsRange Arguments; - /////////////////////////////////////////////////////////////////////////// - void operator()(std::ostream & output, Arguments const & arguments) const; + void execute(std::ostream & output, ParseCommandInfo const & command) const; ///< Execute the command - /**< \param[in] output stream where result messages may be + /**< Same as operator()() + \param[in] output stream where result messages may be + written to + \param[in] arguments command arguments. This is a + range of ranges of Token instances. */ + + void operator()(std::ostream & output, ParseCommandInfo const & command) const; + ///< Execute the command + /**< Same as execute() + \param[in] output stream where result messages may be written to \param[in] arguments command arguments. This is a - range of ranges of ArgumentToken instances. */ + range of ranges of Token instances. */ ptr thisptr(); cptr thisptr() const; @@ -527,24 +621,27 @@ namespace console { #ifndef DOXYGEN private: #endif - virtual void v_execute(std::ostream & output, Arguments const & arguments) const = 0; + virtual void v_execute(std::ostream & output, ParseCommandInfo const & command) const = 0; ///< Called to execute the command /**< \param[in] output stream where result messages may be written to \param[in] arguments command arguments. This is a - range of ranges of ArgumentToken instances. */ + range of ranges of Token instances. */ private: }; - typedef CommandNode::Arguments Arguments; - /** \brief Most simple CommandNode implementation This CommandNode implementation simply forwards the \a output and \a arguments arguments to - an arbitrary callback. + an arbitrary callback. Thus, it allows to add callbacks with the signature + \code + void callback(std::ostream & os, senf::console::ParseCommandInfo const & command) + { ... } + \endcode + to the tree. - \ingroup node_tree + \ingroup console_commands */ class SimpleCommandNode : public CommandNode { @@ -557,7 +654,10 @@ namespace console { typedef boost::shared_ptr cptr; typedef boost::weak_ptr weak_ptr; - typedef boost::function Function; + typedef boost::function Function; + + typedef SimpleCommandNode node_type; + typedef SimpleCommandNode & return_type; /////////////////////////////////////////////////////////////////////////// ///\name Structors and default members @@ -578,7 +678,7 @@ namespace console { private: virtual void v_help(std::ostream & output) const; - virtual void v_execute(std::ostream & output, Arguments const & arguments) const; + virtual void v_execute(std::ostream & output, ParseCommandInfo const & command) const; Function fn_; @@ -586,20 +686,23 @@ namespace console { }; #ifndef DOXYGEN - template + SimpleCommandNode & senf_console_add_node(DirectoryNode & node, std::string const & name, - Function const & fn, ...); + SimpleCommandNode::Function fn, int); + #endif - BOOST_TYPEOF_REGISTER_TYPE(SimpleCommandNode); +}} - DirectoryNode & root(); +#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() + +BOOST_TYPEOF_REGISTER_TYPE(senf::console::DirectoryNode) +BOOST_TYPEOF_REGISTER_TYPE(senf::console::SimpleCommandNode) -}} ///////////////////////////////hh.e//////////////////////////////////////// #include "Node.cci" -#include "Node.ct" +//#include "Node.ct" #include "Node.cti" #endif