// $Id$ // // Copyright (C) 2008 // Fraunhofer Institute for Open Communication Systems (FOKUS) // Competence Center NETwork research (NET), St. Augustin, GERMANY // Stefan Bund // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the // Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \mainpage The Configuration and Runtime Control Framework The Console library implements a runtime interactive (network) console which allows to configure, control and manipulate a running application in any way. Additionally this library provides support for configuration files and command line parsing which can be used with or without the network console. \section console_intro Introduction There are two components to the Config/console framework: \li Building the node tree by registering objects and callbacks \li Utilizing the config/console framework by writing configuration files or using the interactive console. Basic data structure of the console and config framework is the config/console node tree. This tree. This tree works like a file-system. Commands are added to this tree and can then be called from configuration files or from the interactive console. To get started using the config/console library, see \li \ref node_tree \li \ref console_parser \li \ref console_commands \section console_example Example The following example shows a \e very short summary on how to integrate the config/console library. See above links for more: \code // Define callback function. void mycommand(std::ostream & os, senf::console::ParseCommandInfo const & command) { // ... os << "!! Important message ...\n"; } int main(int, char**) { // Provide global documentation senf::console::root() .doc("This is someServer server"); // Add a command senf::console::root() .add("mycommand", &mycommand) .doc("mycommand []\n\n" "If is given, flurgle the , otherwise burgle it"); // Start the interactive console server senf::console::Server::start(senf::INet4SocketAddress(senf::INet4Address::None, 23232u)) .name("someServer"); } \endcode after this registration, the console can be accessed easily via telnet:
    $ telnet localhost 23232
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'
    xxxx-xx-xx xx:xx:xx.xxxxxx-0000 [NOTICE][senf::console::Server] Registered new client 0xxxxxxx
    someServer:/# ls
    mycommand
    someServer:/# mycommand
    !! Important message  ...
    someServer:/# exit
    xxxx-xx-xx xx:xx:xx.xxxxxx-0000 [NOTICE][senf::console::Server] Disposing client 0xxxxxxx
    Connection closed by foreign host.
    $
    
*/ /** \defgroup console_commands Supported command types The Console/config library supports quite a number of different command types. All these types of command are registered, by passing them to DirectoryNode::add() \autotoc \section console_manualparse Manually parsing command arguments This is the most primitive type of command. It will be called with an output stream and with a senf::console::ParseCommandInfo reference which holds information about the command parsed. From this information the command callback gets a list of arguments or tokens which then can be interpreted in an arbitrary way. \code void test1(std::ostream & os, senf::console::ParseCommandInfo const & command) { // We take exactly one argument if (command.arguments().size() != 1) raise senf::console::SyntaxErrorException("invalid number of arguments"); senf::console::ParseCommandInfo::TokenRange & argTokens ( command.arguments()[0]); // The argument must have exactly one token if (argTokens.size() != 1) raise senf::console::SyntaxErrorException("argument syntax error"); // Retrieve the token value std::string arg (argTokens[0].value()); // In this example, we just write the argument to the output stream os << arg << std::endl; } \endcode Registering this callback is done by simply adding it. To provide online help, pass it to 'doc()': \code senf::console::root() .add("test1", &test1) .doc("Usage:\n" " test1 arg\n" "\n" "Echo 'arg' to the console"); \endcode The callback may now be called interactively on the console by it's registered name: \htmlonly
    server:/$ test1
    invalid number of arguments
    server:/$ test1 stefan@j32.de
    stefan@j32.de
    server:/$ test1 (echo me)
    argument syntax error
    server:/$ help test1
    Usage:
        test1 arg

    Echo 'arg' to the console
    server:/$
    
\endhtmlonly As you can see above, the arguments and tokens are returned as boost::iterator_range instances. These behave much like containers: They have \c begin() and \c end() and some other useful members. The parser will have divided the argument tokens into arguments already. This simplifies further parsing. If however you want to access the list of argument tokens as a single list, you can do so using senf::console::ParseCommandInfo::tokens(). Parsing arguments is quite simple but can get very tedious. To simplify this task, the parsing can be delegated to the Console/config library. See the next section. \section console_autoparse Automatic argument parsing To greatly simplify parsing complex commands, we turn to automatic argument parsing. This feature allows to register (almost) arbitrary callbacks. \code std::string test2(std::string const & arg) { return arg; } \endcode This extremely simple callback may be registered by adding it to a senf::console::DirectoryNode. \code senf::console::root() .add("test2", &test2); \endcode The functionality is now identical to \c test1: \htmlonly
    server:/$ test2
    invalid number of arguments
    server:/$ test2 stefan@j32.de
    stefan@j32.de
    server:/$ test2 (echo me)
    argument syntax error
    server:/$ help test2
    Usage:
        test2 arg11:string
    server:/$
    
\endhtmlonly As we can see, some documentation is automatically provided. To add more info, we need to add some additional attributes when registering the command: \code namespace kw = senf::console::kw; senf::console::root() .add("test2", &test2) .doc("Echo 'arg' to the console") .arg( kw::name = "arg", kw::description = "Message to output" ); \endcode (Sadly, there is no way to automatically find out the \e name of an argument, just it's type.) Every callback argument corresponds with a call of the \c arg() attribute. Argument attributes are set using keywords from the \ref senf::console::kw namespace. You will probably wither use this namespace via a namespace alias (as above) or via a using namespace senf::console::kw declaration (as in all the following examples) You don't need to specify any information for an argument: To skip an argument, just call \c arg() without attributes for this argument. After adding this information, the online help is much more intelligible \htmlonly
    server:/$ help test2
    Usage:
        test2 arg:string

    With:
        arg       Message to output

    Echo 'arg' to the console
    server:/$
    
\endhtmlonly \subsection command_ostream Accessing the console stream Commands may have an optional first argument of type std::ostream &. This argument is not considered part of the real interface. When the command is executed, the callback will be passed the current console's output stream object in this argument. With this, the callback can output arbitrary messages to the network console. See the next section for an example. \subsection command_overload Command overloading Automatically parsed commands can be overloaded: You can register multiple commands under the same name. If this happens, each command is tried in turn until no SyntaxErrorException is raised. \code void test3(std::ostream & os, unsigned n, std::string text) { // It's perfectly valid to check additional constraints here and throw a // SyntaxErrorException. In this case, the next overload will be tried. However, you must // ensure, That no action takes place before this check ! if ( n==0 ) throw senf::console::SyntaxErrorException("invalid value for parameter 'n'"); while (n-- > 0) os << text << std::endl; } using namespace senf::console::kw; senf::console::root() .add("test3", &test3) .doc("Echo text to the console") .overloadDoc("Repeat 'text' for 'n' lines") .arg( name = "n", description = "Number of repetitions" ) .arg( name = "text", description = "Message to output" ); senf::console::root() .add("test3", &test2) .overloadDoc("Echo the 'text' argument") .arg( name = "text", description = "Message to output" ); \endcode We can now call \c test2 with one or two arguments: \htmlonly
    server:/$ test3 "The sky is blue"
    The sky is blue
    server:/$ test3 4 ok
    ok
    ok
    ok
    ok
    server:/$ help test3
    Usage:
        1- test3 n:unsigned text:string
        2- test3 text:string
    
    With:
        n         Numer of repetitions
        text      Messsage to output

    Echo text to the console

    Variant 1:
    Repeat 'text' for 'n' lines
    
    Variant 2:
    Echo the 'text' argument
    senf:/$    And 

    
\endhtmlonly \subsection console_defaults Default values Another information which can not be automatically gathered from the type system is default values. These have to be explicitly declared: \code using namespace senf::console::kw; senf::console::root() .add("test4", &test2b) .arg() .arg( default_value = "ok" ); \endcode (Default values must not necessarily be declared in the callback function too.) Of course, default values can be used together with overloading. There must be no argument without default value after an argument with a default value declared. This fill fail at compile time. \subsection console_auto_summary Attribute summary Here a summary of all the attributes available for automatically parsed command nodes:
\c doc ( \e text )Documentation for all overloads
\c overloadDoc ( \e text )Documentation for a specific overliad
\c arg ( \e attributes )Set parameter attributes. All attributes are optional. The attribute keywords are defined in the \ref senf::console::kw namespace. Valid Attributes are: \li \e name: Parameter name \li \e description: One-line description of the argument \li \e default_value: Arguments default value
See senf::console::ParsedArgumentAttributor 'List of all members' \section console_memberfn Registering member functions Member functions are supported like non-member functions. They must however be added through a senf::console::ScopedDirectory instance to bind them to their instance. \code class Test { public: senf::console::ScopedDirectory dir; Test(std::string label) : dir(this), label_ (label) { dir.add("test4", &Test::test2); dir.add("test4", &Test::test3); } std::string test2(std::string const & text) { return label_ + ": " + text; } void test3(std::ostream & os, unsigned n, std::string const & text) { while (n-- > 0) os << label << ": " << text << std::endl; } private: std::string label_; }; // ... Test testOb ("test"); senf::console::root().add("testobj", testOb.dir); \endcode Binding via senf::console::ScopedDirectory ensures, that the commands are automatically removed from the tree when the object is destroyed. */ // Local Variables: // mode: c++ // fill-column: 100 // comment-column: 40 // c-file-style: "senf" // indent-tabs-mode: nil // ispell-local-dictionary: "american" // compile-command: "scons -u test" // mode: auto-fill // End: