// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-/** \mainpage The Configuration and Runtime Control Framework
+/** \mainpage The Configuration and Runtime Control Library
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
+ \autotoc
- There are two components to the Config/console framework:
+ \section console_intro Introduction
- \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.
+ There are three parts to the Config/console library:
- 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.
+ \li The console/config library is based on a \link node_tree tree of console/config
+ nodes. \endlink
+ \li Besides directories, the node contains command nodes. Commands are based on \link
+ console_commands variables or callbacks.\endlink
+ \li The console/config library is utilized by writing configuration files or interactive
+ commands in \link console_parser the console/config language.\endlink
- To get started using the config/console library, see
- \li \ref node_tree
- \li \ref console_parser
- \li \ref console_commands
+ The node tree works like a directory structure. Commands are entered into this directory
+ structure and can be called passing arbitrary arguments. Configuration parameters are just
+ commands which set their respective parameter, however the library allows commands to do much
+ more than just that.
\section console_example Example
library. See above links for more:
\code
+ #include <senf/Console.hh>
+
// Define callback function.
- void mycommand(std::ostream & os, senf::console::ParseCommandInfo const & command)
+ void mycommand(std::ostream & os, int foo, int bar)
{
// ...
os << "!! Important message ...\n";
}
+ namespace kw = senf::console::kw;
+
int main(int, char**)
{
// Provide global documentation
// Add a command
senf::console::root()
.add("mycommand", &mycommand)
- .doc("mycommand <foo> [<bar>]\n\n"
- "If <bar> is given, flurgle the <foo>, otherwise burgle it");
+ .doc("If <bar> is given, flurgle the <foo>, otherwise burgle it")
+ .arg("foo")
+ .arg(kw::name = "bar", kw::default_value = 0);
// Start the interactive console server
senf::console::Server::start(senf::INet4SocketAddress(senf::INet4Address::None, 23232u))
Connection closed by foreign host.
$
</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
+
+ The basic idea is, that the console/config library manages a directory structure of parameters
+ and auxiliary commands. Parameters are just commands which set a parameter value so everything
+ is either a directory entry (senf::console::DirectoryNode) or a command
+ (senf::console::CommandNode).
+
+ \see \ref node_tree
+
+
+ \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
+ conversion.
+
+ Since parsing the tokens into something usable is quite tedious and error prone, the library
+ implements automatic argument parsing where the argument tokens are automatically parsed
+ depending on argument types. This enables you to register a command taking an integer argument
+ which will be called with an already parsed integer value (or throw a
+ senf::console::SyntaxErrorException if the conversion fails). This will be the most often used
+ command.
+
+ \see \ref console_commands
+
+
+ \section intro_language The console/config language
+
+ To call the commands and set parameters, a very simple language is defined. The language is
+ almost declarative (e.g. it does not have any control-flow statements) but is processed
+ imperatively from top to bottom. This is very simple and flexible.
+
+ Commands are referenced by their path in the node tree. To simplify working with deeply nested
+ directory structures, the current directory may be changed persistently or temporarily for some
+ commands.
+ \code
+ /server/port 1234;
+
+ /logger/targets/console {
+ accept senf::log::Debug IMPORTANT;
+ accept server::ServerLog CRITICAL;
+ }
+ \endcode
+
+ \see \ref console_parser
*/
/** \defgroup console_commands Supported command types
\autotoc
+ \section console_cmdadd Adding commands and setting attributes
+
+ Basically, all commands are added using senf::console::DirectoryNode::add(). What exactly
+ happens depends on the type of object added.
+ \code
+ dir.add("name", callback)
+ \endcode
+ will add a command 'name' which will execute 'callback' when called, where 'callback' can be a
+ lot of things as documented in the following chapters.
+
+ The add call always returns (something which can be used as) a reference to the command node
+ added:
+ \code
+ senf::console::CommandNode & node ( dir.add( ... ) );
+ \endcode
+
+ Depending on the object added, you can also bind to a more specific node type
+ (e.g. senf::console::SimpleCommand) if you know the type of node returned.
+
+ Depending on the type of object added, there are additional attributes which can be set. These
+ attributes are always set by calling them on the return value <b>before saving that value as a
+ node reference</b>. It is \e not guaranteed, you can call these members on the node
+ reference.
+ \code
+ dir.add("name", callback)
+ .doc("The documentation");
+ \endcode
+ sets the \e doc attribute (if that is available, otherwise this will fail to compile). The
+ attribute members return value is again (something which can be used as) a reference to the
+ command node
+ \code
+ senf::console::CommandNode & node (
+ dir.add("name", callback)
+ .doc("The documentation") );
+ \endcode
+
+
\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
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)
+ void fun1(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 (
+ senf::console::ParseCommandInfo::TokensRange & argTokens (
command.arguments()[0]);
// The argument must have exactly one token
'doc()':
\code
senf::console::root()
- .add("test1", &test1)
+ .add("test1", &fun1)
.doc("Usage:\n"
" test1 arg\n"
"\n"
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.
+ This type of command has only a single attribute, \e doc to set the commands documentation.
+
\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.
+ To greatly simplify parsing complex commands, we turn to automatic argument parsing.
+ \subsection console_autoadd Adding
+
+ Automatically parsed commands are registered by just adding a callback which has the correct
+ arguments and return-value defined:
\code
- std::string test2(std::string const & arg)
+ std::string fun2(std::string const & arg)
{
return arg;
}
\endcode
- This extremely simple callback may be registered by adding it to a
- senf::console::DirectoryNode.
+ This extremely simple callback may be registered by adding it to a senf::console::DirectoryNode.
\code
senf::console::root()
- .add("test2", &test2);
+ .add("test2", &fun2);
\endcode
The functionality is now identical to \c test1:
\htmlonly
</pre>
\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:
+
+ \subsection command_ostream Accessing the console stream
+
+ 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 consoles output stream object in this argument. With this, the callback can
+ output arbitrary messages to the network console.
\code
- namespace kw = senf::console::kw;
+ void fun3(std::ostream & os, unsigned n, std::string text)
+ {
+ while (n-- > 0) os << text << std::endl;
+ }
senf::console::root()
- .add("test2", &test2)
- .doc("Echo 'arg' to the console")
- .arg( kw::name = "arg",
- kw::description = "Message to output" );
+ .add("test3", &fun3);
\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 <tt>using namespace
- senf::console::kw</tt> 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
+ This simple command can now be used thus:
\htmlonly
<pre>
- server:/$ help test2
+ server:/$ test3
+ invalid number of arguments
+ server:/$ test3 stefan@j32.de
+ invalid number of arguments
+ server:/$ test3 2 ok
+ ok
+ ok
+ server:/$ help test3
Usage:
- test2 arg:string
+ test3 arg11:int arg12:string
+ server:/$
+ </pre>
+ \endhtmlonly
- With:
- arg Message to output
+ \subsection command_overload Overloading
- Echo 'arg' to the console
+ Automatically parsed commands can be overloaded: You can register multiple commands under the
+ same name. Each overload is tried in turn until no SyntaxErrorException is raised.
+ \code
+ senf::console::root()
+ .add("test4", &fun3);
+ senf::console::root()
+ .add("test4", &fun2);
+ \endcode
+ And now, we can call \c test4 with one or two args:
+ <pre>
+ server:/$ test4
+ invalid number of arguments
+ server:/$ test4 stefan@j32.de
+ stefan@j32.de
+ server:/$ test4 2 ok
+ ok
+ ok
+ server:/$ help test4
+ Usage:
+ 1- test4 arg11:int arg12:string
+ 2- test4 arg21:string
server:/$
</pre>
- \endhtmlonly
- \subsection command_ostream Accessing the console stream
+ 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);
- 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
- output arbitrary messages to the network console. See the next section for an example.
+ senf::console::root()
+ .add("over", static_cast<void (*)(int)>(&over));
+ senf::console::root()
+ .add("over", static_cast<void (*)(int,int)>(&over));
+ \endcode
- \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.
+ \subsection console_attributes Attributes
+ As have seen so far, some documentation is automatically provided. We can add more info, by
+ setting additional attributes.
\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;
- }
+ senf::console::root()
+ .add("test5", &fun3)
+ .doc("Echo text to the console")
+ .overloadDoc("Repeat {arg12} for {arg11} lines");
+ senf::console::root()
+ .add("test4", &fun2)
+ .overloadDoc("Echo the {arg21} argument")
+ \endcode
- using namespace senf::console::kw;
+ This additional info is used to provide more documentation:
+ \htmlonly
+ <pre>
+ server:/$ help test5
+ Usage:
+ 1- test5 arg11:int arg12:string
+ 2- test5 arg21:string
+
+ Echo text to the console
+
+ Variant 1:
+ Repeat {arg12} for {arg11} lines
+ Variant 2:
+ Echo the {arg21} argument
+ senf:/$
+ </pre>
+ \endhtmlonly
+
+
+ \subsection console_argattributes Argument attributes
+
+ Additional attributes can be set for each parameter. They are all passed to the
+ senf::console::ParsedArgumentAttributor::arg() attribute.
+
+ \code
+ namespace kw = senf::console::kw;
+
senf::console::root()
- .add("test3", &test3)
+ .add("test6", &fun3)
.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" );
+ .overloadDoc("Repeat {text} for {n} lines");
+ .arg( kw::name = "n", kw::description="Number of repetitions" )
+ .arg( kw::name = "text", kw::description="Text to output" );
senf::console::root()
- .add("test3", &test2)
- .overloadDoc("Echo the 'text' argument")
- .arg( name = "text", description = "Message to output" );
+ .add("test6", &fun2)
+ .overloadDoc("Echo the {text} argument")
+ .arg( kw::name = "text" );
\endcode
- We can now call \c test2 with one or two arguments:
+ (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 either use
+ this namespace via a namespace alias (as above) or via a <tt>using namespace
+ senf::console::kw</tt> declaration (but beware of name collisions).
- \htmlonly
+ 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 readable
+ \htmlonly
<pre>
- server:/$ test3 "The sky is blue"
- The sky is blue
- server:/$ test3 4 ok
- ok
- ok
- ok
- ok
- server:/$ help test3
+ server:/$ help test6
Usage:
- 1- test3 n:unsigned text:string
- 2- test3 text:string
-
+ 1- test6 n:int text:string
+ 2- test6 text:string
+
With:
- n Numer of repetitions
- text Messsage to output
+ n Number of repetitions
+ text Text to output
Echo text to the console
Variant 1:
- Repeat 'text' for 'n' lines
+ Repeat {text} for {n} lines
Variant 2:
- Echo the 'text' argument
- senf:/$ And
-
+ Echo the {text} argument
+ senf:/$
</pre>
\endhtmlonly
+ Since most of the time, we only need to set the name and possibly a description for arguments,
+ there is a shortcut: name and description can be specified as positional arguments in this
+ order. So the following will give the exactly same result as above:
+ \code
+ namespace kw = senf::console::kw;
+
+ senf::console::root()
+ .add("test6", &fun3)
+ .doc("Echo text to the console")
+ .overloadDoc("Repeat <text> for <n> lines");
+ .arg("n", "Number of repetitions")
+ .arg("text", "Text to output");
+ senf::console::root()
+ .add("test6", &fun2)
+ .overloadDoc("Echo the <text> argument")
+ .arg("text");
+ \endcode
+
+ Keyword arguments should always be used if additional attributes are set. You can however mix
+ positional and keyword arguments.
+
+
\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:
+ values. These have to be declared explicitly:
\code
- using namespace senf::console::kw;
+ namespace kw = senf::console::kw;
senf::console::root()
- .add("test4", &test2b)
- .arg()
- .arg( default_value = "ok" );
+ .add("test7", &fun3)
+ .doc("Echo {text} to the console, repeating {text} for {n} lines")
+ .arg("n", "Number of repetitions", kw::default_value=1)
+ .arg("text", "Text to output");
\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.
+ Default values can be used together with overloading. Default (optional) value support is quite
+ flexible, it is not mandatory, for default values to be specified only for the trailing
+ arguments. For the exact definition, how parsed argument values are assigned to overload
+ arguments in the presence of default values, see \ref senf::console::kw::default_value.
+
+ \htmlonly
+ <pre>
+ server:/$ test7 echo
+ echo
+ server:/$ test7 4 ok
+ ok
+ ok
+ ok
+ ok
+ server:/$ help test7
+ Usage:
+ test4 [n:unsigned] text:string
+
+ With:
+ n Number of repetitions
+ default: 1
+ text Text to output
+
+ Echo {text} to the console, repeating {text} for {n} lines
+ server:/$
+ </pre>
+ \endhtmlonly
+
- \subsection console_auto_summary Attribute summary
+ \subsection console_boostfn Non-function-pointer commands
- Here a summary of all the attributes available for automatically parsed command nodes:
+ It is possible to add other callable objects besides function (and member-function)
+ pointers. However, since it is not possible to automatically deduce the argument and return
+ types in this case, the callables have to be wrapped in a \c boost::function object:
+
+ \code
+ senf::console::root()
+ .add("test8",
+ boost::function<void (std::ostream &, std::string const &)>(
+ boost::bind(&fun3, _1, 4u, _2)));
+ \endcode
+
+ This works with any callable object where argument types cannot be deduced automatically:
+ Boost.Bind expressions, Boost.Lambda expressions, functors and so on.
+ \htmlonly
+ <pre>
+ server:/$ test8 ok
+ ok
+ ok
+ ok
+ ok
+ server:/$ help test8
+ Usage:
+ test8 arg11:string
+ server:/$
+ </pre>
+ \endhtmlonly
+
+
+ \subsection console_attr_summary Attribute summary
+
+ Here a summary of the most common attributes
+
<table class="senf fixedwidth">
-
- <tr><td style="width:12em">\c doc ( \e text )</td><td>Documentation for all overloads</td></tr>
- <tr><td>\c overloadDoc ( \e text )</td><td>Documentation for a specific overliad</td></tr>
+ <tr><td style="width:14em">\link senf::console::ParsedArgumentAttributorBase::doc() .doc\endlink
+ ( \e doc )</td><td>Set documentation for all overloads</td></tr>
+
+ <tr><td>\link senf::console::ParsedArgumentAttributorBase::overloadDoc()
+ .overloadDoc\endlink ( \e doc )</td><td>Set documentation for a specific overload</td></tr>
- <tr><td>\c arg ( \e attributes )</td><td>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</td></tr>
+ <tr><td>\link senf::console::ParsedArgumentAttributor::arg() .arg\endlink ( \e argument \e
+ attributes )</td><td>Set argument attributes (see below)</td></tr>
</table>
- See senf::console::ParsedArgumentAttributor 'List of all members'
+ The most important argument attributes (all defined in the senf::console::kw namespace) are:
- \section console_memberfn Registering member functions
+ <table class="senf fixed width">
+
+ <tr><td style="width:14em">\link senf::console::kw::name kw::name\endlink</td><td>Parameter
+ name</td></tr>
+
+ <tr><td>\link senf::console::kw::description kw::description\endlink</td><td>One-line
+ description of the argument</td></tr>
+
+ <tr><td>\link senf::console::kw::default_value kw::default_value\endlink</td><td>Arguments
+ default value</td></tr>
+
+ </table>
+
+ \see <a
+ href="classsenf_1_1console_1_1ParsedArgumentAttributor-members.html">senf::console::ParsedArgumentAttributor
+ / List of all members</a> for the complete attribute interface \n
+ \ref senf::console::kw for a list of all argument attribute keywords
+
+
+ \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<Test> dir;
+ senf::console::ScopedDirectory<Test1> dir;
- Test(std::string label) : dir(this), label_ (label) {
- dir.add("test4", &Test::test2);
- dir.add("test4", &Test::test3);
- }
+ 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; }
- 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; }
+ void test2(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);
+ 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