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.
32 \section console_intro Introduction
34 There are three parts to the Config/console library:
36 \li The console/config library is based on a \link node_tree tree of console/config
38 \li Besides directories, the node contains command nodes. Commands are based on \link
39 console_commands variables or callbacks.\endlink
40 \li The console/config library is utilized by writing configuration files or interactive
41 commands in \link console_parser the console/config language.\endlink
43 The node tree works like a directory structure. Commands are entered into this directory
44 structure and can be called passing arbitrary arguments. Configuration parameters are just
45 commands which set their respective parameter, however the library allows commands to do much
48 \section console_example Example
50 The following example shows a \e very short summary on how to integrate the config/console
51 library. See above links for more:
54 #include <senf/Console.hh>
56 // Define callback function.
57 void mycommand(std::ostream & os, int foo, int bar)
60 os << "!! Important message ...\n";
63 namespace kw = senf::console::kw;
67 // Provide global documentation
69 .doc("This is someServer server");
73 .add("mycommand", &mycommand)
74 .doc("If <bar> is given, flurgle the <foo>, otherwise burgle it")
76 .arg(kw::name = "bar", kw::default_value = 0);
78 // Start the interactive console server
79 senf::console::Server::start(senf::INet4SocketAddress(senf::INet4Address::None, 23232u))
84 after this registration, the console can be accessed easily via telnet:
87 $ telnet localhost 23232
89 Connected to localhost.
90 Escape character is '^]'
91 xxxx-xx-xx xx:xx:xx.xxxxxx-0000 [NOTICE][senf::console::Server] Registered new client 0xxxxxxx
94 someServer:/# mycommand
95 !! Important message ...
97 xxxx-xx-xx xx:xx:xx.xxxxxx-0000 [NOTICE][senf::console::Server] Disposing client 0xxxxxxx
98 Connection closed by foreign host.
102 \see \ref console_testserver for a complete example application
104 \section intro_init Initialization
106 To make the console accessible, it must be initialized when the program is started:
108 #include <senf/Console.hh>
110 int main(int argc, char * argv [])
112 // Configure console nodes, add commands ...
114 // Start console server
115 senf::console::start(senf::INet4SocketAddress(12345u))
118 // You need to enter the scheduler main-loop for the server to work
119 senf::Scheduler::instance().process();
121 // Alternatively enter the main-loop via the PPI
126 This will start the server on IPv4 port 12345. The servers name (as displayed in the interactive
127 console prompt) is set to 'myserver'.
129 After launching the application, the server can be accessed at the given port:
132 bash$ telnet localhost 12345
134 Connected to localhost.
135 Escape character is '^]'.
138 Connection closed by foreign host.
143 \section intro_nodes The node tree
145 The basic idea is, that the console/config library manages a directory structure of parameters
146 and auxiliary commands. Parameters are just commands which set a parameter value so everything
147 is either a directory entry (senf::console::DirectoryNode) or a command
148 (senf::console::CommandNode).
153 \section intro_commands Registering console/config commands
155 The console/config language does not define, how arguments are passed to the commands, it just
156 tokenizes the input and passes the tokens to the commands which then handle the
159 Since parsing the tokens into something usable is quite tedious and error prone, the library
160 implements automatic argument parsing where the argument tokens are automatically parsed
161 depending on argument types. This enables you to register a command taking an integer argument
162 which will be called with an already parsed integer value (or throw a
163 senf::console::SyntaxErrorException if the conversion fails). This will be the most often used
166 \see \ref console_commands
169 \section intro_language The console/config language
171 To call the commands and set parameters, a very simple language is defined. The language is
172 almost declarative (e.g. it does not have any control-flow statements) but is processed
173 imperatively from top to bottom. This is very simple and flexible.
175 Commands are referenced by their path in the node tree. To simplify working with deeply nested
176 directory structures, the current directory may be changed persistently or temporarily for some
181 /logger/targets/console {
182 accept senf::log::Debug IMPORTANT;
183 accept server::ServerLog CRITICAL;
187 \see \ref console_parser
190 \section console_misc Further features
192 \subsection console_serverclient Server and Client objects
194 The senf::console::Server and senf::console::Client objects offer further API calls. To access
195 the server instance you need to store away the senf::console::Server reference returned when
196 starting the server so you can later refer to it:
198 int main(int, char**)
200 senf::console::Server & server ( senf::console::start( ... ) );
208 The client instance can be accessed via the \c std::ostream arg of any command callback
210 void someCallback(std::ostream & os, ... )
212 senf::console::Client & client (senf::console::Client::get(os));
214 // Use the client's log target
215 client.route<senf::log::Debug, senf::Log::IMPORTANT>();
220 senf::console::Server for the Server API \n
221 <a href="classsenf_1_1console_1_1Client-members.html">senf::console::Client / List of all
222 members</a> for the Client API
225 \subsection console_shell Features of the interactive console shell
227 The interactive shell will use the GNU readline library for the first connected
228 instance. Further users will not have access to this functionality since GNU readline is
229 completely non-reentrant.
231 The shell supports auto-cd and auto-completion: If you enter the name of a directory at the
232 prompt, the console will change to that directory. With auto-completion, any unique beginning of
233 a path component will be completed automatically and transparently to th corresponding full
237 /** \defgroup console_commands Supported command types
239 The Console/config library supports quite a number of different command types. All these types
240 of command are registered, by passing them to DirectoryNode::add()
244 \section console_cmdadd Adding commands and setting attributes
246 Basically, all commands are added using senf::console::DirectoryNode::add(). What exactly
247 happens depends on the type of object added.
249 dir.add("name", callback)
251 will add a command 'name' which will execute 'callback' when called, where 'callback' can be a
252 lot of things as documented in the following chapters.
254 The add call always returns (something which can be used as) a reference to the command node
257 senf::console::CommandNode & node ( dir.add( ... ) );
260 Depending on the object added, you can also bind to a more specific node type
261 (e.g. senf::console::SimpleCommand) if you know the type of node returned.
263 Depending on the type of object added, there are additional attributes which can be set. These
264 attributes are always set by calling them on the return value <b>before saving that value as a
265 node reference</b>. It is \e not guaranteed, you can call these members on the node
268 dir.add("name", callback)
269 .doc("The documentation");
271 sets the \e doc attribute (if that is available, otherwise this will fail to compile). The
272 attribute members return value is again (something which can be used as) a reference to the
275 senf::console::CommandNode & node (
276 dir.add("name", callback)
277 .doc("The documentation") );
281 \section console_manualparse Manually parsing command arguments
283 This is the most primitive type of command. It will be called with an output stream and with a
284 senf::console::ParseCommandInfo reference which holds information about the command parsed.
286 From this information the command callback gets a list of arguments or tokens which then can be
287 interpreted in an arbitrary way.
289 void fun1(std::ostream & os, senf::console::ParseCommandInfo const & command)
291 ParseCommandInfo::ArgumentsRange args (command.arguments());
292 ParseCommandInfo::ArgumentsRange::iterator arg (args.begin());
294 // Check that we are not missing our argument
295 if (arg == args.end())
296 raise senf::console::SyntaxErrorException("invalid number of arguments");
298 senf::console::ParseCommandInfo::TokensRange & arg1Tokens ( *(arg++) );
300 // Check that we don't have additional arguments
301 if (arg != args.end())
302 raise senf::console::SyntaxErrorException("invalid number of arguments");
304 // The argument must have exactly one token
305 if (arg1Tokens.size() != 1)
306 raise senf::console::SyntaxErrorException("argument syntax error");
308 // Retrieve the token value
309 std::string arg (argTokens[0].value());
311 // In this example, we just write the argument to the output stream
312 os << arg << std::endl;
316 Registering this callback is done by simply adding it. To provide online help, pass it to
319 senf::console::root()
324 "Echo 'arg' to the console");
327 The callback may now be called interactively on the console by it's registered name:
331 invalid number of arguments
332 server:/$ test1 stefan@j32.de
334 server:/$ test1 (echo me)
335 argument syntax error
340 Echo 'arg' to the console
345 As you can see above, the arguments and tokens are returned as <a
346 href="http://www.boost.org/doc/libs/1_33_1/libs/range/doc/utility_class.html#iter_range">
347 boost::iterator_range</a> instances. These behave much like containers: They have \c begin() and
348 \c end() and some other useful members.
350 The parser will have divided the argument tokens into arguments already. This simplifies further
351 parsing. If however you want to access the list of argument tokens as a single list, you can do
352 so using senf::console::ParseCommandInfo::tokens().
354 Parsing arguments is quite simple but can get very tedious. To simplify this task, the parsing
355 can be delegated to the Console/config library. See the next section.
357 This type of command has only a single attribute, \e doc to set the commands documentation.
360 \section console_autoparse Automatic argument parsing
362 To greatly simplify parsing complex commands, we turn to automatic argument parsing.
364 \subsection console_autoadd Adding
366 Automatically parsed commands are registered by just adding a callback which has the correct
367 arguments and return-value defined:
369 std::string fun2(std::string const & arg)
375 This extremely simple callback may be registered by adding it to a senf::console::DirectoryNode.
377 senf::console::root()
378 .add("test2", &fun2);
380 The functionality is now identical to \c test1:
384 invalid number of arguments
385 server:/$ test2 stefan@j32.de
387 server:/$ test2 (echo me)
388 argument syntax error
397 \subsection command_ostream Accessing the console stream
399 Commands may have an optional first argument of type <tt>std::ostream &</tt>. This argument is
400 not considered part of the real interface. When the command is executed, the callback will be
401 passed the current consoles output stream object in this argument. With this, the callback can
402 output arbitrary messages to the network console.
404 void fun3(std::ostream & os, unsigned n, std::string text)
406 while (n-- > 0) os << text << std::endl;
409 senf::console::root()
410 .add("test3", &fun3);
413 This simple command can now be used thus:
417 invalid number of arguments
418 server:/$ test3 stefan@j32.de
419 invalid number of arguments
425 test3 arg11:int arg12:string
430 \subsection command_overload Overloading
432 Automatically parsed commands can be overloaded: You can register multiple commands under the
433 same name. Each overload is tried in turn until no SyntaxErrorException is raised.
435 senf::console::root()
436 .add("test4", &fun3);
437 senf::console::root()
438 .add("test4", &fun2);
440 And now, we can call \c test4 with one or two args:
443 invalid number of arguments
444 server:/$ test4 stefan@j32.de
451 1- test4 arg11:int arg12:string
452 2- test4 arg21:string
456 One note: When taking the address of an overloaded function (member or non-member), the C++
457 language forces you to cast that address to one of the possible types so the compiler knows,
458 which overload is requested. So to add a function which is overloaded in C++, each overload
459 needs to be added explicitly, casting to the correct type:
464 senf::console::root()
465 .add("over", static_cast<void (*)(int)>(&over));
466 senf::console::root()
467 .add("over", static_cast<void (*)(int,int)>(&over));
471 \subsection console_attributes Attributes
473 As have seen so far, some documentation is automatically provided. We can add more info, by
474 setting additional attributes.
476 senf::console::root()
478 .doc("Echo text to the console")
479 .overloadDoc("Repeat {arg12} for {arg11} lines");
480 senf::console::root()
482 .overloadDoc("Echo the {arg21} argument")
485 This additional info is used to provide more documentation:
490 1- test5 arg11:int arg12:string
491 2- test5 arg21:string
493 Echo text to the console
496 Repeat {arg12} for {arg11} lines
499 Echo the {arg21} argument
505 \subsection console_argattributes Argument attributes
507 Additional attributes can be set for each parameter. They are all passed to the
508 senf::console::ParsedArgumentAttributor::arg() attribute.
511 namespace kw = senf::console::kw;
513 senf::console::root()
515 .doc("Echo text to the console")
516 .overloadDoc("Repeat {text} for {n} lines");
517 .arg( kw::name = "n", kw::description="Number of repetitions" )
518 .arg( kw::name = "text", kw::description="Text to output" );
519 senf::console::root()
521 .overloadDoc("Echo the {text} argument")
522 .arg( kw::name = "text" );
525 (Sadly, there is no way to automatically find out the \e name of an argument, just it's type.)
526 Every callback argument corresponds with a call of the \c arg() attribute. Argument attributes
527 are set using keywords from the \ref senf::console::kw namespace. You will probably either use
528 this namespace via a namespace alias (as above) or via a <tt>using namespace
529 senf::console::kw</tt> declaration (but beware of name collisions).
531 You don't need to specify any information for an argument: To skip an argument, just call \c
532 arg() without attributes for this argument.
534 After adding this information, the online help is much more readable
539 1- test6 n:int text:string
543 n Number of repetitions
546 Echo text to the console
549 Repeat {text} for {n} lines
552 Echo the {text} argument
557 Since most of the time, we only need to set the name and possibly a description for arguments,
558 there is a shortcut: name and description can be specified as positional arguments in this
559 order. So the following will give the exactly same result as above:
561 namespace kw = senf::console::kw;
563 senf::console::root()
565 .doc("Echo text to the console")
566 .overloadDoc("Repeat <text> for <n> lines");
567 .arg("n", "Number of repetitions")
568 .arg("text", "Text to output");
569 senf::console::root()
571 .overloadDoc("Echo the <text> argument")
575 Keyword arguments should always be used if additional attributes are set. You can however mix
576 positional and keyword arguments.
579 \subsection console_defaults Default values
581 Another information which can not be automatically gathered from the type system is default
582 values. These have to be declared explicitly:
584 namespace kw = senf::console::kw;
586 senf::console::root()
588 .doc("Echo {text} to the console, repeating {text} for {n} lines")
589 .arg("n", "Number of repetitions", kw::default_value=1)
590 .arg("text", "Text to output");
593 Default values can be used together with overloading. Default (optional) value support is quite
594 flexible, it is not mandatory, for default values to be specified only for the trailing
595 arguments. For the exact definition, how parsed argument values are assigned to overload
596 arguments in the presence of default values, see \ref senf::console::kw::default_value.
609 test4 [n:unsigned] text:string
612 n Number of repetitions
616 Echo {text} to the console, repeating {text} for {n} lines
622 \subsection console_boostfn Non-function-pointer commands
624 It is possible to add other callable objects besides function (and member-function)
625 pointers. However, since it is not possible to automatically deduce the argument and return
626 types in this case, the callables have to be wrapped in a \c boost::function object:
629 senf::console::root()
631 boost::function<void (std::ostream &, std::string const &)>(
632 boost::bind(&fun3, _1, 4u, _2)));
635 This works with any callable object where argument types cannot be deduced automatically:
636 Boost.Bind expressions, Boost.Lambda expressions, functors and so on.
653 \subsection console_attr_summary Attribute summary
655 Here a summary of the most common attributes
657 <table class="senf fixedwidth">
659 <tr><td style="width:14em">\link senf::console::ParsedArgumentAttributorBase::doc() .doc\endlink
660 ( \e doc )</td><td>Set documentation for all overloads</td></tr>
662 <tr><td>\link senf::console::ParsedArgumentAttributorBase::overloadDoc()
663 .overloadDoc\endlink ( \e doc )</td><td>Set documentation for a specific overload</td></tr>
665 <tr><td>\link senf::console::ParsedArgumentAttributor::arg() .arg\endlink ( \e argument \e
666 attributes )</td><td>Set argument attributes (see below)</td></tr>
670 The most important argument attributes (all defined in the senf::console::kw namespace) are:
672 <table class="senf fixed width">
674 <tr><td style="width:14em">\link senf::console::kw::name kw::name\endlink</td><td>Parameter
677 <tr><td>\link senf::console::kw::description kw::description\endlink</td><td>One-line
678 description of the argument</td></tr>
680 <tr><td>\link senf::console::kw::default_value kw::default_value\endlink</td><td>Arguments
681 default value</td></tr>
686 href="classsenf_1_1console_1_1ParsedArgumentAttributor-members.html">senf::console::ParsedArgumentAttributor
687 / List of all members</a> for the complete attribute interface \n
688 \ref senf::console::kw for a list of all argument attribute keywords
691 \section console_memberfn Member functions
693 Non-static member functions are supported like non-member functions (static member functions are
694 identical to non-members). They must however be added through a senf::console::ScopedDirectory
695 instance to bind them to their instance.
700 senf::console::ScopedDirectory<Test1> dir;
702 Test1(std::string label) : dir(this), label_ (label)
703 { dir.add("test", &Test::test1);
704 dir.add("test", &Test::test2); }
706 std::string test1(std::string const & text)
707 { return label_ + ": " + text; }
709 void test2(std::ostream & os, unsigned n, std::string const & text)
710 { while (n-- > 0) os << label << ": " << text << std::endl; }
718 Test1 test1ob ("test");
719 senf::console::root().add("test1ob", test1ob.dir);
722 Binding via senf::console::ScopedDirectory ensures, that the commands are automatically removed
723 from the tree when the object is destroyed.
726 \section console_variables Variables
728 \subsection console_varadd Adding
730 The console/config library supports the direct registration of variables as commands. A
731 variable command consists of two overloads, one to query the current value and one to change the
737 senf::console::ScopedDirectory<Test2> dir;
739 Test2() : dir(this), var_(0)
740 { dir.add("var", var_); }
747 senf::console::root().add("test2ob", test2ob.dir);
749 This shows the most common scenario: A member variable is added to a ScopedDirectory of the same
750 class. This ensures, that the variable command node is removed from the tree when the instance
751 (and thereby the variable) are destroyed. The variable can now be used like any other command:
754 server:/$ test2ob/var
756 server:/$ test2ob/var 10
757 server:/$ test2ob/var
759 server:/$ help test2ob
768 \subsection console_varro Read-only variables
770 The library also supports read-only variables. To make a variable read-only, just wrap it in \c
771 boost::cref() (where \c cref stands for \c const reference)
775 senf::console::root().add("var1", boost::cref(var));
777 A read-only variable only has a single overload:
790 \subsection console_varattr Attributes
792 The most important Variable command attributes are
794 <table class="senf fixedwidth">
796 <tr><td style="width:14em">\link senf::console::VariableAttributor::doc() .doc\endlink
797 ( \e doc )</td><td>Set variable documentation</td></tr>
799 <tr><td>\link senf::console::VariableAttributor::onChange() .onChange\endlink
800 ( \e handler )</td><td>Set change handler</td></tr>
804 \see senf::console::VariableAttributor for the complete attribute interface
806 \subsection console_varchange Change notification
808 A \e handler can be set to be called, whenever the variable is changed. It will be called with a
809 reference to the old value. The handler is called, after the value has been changed
814 // Since this is int, it would make sense to declare the argument pass-by-value (int old)
815 // but for more complex args, use a const & here
816 void varChanged(int const & old)
821 senf::console::root().add("var2",var)
822 .onChange(&varChanged);
825 After this setup, \c varChanged will be called, whenever the value has changed.
828 \section console_args Registering special argument types
830 By default, argument types which can be read and written using \c iostreams are automatically
831 supported. Other types need to be registered explicitly
834 \subsection console_args_enum Registering enum types
836 Enum types are a special case, since it is not possible, to find a string representation for the
837 enumerator values automatically. Therefore, enum types need to be registered manually.
839 enum MyEnum { Sit, Run, Jump };
840 SENF_CONSOLE_REGISTER_ENUM( MyEnum, (Sit)(Run)(Jump) );
842 MyEnum fun4(MyEnum v) { return v }
844 senf::console::root()
845 .add("test9", &fun4);
848 After an enum type is registered, it can be used like any other type for arguments or
855 server:/$ test9 Crawl
856 argument syntax error: invalid enum value
864 \ref SENF_CONSOLE_REGISTER_ENUM() can only be used, to register enums at namespace scope. To
865 register enums defined within some class, use \ref SENF_CONSOLE_REGISTER_ENUM_MEMBER()
871 enum Color { Red, Green, Blue };
873 senf::console::ScopedDirectory<MyClass> dir;
877 Color mem3(Color c) { return c }
879 SENF_CONSOLE_REGISTER_ENUM_MEMBER( Test3, Color, (Red)(Green)(Blue) );
881 Test3::Test3() : dir(this)
882 { dir.add("test", &MyClass::mem3); }
885 senf::console::root().add("test3ob", test3ob.dir);
888 Using this command/type is identical
891 server:/$ test3ob/test Red
893 server:/$ test3ob/test White
894 argument syntax error: invalid enum value
895 server:/$ help test3ob/test
902 \subsection console_args_custom Customizing argument and return value parsing/formatting
904 To support or customize parsing/formatting of other types, they need to be registered. In it's
905 simplest case, this works, by just providing an appropriate overload for
906 senf_console_parse_argument() and senf_console_format_value():
910 Coordinate() : x(0), y(0) {}
911 Coordinate(int x_, int y_) : x(x_), y(y_) {}
916 void senf_console_parse_argument(senf::console::ParseCommandInfo::TokensRange const & tokens,
919 if (tokens.size() != 2)
920 throw SyntaxErrorException("parameter syntax error");
921 senf::console::ArgumentTraits<int>::parse(
922 senf::console::ParseCommandInfo::TokensRange( tokens.begin(), tokens.begin()+1 ),
924 senf::console::ArgumentTraits<int>::parse(
925 senf::console::ParseCommandInfo::TokensRange( tokens.begin()+1, tokens.end() ),
929 void senf_console_format_value(Coordinate const & value, std::ostream & os)
931 os << '(' << value.x << ' ' << value.y << ')';
934 The parser will accept an argument with two tokens which are each forwarded to the integer
935 parser. The formatter writes out the value as a parenthesized pair.
938 Coordinate fun5(Coordinate const & p) { return Coordinate(2*p.x, 2*p.y) }
940 namespace kw = senf::console::kw;
942 senf::console::root()
943 .add("test10", &fun5)
944 .arg("x","coordinate to double",
945 kw::default_value = Coordinate())
947 We can now call \c test10 with a coordinate argument:
950 server:/$ test10 (2 7)
952 server:/$ help test10
954 test10 [x:Coordinate]
957 x Coordinate to double
963 If you want to customize the formatting of default values differently from the formating of
964 return-values or if you want to change the displayed name of a type, you will need to specialize
965 the senf::console::ArgumentTraits class instead of implementing
966 senf_console_parse_argument(). See senf::console::ArgumentTraits and
967 senf::console::ReturnValueTraits for more.
974 // comment-column: 40
975 // c-file-style: "senf"
976 // indent-tabs-mode: nil
977 // ispell-local-dictionary: "american"
978 // compile-command: "scons -u test"