Socket/Protocols/INet: Add 'shutdown' member to TCPSocketProtocol
[senf.git] / Console / Mainpage.dox
index 62cffd6..8226247 100644 (file)
@@ -51,6 +51,8 @@
     library. See above links for more:
 
     \code
+    #include <senf/Console.hh>
+
     // Define callback function.
     void mycommand(std::ostream & os, int foo, int bar)
     {
     $
     </pre>
 
+    \see \ref console_testserver for a complete example application
+
+    \section intro_init Initialization
+
+    To make the console accessible, it must be initialized when the program is started:
+    \code
+    #include <senf/Console.hh>
+
+    int main(int argc, char * argv [])
+    {
+        // Configure console nodes, add commands ...
+
+        // Start console server
+        senf::console::start(senf::INet4SocketAddress(12345u))
+           .name("myserver");
+
+        // You need to enter the scheduler main-loop for the server to work
+        senf::Scheduler::instance().process();
+       
+        // Alternatively enter the main-loop via the PPI
+        // senf::ppi::run();
+    }
+    \endcode
+
+    This will start the server on IPv4 port 12345. The servers name (as displayed in the interactive
+    console prompt) is set to 'myserver'.
+
+    After launching the application, the server can be accessed at the given port:
+    \htmlonly
+    <pre>
+    bash$ telnet localhost 12345
+    Trying 127.0.0.1...
+    Connected to localhost.
+    Escape character is '^]'.
+
+    myserver:/$ exit
+    Connection closed by foreign host.
+    bash$
+    </pre>
+    \endhtmlonly
 
     \section intro_nodes The node tree
 
     \see \ref node_tree
 
 
-    \section intro_commands Console/config commands
+    \section intro_commands Registering console/config commands
 
     The console/config language does not define, how arguments are passed to the commands, it just
     tokenizes the input and passes the tokens to the commands which then handle the
         if (command.arguments().size() != 1) 
             raise senf::console::SyntaxErrorException("invalid number of arguments");
 
-        senf::console::ParseCommandInfo::TokenRange & argTokens (
+        senf::console::ParseCommandInfo::TokensRange & argTokens (
             command.arguments()[0]);
 
         // The argument must have exactly one token
 
     Commands may have an optional first argument of type <tt>std::ostream &</tt>. 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
+    passed the current consoles output stream object in this argument. With this, the callback can
     output arbitrary messages to the network console.
     \code
     void fun3(std::ostream & os, unsigned n, std::string text)
     server:/$
     </pre>
 
+    One note: When taking the address of an overloaded function (member or non-member), the C++
+    language forces you to cast that address to one of the possible types so the compiler knows,
+    which overload is requested. So to add a function which is overloaded in C++, each overload
+    needs to be added explicitly, casting to the correct type:
+    \code
+    void over(int);
+    void over(int,int);
+
+    senf::console::root()
+        .add("over", static_cast<void (*)(int)>(&over));
+    senf::console::root()
+        .add("over", static_cast<void (*)(int,int)>(&over));
+    \endcode
+
+
     \subsection console_attributes Attributes
 
     As have seen so far, some documentation is automatically provided. We can add more info, by
     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 
+    class Test1
     {
     public:
-        senf::console::ScopedDirectory<Test> dir;
-
-        Test(std::string label) : dir(this), label_ (label) 
-        {
-            dir.add("test4", &Test::test2);
-            dir.add("test4", &Test::test3);
-        }
+        senf::console::ScopedDirectory<Test1> dir;
 
-        std::string test2(std::string const & text)
+        Test1(std::string label) : dir(this), label_ (label) 
+            { dir.add("test", &Test::test1);
+              dir.add("test", &Test::test2); }
+    
+        std::string test1(std::string const & text)
             { return label_ + ": " + text; }
 
-        void test3(std::ostream & os, unsigned n, std::string const & text) 
+        void test2(std::ostream & os, unsigned n, std::string const & text) 
             { while (n-- > 0) os << label << ": " << text << std::endl; }
 
     private:
 
     // ...
 
-    Test testOb ("test");
-    senf::console::root().add("testobj", testOb.dir);
+    Test1 test1ob ("test");
+    senf::console::root().add("test1ob", test1ob.dir);
     \endcode
 
     Binding via senf::console::ScopedDirectory ensures, that the commands are automatically removed
     from the tree when the object is destroyed.
+
+
+    \section console_variables Variables
+    
+    \subsection console_varadd Adding
+
+    The console/config library supports the direct registration of variables as commands. A
+    variable command consists of two overloads, one to query the current value and one to change the
+    value. 
+    \code
+    class Test2
+    {
+    public:
+        senf::console::ScopedDirectory<Test2> dir;
+
+        Test2() : dir(this), var_(0)
+            { dir.add("var", var_); }
+
+    private:
+        int var_;
+    };
+
+    Test2 test2ob;
+    senf::console::root().add("test2ob", test2ob.dir);
+    \endcode
+    This shows the most common scenario: A member variable is added to a ScopedDirectory of the same
+    class. This ensures, that the variable command node is removed from the tree when the instance
+    (and thereby the variable) are destroyed. The variable can now be used like any other command:
+    \htmlonly
+    <pre>
+    server:/$ test2ob/var
+    0
+    server:/$ test2ob/var 10
+    server:/$ test2ob/var
+    10
+    server:/$ help test2ob
+    Usage:
+        1- var new_value:int
+        2- var
+    server:/$
+    </pre>
+    \endhtmlonly
+
+
+    \subsection console_varro Read-only variables
+    
+    The library also supports read-only variables. To make a variable read-only, just wrap it in \c
+    boost::cref() (where \c cref stands for \c const reference)
+    \code
+    int var (0);
+
+    senf::console::root().add("var1", boost::cref(var));
+    \endcode
+    A read-only variable only has a single overload:
+    \htmlonly
+    <pre>
+    server:/$ var1
+    0
+    server:/$ help var1
+    Usage:
+        var1
+    server:/$ 
+    </pre>
+    \endhtmlonly
+
+
+    \subsection console_varattr Attributes
+
+    The most important Variable command attributes are
+
+    <table class="senf fixedwidth">
+
+    <tr><td style="width:14em">\link senf::console::VariableAttributor::doc() .doc\endlink
+    ( \e doc )</td><td>Set variable documentation</td></tr>
+    
+    <tr><td>\link senf::console::VariableAttributor::onChange() .onChange\endlink
+    ( \e handler )</td><td>Set change handler</td></tr>
+    
+    </table>
+
+    \see senf::console::VariableAttributor for the complete attribute interface
+
+    \subsection console_varchange Change notification
+
+    A \e handler can be set to be called, whenever the variable is changed. It will be called with a
+    reference to the old value. The handler is called, after the value has been changed
+
+    \code
+    int var (0);
+
+    // Since this is int, it would make sense to declare the argument pass-by-value (int old)
+    // but for more complex args, use a const & here
+    void varChanged(int const & old)
+    {
+        // ...
+    }
+
+    senf::console::root().add("var2",var)
+        .onChange(&varChanged);
+    \endcode
+    
+    After this setup, \c varChanged will be called, whenever the value has changed.
+
+
+    \section console_args Registering special argument types
+
+    By default, argument types which can be read and written using \c iostreams are automatically
+    supported. Other types need to be registered explicitly
+
+
+    \subsection console_args_enum Registering enum types
+
+    Enum types are a special case, since it is not possible, to find a string representation for the
+    enumerator values automatically. Therefore, enum types need to be registered manually.
+    \code
+    enum MyEnum { Sit, Run, Jump };
+    SENF_CONSOLE_REGISTER_ENUM( MyEnum, (Sit)(Run)(Jump) );
+
+    MyEnum fun4(MyEnum v) { return v }
+
+    senf::console::root()
+        .add("test9", &fun4);
+    \endcode
+
+    After an enum type is registered, it can be used like any other type for arguments or
+    return-values:
+
+    \htmlonly
+    <pre>
+    server:/$ test9 Sit
+    Sit
+    server:/$ test9 Crawl
+    argument syntax error: invalid enum value
+    server:/$ help test9
+    Usage:
+        test9 arg11:MyEnum
+    server:/$
+    </pre>
+    \endhtmlonly
+
+    \ref SENF_CONSOLE_REGISTER_ENUM() can only be used, to register enums at namespace scope. To
+    register enums defined within some class, use \ref SENF_CONSOLE_REGISTER_ENUM_MEMBER()
+
+    \code
+    class Test3
+    {
+    public:
+        enum Color { Red, Green, Blue };
+    
+        senf::console::ScopedDirectory<MyClass> dir;
+
+        Test3();
+
+        Color mem3(Color c) { return c }
+    };
+    SENF_CONSOLE_REGISTER_ENUM_MEMBER( Test3, Color, (Red)(Green)(Blue) );
+
+    Test3::Test3() : dir(this)
+        { dir.add("test", &MyClass::mem3); }
+    
+    Test3 test3ob;
+    senf::console::root().add("test3ob", test3ob.dir);
+    \endcode
+
+    Using this command/type is identical
+    \htmlonly
+    <pre>
+    server:/$ test3ob/test Red
+    Red
+    server:/$ test3ob/test White
+    argument syntax error: invalid enum value
+    server:/$ help test3ob/test
+    Usage:
+        test arg11:Color
+    </pre>
+    \endhtmlonly
+
+
+    \subsection console_args_custom Customizing argument and return value parsing/formatting
+
+    To support or customize parsing/formatting of other types, they need to be registered. In it's
+    simplest case, this works, by just providing an appropriate overload for
+    senf_console_parse_argument() and senf_console_format_value():
+    \code
+    struct Coordinate
+    {
+        Coordinate() : x(0), y(0) {}
+        Coordinate(int x_, int y_) : x(x_), y(y_) {}
+
+        int x, y;
+    }
+
+    void senf_console_parse_argument(senf::console::ParseCommandInfo::TokensRange const & tokens,
+                                     Coordinate & out)
+    {
+        if (tokens.size() != 2)
+            throw SyntaxErrorException("parameter syntax error");
+        senf::console::ArgumentTraits<int>::parse(
+            senf::console::ParseCommandInfo::TokensRange( tokens.begin(), tokens.begin()+1 ),
+            out.x )
+        senf::console::ArgumentTraits<int>::parse(
+            senf::console::ParseCommandInfo::TokensRange( tokens.begin()+1, tokens.end() ),
+            out.y )
+    }
+
+    void senf_console_format_value(Coordinate const & value, std::ostream & os)
+    {
+        os << '(' << value.x << ' ' << value.y << ')';
+    }
+    \endcode
+    The parser will accept an argument with two tokens which are each forwarded to the integer
+    parser. The formatter writes out the value as a parenthesized pair.
+
+    \code
+    Coordinate fun5(Coordinate const & p) { return Coordinate(2*p.x, 2*p.y) }
+    
+    namespace kw = senf::console::kw;
+
+    senf::console::root()
+        .add("test10", &fun5)
+        .arg("x","coordinate to double",
+             kw::default_value = Coordinate())
+    \endcode
+    We can now call \c test10 with a coordinate argument:
+    \htmlonly
+    <pre>
+    server:/$ test10 (2 7)
+    (4 14)
+    server:/$ help test10
+    Usage:
+        test10 [x:Coordinate]
+
+    With:
+        x         Coordinate to double
+            default: (0 0)
+    server:/$
+    </pre>
+    \endhtmlonly
+    
+    If you want to customize the formatting of default values differently from the formating of
+    return-values or if you want to change the displayed name of a type, you will need to specialize
+    the senf::console::ArgumentTraits class instead of implementing
+    senf_console_parse_argument(). See senf::console::ArgumentTraits and
+    senf::console::ReturnValueTraits for more.
  */
 
 \f