4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 /** \mainpage The Configuration and Runtime Control Library
25 The Console library implements a runtime interactive (network) console which allows to
26 configure, control and manipulate a running application in any way. Additionally this library
27 provides support for configuration files and command line parsing which can be used with or
28 without the network console.
33 \section console_intro Introduction
35 There are three parts to the Config/console library:
37 The Config/Console library is built around several components
39 \li The \link node_tree Node tree\endlink represents all configuration options and commands
40 organized in a filesystem like structure.
41 \li \link console_commands Actions\endlink are added to the node tree in the form of command
43 \li There exist several interfaces to \link console_access access\endlink entries in the node
44 tree: interactive console, reading configuration files etc.
46 The node tree works like a directory structure. Commands are entered into this directory
47 structure and can be called passing arbitrary arguments. Configuration parameters are just
48 commands which set their respective parameter, however the library allows commands to do much
52 \section console_example Example
54 The following example shows a \e very short summary on how to integrate the config/console
55 library. See above links for more:
58 #include <senf/Console.hh>
60 // Define callback function.
61 void mycommand(std::ostream & os, int foo, int bar)
64 os << "!! Important message ...\n";
67 namespace kw = senf::console::kw;
68 namespace fty = senf::console::factory;
70 int main(int argc, char** argv)
72 // Provide global documentation
74 .doc("This is someServer server");
77 senf::console::root().add("mycommand", fty::Command(&mycommand)
78 .doc("If <bar> is given, flurgle the <foo>, otherwise burgle it")
80 .arg(kw::name = "bar", kw::default_value = 0) );
82 // Parse command line parameters
83 senf::console::parseOptions(argc,argv);
85 // Start the interactive console server
86 senf::console::Server::start(senf::INet4SocketAddress(senf::INet4Address::None, 23232u))
90 senf::scheduler::process();
94 after this registration, we can call the command from the command-line using
97 $ someServer --mycommand="1 2"
100 the console can be accessed easily via telnet:
103 $ telnet localhost 23232
105 Connected to localhost.
106 Escape character is '^]'
107 xxxx-xx-xx xx:xx:xx.xxxxxx-0000 [NOTICE][senf::console::Server] Registered new client 0xxxxxxx
110 someServer:/# mycommand
111 !! Important message ...
113 xxxx-xx-xx xx:xx:xx.xxxxxx-0000 [NOTICE][senf::console::Server] Disposing client 0xxxxxxx
114 Connection closed by foreign host.
118 \see \ref console_testserver for a complete example application
121 \section intro_usage Using the Console: Configuration files, Network console
122 \seechapter \ref console_access
124 There are several ways to access the node tree:
125 \li By parsing configuration files
126 \li By parsing command line parameters
127 \li By providing interactive or non-interactive network console access
130 \section intro_nodes The node tree
131 \seechapter \ref node_tree
133 The basic idea is, that the console/config library manages a directory structure of parameters
134 and auxiliary commands. Parameters are just commands which set a parameter value so everything
135 is either a directory entry (senf::console::DirectoryNode) or a command
136 (senf::console::CommandNode).
139 \section intro_commands Implementing console/config commands
140 \seechapter \ref console_commands
142 The console/config language does not define, how arguments are passed to the commands, it just
143 tokenizes the input and passes the tokens to the commands which then handle the
146 Since parsing the tokens into something usable is quite tedious and error prone, the library
147 implements automatic argument parsing where the argument tokens are automatically parsed
148 depending on argument types. This enables you to register a command taking an integer argument
149 which will be called with an already parsed integer value (or throw a
150 senf::console::SyntaxErrorException if the conversion fails). This will be the most often used
154 /** \defgroup console_access Accessing the Console/Config tree
156 The Console/Config library provides several ways to use the node tree to configure and control
162 \section console_access_config Configuration support
164 The configuration support of the Console/Config library revolves around the ConfigSource
165 concept. Each ConfigSource will somehow provide commands which will then be executed against the
168 To simplify the usage, there will always be three interfaces to a specific config source:
169 \li A constructor to build a bare config source which is then added to a
170 senf::console::ConfigBundle (see \ref console_access_multiple)
171 \li A class parsing and executing a single config source. The visible interface of this class is
172 a combination of the constructor and the senf::console::ConfigBundle interfaces.
173 \li A helper function which will do the complete parsing of a single source with default
176 When parsing these configuration sources, it is always possible to optionally change the root
177 node used during parsing and it is also possible to restrict parsing to a command subset. See
178 \ref console_access_partial.
181 \subsection console_access_file Configuration files
183 <table class="senf fixedwidth">
184 <tr><td><b>Constructor</b></td> <td>senf::console::FileConfig()</td></tr>
185 <tr><td><b>Class</b></td> <td>senf::console::ConfigFile</td></tr>
186 <tr><td><b>Helper</b></td> <td>senf::console::parseFile()</td></tr>
189 In it's simplest form, parsing a configuration file consists of calling
190 senf::console::parseFile() with the name of the respective config file as argument.
193 senf::console::parseFile("some.conf");
196 To get more flexible, instantiate a senf::console::ConfigFile instance at use that to parse the
200 senf::console::ConfigFile cf ("some.conf");
201 // The following line is optional: Call to ignore mussing files
206 If the application supports other configuration sources besides a single configuration file
207 (like command line options) or if it supports multiple configuration files (e.g. a system-wide
208 and a user specific configuration file) see \ref console_access_multiple and add one (or more)
209 senf::console::FileConfig() source to a senf::console::ConfigBundle.
212 \subsubsection console_access_file_syntax Configuration file syntax
214 Configuration files are written in a simple configuration language. This language is almost
215 declarative (e.g. it does not have any control-flow statements) but is processed imperatively
216 from top to bottom. This is very simple and flexible.
218 Commands are referenced by their path in the node tree. To simplify working with deeply nested
219 directory structures, the current directory may be changed persistently or temporarily for some
224 /logger/targets/console {
225 accept senf::log::Debug IMPORTANT;
226 accept server::ServerLog CRITICAL;
230 \see \ref console_parser
233 \subsection console_access_options Command line options
235 <table class="senf fixedwidth">
236 <tr><td><b>Constructor</b></td> <td>senf::console::OptionsConfig()</td></tr>
237 <tr><td><b>Class</b></td> <td>senf::console::ProgramOptions</td></tr>
238 <tr><td><b>Helper</b></td> <td>senf::console::parseOptions()</td></tr>
241 Command line options can either be parsed by calling the senf::console::parseOptions() helper
244 senf::console::parseOptions(argc, argv)
247 or more flexibly by instantiating a senf::console::ProgramOptions class
250 std::vector<std::string> args;
251 senf::console::ProgramOptions opts (argc, argv);
254 .alias('c', "--mycommand",true)
255 .alias('C', "--mycommand=2 3");
259 This registeres two short options and accumulates all non-option arguments in \c args.
261 If the application supports other configuration sources besides the command line options (like
262 configuration files) see \ref console_access_multiple and add a senf::console::OptionsConfig()
263 source to a senf::console::ConfigBundle.
265 See \ref senf::console::ProgramOptions for the source specific additional parameters. These
266 apply to senf::console::ProgramOptions and to the senf::console::OptionsConfig() source.
269 \subsubsection console_access_options_syntax Options syntax
271 Command line options are primarily parsed as long-options. Long options start with '--'. Further
272 '-' characters serve as directory separators if required (that is, they are \e only interpreted
273 as directory separator is there is no entry in the current (sub-) directory matching more than a
274 single name component). This still allows using hyphens in node names.
276 Options can be abbreviated at each directory boundary: A command <tt>/foo/bar/do</tt> can be
277 called as <tt>--f-b-d</tt> as long as this name is unique.
279 Everything after the first '=' character is parsed into argument tokens using the normal
280 config/console parser. If the option has no '=' character, the list of argument tokens will be
283 <table style="font-size:80%" class="senf">
284 <tr><th>Command</th><th>File syntax</th><th>Option syntax</th></tr>
287 <td><tt>void doo()</tt></td>
288 <td><tt>/path/to/doo;</tt></td>
289 <td><tt>--path-to-doo</tt></td>
293 <td><tt>void doo(std::string const &)</tt></td>
294 <td><tt>/path/to/doo john.doe@everywhere.org;</tt></td>
295 <td><tt>--path-to-doo="john.doe@everywhere.org"</tt></td>
299 <td><tt>void doo(std::string const &)</tt></td>
300 <td><tt>/path/to/doo "some test";</tt></td>
301 <td><tt>--path-to-doo='"some text"'</tt></td>
305 <td><tt>void doo(std::string const &, int)</tt></td>
306 <td><tt>/path/to/doo take 1;</tt></td>
307 <td><tt>--path-to-doo="take 1"</tt></td>
311 The last column is additionally quoted using standard \c sh quoting: quotes in arguments need to
312 be additionally quoted for the shell.
314 Short options are registered as aliases for long options. They can be registered with or without
315 an implied parameter and can optionally take a parameter. so after
319 .alias('c', "--mycommand",true)
320 .alias('C', "--mycommand=2 3");
326 $ program -C -c "4 5"
333 $ program --mycommand="2 3" --mycommand="4 5"
336 (Beware, that the second argument to \c alias() is \e not shell quoted).
339 \subsection console_access_root Changing the root node
341 When used in it's default state, parsing will always interpret all commands relative to the
342 senf::console::root() node and will parse a file completely.
344 The first possibility to control this is to change the root node. This is done by
345 \li passing that root node to the helper class or to the parse helper as an additional argument
346 (see the respective documentation).
347 \li passing it to the senf::console::ConfigBundle constructor when parsing multiple sources.
352 senf::console::parseFile("/etc/myserver.conf", senf::console::root()['config']);
355 This functionality is even more powerful by combining it with \c link nodes: This allows to
356 selectively choose commands from the node tree which are to be made accessible for
357 configuration. See \ref node_tree.
360 \subsection console_access_partial Partial / incremental configuration
362 Another feature provided by senf::console::ConfigBundle and all helper classes is partial
366 // Create a console/config aware object and place it (that is it's directory node) into the node
369 senf::console::root().add("foo", foo.dir);
371 // Open configuration file
372 senf::console::ConfigFile cf ("/etc/myserver.conf");
374 // Parse only commands in the configuration file which are in the foo.dir directory
379 // Anywhere later, parse the rest of the configuration file
383 This feature allows to parse parts of one or more configuration sources before the
384 console/config tree has been fully established. Partial parsing can be applied any number of
385 times to arbitrary nodes. Any command already parsed will be skipped automatically.
387 When combining partial parsing with \c chroot() and \c link's, it is important to realize, that
388 <em>partial parsing always applies to the \e real target and ignores links</em>. This is very
389 important: It allows a subsystem to parse it's configuration parameters irrespective of any
390 links pointing to nodes of that subsystem.
393 \subsection console_access_multiple Multiple sources
395 Most of the time, an application will utilize multiple configuration sources: A global
396 configuration file, maybe a user specific local configuration file, command line options ...
398 When parsing configuration commands, especially using partial / incremental parsing, all parse
399 commands should be applied to each configuration source in turn. This is the responsibility of
400 senf::console::ConfigBundle.
403 senf::console::ScopedDirectory<> config;
404 senf::console::root().add("config", config);
406 // Let's enable all logger commands for configuration
407 config.link("logger", senf::console::root()["logger"]);
409 // Create bundle and add sources
410 std::vector<std::string> args;
411 senf::console::ConfigBundle conf (senf::console::root()["config"]);
412 conf.add( senf::console::FileConfig("/etc/myserver.conf") );
413 conf.add( senf::console::FileConfig(".myserver.conf")->ignoreMissing() );
414 conf.add( senf::console::OptionsConfig(senf::Daemon::instance().argc(),
415 senf::Daemon::instance().argv()) )
417 .alias('c', "--mycommand",true)
418 .alias('C', "--mycommand=2 3");
420 // Parse the logger subsystem commands in '/logger'
421 conf.parse(senf::console::root()['logger']);
425 // Parse all other configuration commands. All necessary commands and links in '/config' must by
426 // now have been created.
430 This example parses three configuration sources: Two configuration files and additional
431 parameters specified on the command line. All the configuration commands are placed into the
432 <tt>/config</tt> directory (directly or via links). The configuration sources are parsed in the
433 order they are specified, so in this case, the command line options will override any options
434 specified in one of the configuration files.
437 \section console_access_console The network console
439 To make the network console accessible, it must be initialized when the program is started:
441 #include <senf/Console.hh>
443 int main(int argc, char * argv [])
445 // Configure console nodes, add commands ...
447 // Start console server
448 senf::console::start(senf::INet4SocketAddress(12345u))
451 // You need to enter the scheduler main-loop for the server to work
452 senf::scheduler::process();
454 // Alternatively enter the main-loop via the PPI
459 This will start the server on IPv4 port 12345. The servers name (as displayed in the interactive
460 console prompt) is set to 'myserver'.
462 After launching the application, the server can be accessed at the given port:
465 bash$ telnet localhost 12345
467 Connected to localhost.
468 Escape character is '^]'.
471 Connection closed by foreign host.
476 It is possible to start multiple server consoles by calling \c start() multiple times with
477 different ports/addresses. Each server can be configured separately (e.g. root node, mode ...).q
480 \subsection console_serverclient Server and Client objects
482 The senf::console::Server and senf::console::Client objects offer further API calls. To access
483 the server instance you need to store away the senf::console::Server reference returned when
484 starting the server so you can later refer to it:
486 int main(int, char**)
488 senf::console::Server & server ( senf::console::start( ... ) );
496 The client instance can be accessed via the \c std::ostream arg of any command callback
498 void someCallback(std::ostream & os, ... )
500 senf::console::Client & client (senf::console::Client::get(os));
502 // Use the client's log target
503 client.route<senf::log::Debug, senf::Log::IMPORTANT>();
508 senf::console::Server for the Server API \n
509 <a href="classsenf_1_1console_1_1Client-members.html">senf::console::Client / List of all
510 members</a> for the Client API
513 \subsection console_shell The interactive console shell
515 The interactive shell implements a fully function line editor on capable terminals. This support
516 is available when using a full featured telnet client on a fully supported terminal (like vt100
519 The shell supports auto-cd and auto-completion: If you enter the name of a directory at the
520 prompt, the console will change to that directory. With auto-completion, any unique beginning of
521 a path component will be completed automatically and transparently to the corresponding full
525 \subsection console_noninteractive Non-interactive network console
527 After a new connection is established, the console server waits a short time for data to arrive.
528 Only if nothing happens in the first 500ms, an interactive session is initialized.
530 By sending data immediately after opening the connection, the console is switched into
531 non-interactive mode. In this mode, no prompt is displayed. In this mode, commands are \e not
532 terminated automatically by end-of-line (CR). This allows, to easily cat an arbitrary
533 configuration file into the network console using netcat:
536 $ nc -q1 localhost 23232 < some.conf
539 The argument <tt>-q1</tt> makes netcat close the sending end of the connection on EOF and wait
540 up to 1 second for the console to terminate. Even better, use \c netcat6, which has full TCP
544 $ echo "ls" | nc6 --half-close localhost 23232 2>/dev/null
551 Commands are executed as soon as the terminating character (';', '{' or '}') is received or when
552 the sending end of the connection is closed.
554 \section console_udp Non-interactive UDP console
556 The UDP console allows to script the console tree via UDP packets. Every UDP packet must be a
557 complete command (or sequence of commands). The combined reply of all these commands will be
558 returned in a single UDP packet. This reply can be disabled or directed to a different address.
560 To start a UDP server, just create an instance of the senf::console::UDPServer class
562 senf::console::UDPServer server (senf::INet4SocketAddress("127.0.0.1:23232"));
564 (Remember to enter the scheduler main-loop for processing)
566 Commands may then be sent to this UDP console e.g. using netcat
568 $ echo "cd sys; ls" | nc -uq0 localhost 23232 2>/dev/null
571 \see senf::console::UDPServer
574 /** \defgroup console_commands Supported command types
576 The Console/config library supports quite a number of different command types. All these types
577 of command are registered by passing an appropriate factory instance to DirectoryNode::add()
582 \section console_cmdadd Adding commands and setting attributes
584 Basically, all commands are added using senf::console::DirectoryNode::add().
586 namespace fty = senf::console::factory;
587 dir.add("name", fty::Command(callback));
589 will add the command 'name' which will execute 'callback' when called.
591 The add call always returns (something which can be used as) a reference to the command node
594 senf::console::CommandNode & node ( dir.add( ... ) );
597 Depending on the object added, you can also bind to a more specific node type
598 (e.g. senf::console::SimpleCommand) if you know the type of node returned.
600 Depending on the type of object added, there are additional attributes which can be set. These
601 attributes are always set by calling them on the factory return value. It is \e not guaranteed,
602 you can call these members on the node reference returned by the \c add() call.
604 namespace fty = senf::console::factory;
605 dir.add("name", fty::Command(callback)
606 .doc("The documentation") );
608 sets the \e doc attribute (if that is available, otherwise this will fail to compile).
611 \section console_manualparse Manually parsing command arguments
613 This is the most primitive type of command. It will be called with an output stream and with a
614 senf::console::ParseCommandInfo reference which holds information about the command parsed.
616 From this information the command callback gets a list of arguments or tokens which then can be
617 interpreted in an arbitrary way.
619 void fun1(std::ostream & os, senf::console::ParseCommandInfo const & command)
621 // Here we declare variables for the arguments
625 // We parse the arguments using the CheckedArgumentIteratorWrapper. This wrapper
626 // will throw a SyntaxErrorException if we access a nonexistent argument or if we
627 // do not parse all arguments.
628 senf::console::CheckedArgumentIteratorWrapper args (command.arguments());
630 // Extract the first argument. This is again a token range.
631 senf::console::ParseCommandInfo::TokensRange arg1Tokens ( *(args++) );
632 if (arg1Tokens.size() != 1)
633 raise senf::console::SyntaxErrorException("argument syntax error");
634 value = arg1Tokens[0].value();
637 os << value << std::endl;
641 Registering this callback is done by simply adding it. To provide online help, pass it to
644 namespace fty = senf::console::factory;
645 senf::console::root().add("test1", fty::Command(&fun1)
649 "Echo 'arg' to the console") );
652 The callback may now be called interactively on the console by it's registered name:
656 invalid number of arguments
657 server:/$ test1 stefan@j32.de
659 server:/$ test1 (echo me)
660 argument syntax error
665 Echo 'arg' to the console
670 As you can see above, the arguments and tokens are returned as <a
671 href="http://www.boost.org/doc/libs/1_33_1/libs/range/doc/utility_class.html#iter_range">
672 boost::iterator_range</a> instances. These behave much like containers: They have \c begin() and
673 \c end() and some other useful members.
675 The parser will have divided the argument tokens into arguments already. This simplifies further
676 parsing. If however you want to access the list of argument tokens as a single list, you can do
677 so using senf::console::ParseCommandInfo::tokens().
679 Parsing arguments is quite simple but can get very tedious. To simplify this task, the parsing
680 can be delegated to the Console/config library. See the next section.
682 This type of command has only a single attribute, \e doc to set the commands documentation.
685 \section console_autoparse Automatic argument parsing
687 To greatly simplify parsing complex commands, we turn to automatic argument parsing.
690 \subsection console_autoadd Adding
692 Automatically parsed commands are registered by just adding a callback which has the correct
693 arguments and return-value defined:
695 std::string fun2(std::string const & arg)
701 This extremely simple callback may be registered by adding it to a senf::console::DirectoryNode.
703 namespace fty = senf::console::factory;
704 senf::console::root().add("test2", fty::Command(&fun2));
706 The functionality is now identical to \c test1:
710 invalid number of arguments
711 server:/$ test2 stefan@j32.de
713 server:/$ test2 (echo me)
714 argument syntax error
723 \subsection command_ostream Accessing the console stream
725 Commands may have an optional first argument of type <tt>std::ostream &</tt>. This argument is
726 not considered part of the real interface. When the command is executed, the callback will be
727 passed the current consoles output stream object in this argument. With this, the callback can
728 output arbitrary messages to the network console.
730 namespace fty = senf::console::factory;
732 void fun3(std::ostream & os, unsigned n, std::string text)
734 while (n-- > 0) os << text << std::endl;
737 senf::console::root().add("test3", fty::Command(&fun3));
740 This simple command can now be used thus:
744 invalid number of arguments
745 server:/$ test3 stefan@j32.de
746 invalid number of arguments
752 test3 arg11:int arg12:string
758 \subsection command_overload Overloading
760 Automatically parsed commands can be overloaded: You can register multiple commands under the
761 same name. Each overload is tried in turn until no SyntaxErrorException is raised.
763 namespace fty = senf::console::factory;
765 senf::console::root().add("test4", fty::Command(&fun3));
766 senf::console::root().add("test4", fty::Command(&fun2));
768 And now, we can call \c test4 with one or two args:
771 invalid number of arguments
772 server:/$ test4 stefan@j32.de
779 1- test4 arg11:int arg12:string
780 2- test4 arg21:string
784 One note: When taking the address of an overloaded function (member or non-member), the C++
785 language forces you to cast that address to one of the possible types so the compiler knows,
786 which overload is requested. So to add a function which is overloaded in C++, each overload
787 needs to be added explicitly, casting to the correct type. There are some macros in
788 Utils/membind.hh to simplify this:
791 namespace fty = senf::console::factory;
796 senf::console::root().add("over", fty::Command(SENF_FNP(void, over, (int))));
797 senf::console::root().add("over", fty::Command(SENF_FNP(void, over, (int,int)));
800 senf::console::ScopedDirectory<SomeModule> dir;
802 unsigned int overlodedMethod() const {....};
803 void overlodedMethod(unsigned int) {....};
805 void addConsoleCommands() {
807 .add("overlodedMethod", fty::Command(
808 SENF_MEMBINDFNP(unsigned int, SomeModule, overlodedMethod, () const)));
810 .add("overlodedMethod", fty::Command(
811 SENF_MEMBINDFNP(unsigned int, SomeModule, overlodedMethod, (unsigned int))));
817 \subsection console_attributes Attributes
819 As have seen so far, some documentation is automatically provided. We can add more info, by
820 setting additional attributes.
822 namespace fty = senf::console::factory;
824 senf::console::root().add("test5", fty::Command(&fun3)
825 .doc("Echo text to the console")
826 .overloadDoc("Repeat {arg12} for {arg11} lines") );
827 senf::console::root().add("test4", fty::Command(&fun2)
828 .overloadDoc("Echo the {arg21} argument") );
831 This additional info is used to provide more documentation:
836 1- test5 arg11:int arg12:string
837 2- test5 arg21:string
839 Echo text to the console
842 Repeat {arg12} for {arg11} lines
845 Echo the {arg21} argument
851 \subsection console_argattributes Argument attributes
853 Additional attributes can be set for each parameter. They are all passed to the
854 senf::console::ParsedArgumentAttributor::arg() attribute.
857 namespace kw = senf::console::kw;
858 namespace fty = senf::console::factory;
860 senf::console::root().add("test6", fty::Command(&fun3)
861 .doc("Echo text to the console")
862 .overloadDoc("Repeat {text} for {n} lines");
863 .arg( kw::name = "n", kw::description="Number of repetitions" )
864 .arg( kw::name = "text", kw::description="Text to output" ) );
865 senf::console::root().add("test6", fty::Command(&fun2)
866 .overloadDoc("Echo the {text} argument")
867 .arg( kw::name = "text" ) );
870 (Sadly, there is no way to automatically find out the \e name of an argument, just it's type.)
871 Every callback argument corresponds with a call of the \c arg() attribute. Argument attributes
872 are set using keywords from the \ref senf::console::kw namespace. You will probably either use
873 this namespace via a namespace alias (as above) or via a <tt>using namespace
874 senf::console::kw</tt> declaration (but beware of name collisions).
876 You don't need to specify any information for an argument: To skip an argument, just call \c
877 arg() without attributes for this argument.
879 After adding this information, the online help is much more readable
884 1- test6 n:int text:string
888 n Number of repetitions
891 Echo text to the console
894 Repeat {text} for {n} lines
897 Echo the {text} argument
902 Since most of the time, we only need to set the name and possibly a description for arguments,
903 there is a shortcut: name and description can be specified as positional arguments in this
904 order. So the following will give the exactly same result as above:
906 namespace kw = senf::console::kw;
907 namespace fty = senf::console::factory;
909 senf::console::root().add("test6", fty::Command(&fun3)
910 .doc("Echo text to the console")
911 .overloadDoc("Repeat <text> for <n> lines");
912 .arg("n", "Number of repetitions")
913 .arg("text", "Text to output") );
914 senf::console::root().add("test6", fty::Command(&fun2)
915 .overloadDoc("Echo the <text> argument") );
919 Keyword arguments should always be used if additional attributes are set. You can however mix
920 positional and keyword arguments.
923 \subsection console_defaults Default values
925 Another information which can not be automatically gathered from the type system is default
926 values. These have to be declared explicitly:
928 namespace kw = senf::console::kw;
929 namespace fty = senf::console::factory;
931 senf::console::root().add("test7", fty::Command(&fun3)
932 .doc("Echo {text} to the console, repeating {text} for {n} lines")
933 .arg("n", "Number of repetitions", kw::default_value=1)
934 .arg("text", "Text to output") );
937 Default values can be used together with overloading. Default (optional) value support is quite
938 flexible, it is not mandatory, for default values to be specified only for the trailing
939 arguments. For the exact definition, how parsed argument values are assigned to overload
940 arguments in the presence of default values, see \ref senf::console::kw::default_value.
953 test4 [n:unsigned] text:string
956 n Number of repetitions
960 Echo {text} to the console, repeating {text} for {n} lines
966 \subsection console_boostfn Non-function-pointer commands
968 It is possible to add other callable objects besides function (and member-function)
969 pointers. However, since it is not possible to automatically deduce the argument and return
970 types in this case, the signature has to be specified explicitly:
972 namespace fty = senf::console::factory;
974 senf::console::root()
975 .add("test8",fty::Command<void (std::ostream &, std::string const &)>(
976 boost::bind(&fun3, _1, 4u, _2)));
979 This works with any callable object where argument types cannot be deduced automatically:
980 Boost.Bind expressions, Boost.Lambda expressions, functors and so on.
997 \subsection console_attr_summary Attribute summary
999 Here a summary of the most common attributes
1001 <table class="senf fixedwidth">
1003 <tr><td style="width:14em">\link senf::console::ParsedArgumentAttributorBase::doc() .doc\endlink
1004 ( \e doc )</td><td>Set documentation for all overloads</td></tr>
1006 <tr><td>\link senf::console::ParsedArgumentAttributorBase::overloadDoc()
1007 .overloadDoc\endlink ( \e doc )</td><td>Set documentation for a specific overload</td></tr>
1009 <tr><td>\link senf::console::ParsedArgumentAttributor::arg() .arg\endlink ( \e argument \e
1010 attributes )</td><td>Set argument attributes (see below)</td></tr>
1014 The most important argument attributes (all defined in the senf::console::kw namespace) are:
1016 <table class="senf fixed width">
1018 <tr><td style="width:14em">\link senf::console::kw::name kw::name\endlink</td><td>Parameter
1021 <tr><td>\link senf::console::kw::description kw::description\endlink</td><td>One-line
1022 description of the argument</td></tr>
1024 <tr><td>\link senf::console::kw::default_value kw::default_value\endlink</td><td>Arguments
1025 default value</td></tr>
1030 href="classsenf_1_1console_1_1ParsedArgumentAttributor-members.html">senf::console::ParsedArgumentAttributor
1031 / List of all members</a> for the complete attribute interface \n
1032 \ref senf::console::kw for a list of all argument attribute keywords
1035 \section console_memberfn Member functions
1037 Non-static member functions are supported like non-member functions (static member functions are
1038 identical to non-members). They must however be added through a senf::console::ScopedDirectory
1039 instance to bind them to their instance.
1041 namespace fty = senf::console::factory;
1046 senf::console::ScopedDirectory<Test1> dir;
1048 Test1(std::string label) : dir(this), label_ (label)
1049 { dir.add("test", fty::Command(&Test::test1, this));
1050 dir.add("test", fty::Command(&Test::test2, this)); }
1052 std::string test1(std::string const & text)
1053 { return label_ + ": " + text; }
1055 void test2(std::ostream & os, unsigned n, std::string const & text)
1056 { while (n-- > 0) os << label << ": " << text << std::endl; }
1064 Test1 test1ob ("test");
1065 senf::console::root().add("test1ob", test1ob.dir);
1068 Binding via senf::console::ScopedDirectory ensures, that the commands are automatically removed
1069 from the tree when the object is destroyed.
1072 \section console_variables Variables
1074 \subsection console_varadd Adding
1076 The console/config library supports the direct registration of variables as commands. A
1077 variable command consists of two overloads, one to query the current value and one to change the
1080 namespace fty = senf::console::factory;
1085 senf::console::ScopedDirectory<Test2> dir;
1087 Test2() : dir(this), var_(0)
1088 { dir.add("var", fty::Variabl(var_) ); }
1095 senf::console::root().add("test2ob", test2ob.dir);
1097 This shows the most common scenario: A member variable is added to a ScopedDirectory of the same
1098 class. This ensures, that the variable command node is removed from the tree when the instance
1099 (and thereby the variable) are destroyed. The variable can now be used like any other command:
1102 server:/$ test2ob/var
1104 server:/$ test2ob/var 10
1105 server:/$ test2ob/var
1107 server:/$ help test2ob
1109 1- var new_value:int
1116 \subsection console_varro Read-only variables
1118 The library also supports read-only variables. To make a variable read-only, just wrap it in \c
1119 boost::cref() (where \c cref stands for \c const reference)
1121 namespace fty = senf::console::factory;
1125 senf::console::root().add("var1", fty::Variable(boost::cref(var)));
1127 A read-only variable only has a single overload:
1140 \subsection console_varattr Attributes
1142 The most important Variable command attributes are
1144 <table class="senf fixedwidth">
1146 <tr><td style="width:14em">\link senf::console::VariableAttributor::doc() .doc\endlink
1147 ( \e doc )</td><td>Set variable documentation</td></tr>
1149 <tr><td>\link senf::console::VariableAttributor::onChange() .onChange\endlink
1150 ( \e handler )</td><td>Set change handler</td></tr>
1154 \see senf::console::VariableAttributor for the complete attribute interface
1157 \subsection console_varchange Change notification
1159 A \e handler can be set to be called, whenever the variable is changed. It will be called with a
1160 reference to the old value. The handler is called, after the value has been changed
1163 namespace fty = senf::console::factory;
1167 // Since this is int, it would make sense to declare the argument pass-by-value (int old)
1168 // but for more complex args, use a const & here
1169 void varChanged(int const & old)
1174 senf::console::root().add("var2", fty::Variable(var)
1175 .onChange(&varChanged) );
1178 After this setup, \c varChanged will be called, whenever the value has changed.
1181 \section console_args Console library supported types
1183 By default, types which can be read and written using \c iostreams are automatically supported.
1184 This includes all the C++ built-in types as well as user defined streamable types.
1186 An exception is made for all \c char types: These types are by default parsed as \e numeric
1187 values not single-character data. To interpret \c char values as single-char strings, use \ref
1188 senf::console::CharAsString.
1190 \subsection console_args_stl STL container support
1192 The %console library contains support for the STL container types: \c std::vector, \c
1193 std::list, \c std::set, \c std::multiset, \c std::map and \c std::multimap.
1195 All container types are parsed as parenthesized list of elements. Each element is parsed as
1196 defined for the element type:
1198 \c vector, \c list or \c set of integers:
1203 \c vector, \c list or \c set of strings:
1205 ("String 1" "String 2" "String 3")
1208 \c vector, \c list or \c set of <tt>pair<int,string></tt>:
1210 ((1 "String 1") (2 "String 2") (3 "String 3"))
1218 Collection's with only one element may skip the parenthesis <em>if and only if</em> the element
1219 type does not need additional parenthesis
1221 A \c vector, \c list or \c set of integer with one element may be written with or without
1228 \e but a single element \c vector, \c list or \c set of <tt>pair<int,string></tt> may \e only be
1234 In mapping containers, the key and value are separated by \c =:
1236 (foo=1 bar=2 "foo bar"=3)
1240 \subsection console_args_bool Boolean arguments and return values
1242 The console library by default formats boolean values using the strings \c true and \c false for
1243 their representation. When parsing a boolean value, most sensible representations will be
1246 <table class="senf">
1247 <tr><td>\c true</td> <td>\c false</td> <td>\ref senf::console::formatTrueFalse</td></tr>
1248 <tr><td>\c on</td> <td>\c off</td> <td>\ref senf::console::formatOnOff</td></tr>
1249 <tr><td>\c enabled</td> <td>\c disabled</td> <td>\ref senf::console::formatEnabledDisabled</td></tr>
1250 <tr><td>\c yes</td> <td>\c no</td> <td>\ref senf::console::formatYesNo</td></tr>
1251 <tr><td><em>non-zero integer</em></td><td>\c 0</td><td>\ref senf::console::formatOneZero</td></tr>
1254 The boolean parser will accept these values in any (mixed) case and accepts any unique initial
1255 substring (e.g. \c Y / \c N).
1257 The last column lists explicit formatters which can be set to customize the return value
1258 formatting of a registered overload accordingly.
1261 \subsection console_args_enum Registering enum types
1263 Enum types are a special case, since it is not possible, to find a string representation for the
1264 enumerator values automatically. Therefore, enum types need to be registered manually.
1266 namespace fty = senf::console::factory;
1268 enum MyEnum { Sit, Run, Jump };
1269 SENF_CONSOLE_REGISTER_ENUM( MyEnum, (Sit)(Run)(Jump) );
1271 MyEnum fun4(MyEnum v) { return v }
1273 senf::console::root().add("test9", fty::Command(&fun4));
1276 After an enum type is registered, it can be used like any other type for arguments or
1283 server:/$ test9 Crawl
1284 argument syntax error: invalid enum value
1285 server:/$ help test9
1292 \ref SENF_CONSOLE_REGISTER_ENUM() can only be used, to register enums at namespace scope. To
1293 register enums defined within some class, use \ref SENF_CONSOLE_REGISTER_ENUM_MEMBER()
1296 namespace fty = senf::console::factory;
1301 enum Color { Red, Green, Blue };
1303 senf::console::ScopedDirectory<Test3> dir;
1307 Color mem3(Color c) { return c }
1309 SENF_CONSOLE_REGISTER_ENUM_MEMBER( Test3, Color, (Red)(Green)(Blue) );
1311 Test3::Test3() : dir(this)
1312 { dir.add("test", fty::Command(&Test3::mem3, this)); }
1315 senf::console::root().add("test3ob", test3ob.dir);
1318 Using this command/type is identical
1321 server:/$ test3ob/test Red
1323 server:/$ test3ob/test White
1324 argument syntax error: invalid enum value
1325 server:/$ help test3ob/test
1332 \subsection console_args_convert Handling argument types by conversion
1334 Sometimes an argument type is best handled by just pretending it to be of some other type. The
1335 basic idea is, to provide an explicit signature with different (but compatible) types to the
1339 namespace fty = senf::console::factory;
1346 senf::console::root()
1347 .add("test8", fty::Command<bool (bool)>(&fun4));
1350 Here, the type signature passed to fty::Command is different from the real type signature but it
1351 is compatible, the conversion is handled automatically. Since the console library now sees the
1352 argument and return value of type \c bool, the values will be parsed and formatted as boolean
1356 \subsection console_args_special Special Console types
1358 The %console library defines some special types to be used as arguments and/or return values.
1359 Some of these are wrappers around basic types which provide custom formatting. Those are used
1360 via argument type conversion (see previous section).
1362 \see \ref senf_console_utilities
1365 \subsection console_args_custom Extending the library to support additional types
1367 To support or customize parsing/formatting of other types, they need to be registered. In it's
1368 simplest case, this works, by just providing an appropriate overload for
1369 senf_console_parse_argument() and senf_console_format_value():
1373 Coordinate() : x(0), y(0) {}
1374 Coordinate(int x_, int y_) : x(x_), y(y_) {}
1379 void senf_console_parse_argument(senf::console::ParseCommandInfo::TokensRange const & tokens,
1382 senf::console::CheckedArgumentIteratorWrapper arg (tokens);
1383 senf::console::parse( *(arg++), out.x );
1384 senf::console::parse( *(arg++), out.y );
1387 void senf_console_format_value(Coordinate const & value, std::ostream & os)
1389 os << '(' << value.x << ' ' << value.y << ')';
1393 The parser will accept an argument with two tokens which are each forwarded to the integer
1394 parser. The senf::console::CheckedArgumentIteratorWrapper ensures two things: That all input
1395 tokens are parsed and no extra trailing tokens are left unparsed and it checks, that all
1396 referenced tokens really exist.
1398 The formatter writes out the value as a parenthesized pair.
1401 namespace fty = senf::console::factory;
1403 Coordinate fun5(Coordinate const & p) { return Coordinate(2*p.x, 2*p.y) }
1405 namespace kw = senf::console::kw;
1407 senf::console::root()
1408 .add("test10", fty::Command(&fun5))
1409 .arg("x","coordinate to double",
1410 kw::default_value = Coordinate())
1412 We can now call \c test10 with a coordinate argument:
1415 server:/$ test10 (2 7)
1417 server:/$ help test10
1419 test10 [x:Coordinate]
1422 x Coordinate to double
1428 If you want to customize the formatting of default values differently from the formating of
1429 return-values or if you want to change the displayed name of a type, you will need to specialize
1430 the senf::console::ArgumentTraits class instead of implementing
1431 senf_console_parse_argument(). See senf::console::ArgumentTraits and
1432 senf::console::ReturnValueTraits for more.
1439 // comment-column: 40
1440 // c-file-style: "senf"
1441 // indent-tabs-mode: nil
1442 // ispell-local-dictionary: "american"
1443 // compile-command: "scons -u test"