X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Console%2FMainpage.dox;h=e6cf4044619e9bdd08139ecd985b55d3e19ede5c;hb=1b1d76302a5d61e918ef71f1c8e11f80ac1262e2;hp=62cffd6d85642731960c1a04a66749401e70d897;hpb=80c83d2565c50f8ad33af2be0f4cb3e5735cafcf;p=senf.git diff --git a/Console/Mainpage.dox b/Console/Mainpage.dox index 62cffd6..e6cf404 100644 --- a/Console/Mainpage.dox +++ b/Console/Mainpage.dox @@ -51,6 +51,8 @@ library. See above links for more: \code + #include + // Define callback function. void mycommand(std::ostream & os, int foo, int bar) { @@ -97,6 +99,46 @@ $ + \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 + + 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 +
+    bash$ telnet localhost 12345
+    Trying 127.0.0.1...
+    Connected to localhost.
+    Escape character is '^]'.
+
+    myserver:/$ exit
+    Connection closed by foreign host.
+    bash$
+    
+ \endhtmlonly \section intro_nodes The node tree @@ -108,7 +150,7 @@ \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 @@ -143,6 +185,53 @@ \endcode \see \ref console_parser + + + \section console_misc Further features + + \subsection console_serverclient Server and Client objects + + The senf::console::Server and senf::console::Client objects offer further API calls. To access + the server instance you need to store away the senf::console::Server reference returned when + starting the server so you can later refer to it: + \code + int main(int, char**) + { + senf::console::Server & server ( senf::console::start( ... ) ); + + // Do something ... + + server.stop() + } + \endcode + + The client instance can be accessed via the \c std::ostream arg of any command callback + \code + void someCallback(std::ostream & os, ... ) + { + senf::console::Client & client (senf::console::Client::get(os)); + + // Use the client's log target + client.route(); + } + \endcode + + \see + senf::console::Server for the Server API \n + senf::console::Client / List of all + members for the Client API + + + \subsection console_shell Features of the interactive console shell + + The interactive shell will use the GNU readline library for the first connected + instance. Further users will not have access to this functionality since GNU readline is + completely non-reentrant. + + The shell supports auto-cd and auto-completion: If you enter the name of a directory at the + prompt, the console will change to that directory. With auto-completion, any unique beginning of + a path component will be completed automatically and transparently to th corresponding full + name. */ /** \defgroup console_commands Supported command types @@ -203,7 +292,7 @@ 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 @@ -303,7 +392,7 @@ 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 + 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) @@ -358,6 +447,21 @@ server:/$ + 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(&over)); + senf::console::root() + .add("over", static_cast(&over)); + \endcode + + \subsection console_attributes Attributes As have seen so far, some documentation is automatically provided. We can add more info, by @@ -580,24 +684,23 @@ \section console_memberfn 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. + Non-static member functions are supported like non-member functions (static member functions are + identical to non-members). 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 dir; + 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) + 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: @@ -606,12 +709,256 @@ // ... - 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 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 +
+    server:/$ test2ob/var
+    0
+    server:/$ test2ob/var 10
+    server:/$ test2ob/var
+    10
+    server:/$ help test2ob
+    Usage:
+        1- var new_value:int
+        2- var
+    server:/$
+    
+ \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 +
+    server:/$ var1
+    0
+    server:/$ help var1
+    Usage:
+        var1
+    server:/$ 
+    
+ \endhtmlonly + + + \subsection console_varattr Attributes + + The most important Variable command attributes are + + + + + + + +
\link senf::console::VariableAttributor::doc() .doc\endlink + ( \e doc )Set variable documentation
\link senf::console::VariableAttributor::onChange() .onChange\endlink + ( \e handler )Set change handler
+ + \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 +
+    server:/$ test9 Sit
+    Sit
+    server:/$ test9 Crawl
+    argument syntax error: invalid enum value
+    server:/$ help test9
+    Usage:
+        test9 arg11:MyEnum
+    server:/$
+    
+ \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 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 +
+    server:/$ test3ob/test Red
+    Red
+    server:/$ test3ob/test White
+    argument syntax error: invalid enum value
+    server:/$ help test3ob/test
+    Usage:
+        test arg11:Color
+    
+ \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::parse( + senf::console::ParseCommandInfo::TokensRange( tokens.begin(), tokens.begin()+1 ), + out.x ) + senf::console::ArgumentTraits::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 +
+    server:/$ test10 (2 7)
+    (4 14)
+    server:/$ help test10
+    Usage:
+        test10 [x:Coordinate]
+
+    With:
+        x         Coordinate to double
+            default: (0 0)
+    server:/$
+    
+ \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. */