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 /** \defgroup console_commands Supported command types
192 The Console/config library supports quite a number of different command types. All these types
193 of command are registered, by passing them to DirectoryNode::add()
197 \section console_cmdadd Adding commands and setting attributes
199 Basically, all commands are added using senf::console::DirectoryNode::add(). What exactly
200 happens depends on the type of object added.
202 dir.add("name", callback)
204 will add a command 'name' which will execute 'callback' when called, where 'callback' can be a
205 lot of things as documented in the following chapters.
207 The add call always returns (something which can be used as) a reference to the command node
210 senf::console::CommandNode & node ( dir.add( ... ) );
213 Depending on the object added, you can also bind to a more specific node type
214 (e.g. senf::console::SimpleCommand) if you know the type of node returned.
216 Depending on the type of object added, there are additional attributes which can be set. These
217 attributes are always set by calling them on the return value <b>before saving that value as a
218 node reference</b>. It is \e not guaranteed, you can call these members on the node
221 dir.add("name", callback)
222 .doc("The documentation");
224 sets the \e doc attribute (if that is available, otherwise this will fail to compile). The
225 attribute members return value is again (something which can be used as) a reference to the
228 senf::console::CommandNode & node (
229 dir.add("name", callback)
230 .doc("The documentation") );
234 \section console_manualparse Manually parsing command arguments
236 This is the most primitive type of command. It will be called with an output stream and with a
237 senf::console::ParseCommandInfo reference which holds information about the command parsed.
239 From this information the command callback gets a list of arguments or tokens which then can be
240 interpreted in an arbitrary way.
242 void fun1(std::ostream & os, senf::console::ParseCommandInfo const & command)
244 // We take exactly one argument
245 if (command.arguments().size() != 1)
246 raise senf::console::SyntaxErrorException("invalid number of arguments");
248 senf::console::ParseCommandInfo::TokensRange & argTokens (
249 command.arguments()[0]);
251 // The argument must have exactly one token
252 if (argTokens.size() != 1)
253 raise senf::console::SyntaxErrorException("argument syntax error");
255 // Retrieve the token value
256 std::string arg (argTokens[0].value());
258 // In this example, we just write the argument to the output stream
259 os << arg << std::endl;
263 Registering this callback is done by simply adding it. To provide online help, pass it to
266 senf::console::root()
271 "Echo 'arg' to the console");
274 The callback may now be called interactively on the console by it's registered name:
278 invalid number of arguments
279 server:/$ test1 stefan@j32.de
281 server:/$ test1 (echo me)
282 argument syntax error
287 Echo 'arg' to the console
292 As you can see above, the arguments and tokens are returned as <a
293 href="http://www.boost.org/doc/libs/1_33_1/libs/range/doc/utility_class.html#iter_range">
294 boost::iterator_range</a> instances. These behave much like containers: They have \c begin() and
295 \c end() and some other useful members.
297 The parser will have divided the argument tokens into arguments already. This simplifies further
298 parsing. If however you want to access the list of argument tokens as a single list, you can do
299 so using senf::console::ParseCommandInfo::tokens().
301 Parsing arguments is quite simple but can get very tedious. To simplify this task, the parsing
302 can be delegated to the Console/config library. See the next section.
304 This type of command has only a single attribute, \e doc to set the commands documentation.
307 \section console_autoparse Automatic argument parsing
309 To greatly simplify parsing complex commands, we turn to automatic argument parsing.
311 \subsection console_autoadd Adding
313 Automatically parsed commands are registered by just adding a callback which has the correct
314 arguments and return-value defined:
316 std::string fun2(std::string const & arg)
322 This extremely simple callback may be registered by adding it to a senf::console::DirectoryNode.
324 senf::console::root()
325 .add("test2", &fun2);
327 The functionality is now identical to \c test1:
331 invalid number of arguments
332 server:/$ test2 stefan@j32.de
334 server:/$ test2 (echo me)
335 argument syntax error
344 \subsection command_ostream Accessing the console stream
346 Commands may have an optional first argument of type <tt>std::ostream &</tt>. This argument is
347 not considered part of the real interface. When the command is executed, the callback will be
348 passed the current consoles output stream object in this argument. With this, the callback can
349 output arbitrary messages to the network console.
351 void fun3(std::ostream & os, unsigned n, std::string text)
353 while (n-- > 0) os << text << std::endl;
356 senf::console::root()
357 .add("test3", &fun3);
360 This simple command can now be used thus:
364 invalid number of arguments
365 server:/$ test3 stefan@j32.de
366 invalid number of arguments
372 test3 arg11:int arg12:string
377 \subsection command_overload Overloading
379 Automatically parsed commands can be overloaded: You can register multiple commands under the
380 same name. Each overload is tried in turn until no SyntaxErrorException is raised.
382 senf::console::root()
383 .add("test4", &fun3);
384 senf::console::root()
385 .add("test4", &fun2);
387 And now, we can call \c test4 with one or two args:
390 invalid number of arguments
391 server:/$ test4 stefan@j32.de
398 1- test4 arg11:int arg12:string
399 2- test4 arg21:string
403 One note: When taking the address of an overloaded function (member or non-member), the C++
404 language forces you to cast that address to one of the possible types so the compiler knows,
405 which overload is requested. So to add a function which is overloaded in C++, each overload
406 needs to be added explicitly, casting to the correct type:
411 senf::console::root()
412 .add("over", static_cast<void (*)(int)>(&over));
413 senf::console::root()
414 .add("over", static_cast<void (*)(int,int)>(&over));
418 \subsection console_attributes Attributes
420 As have seen so far, some documentation is automatically provided. We can add more info, by
421 setting additional attributes.
423 senf::console::root()
425 .doc("Echo text to the console")
426 .overloadDoc("Repeat {arg12} for {arg11} lines");
427 senf::console::root()
429 .overloadDoc("Echo the {arg21} argument")
432 This additional info is used to provide more documentation:
437 1- test5 arg11:int arg12:string
438 2- test5 arg21:string
440 Echo text to the console
443 Repeat {arg12} for {arg11} lines
446 Echo the {arg21} argument
452 \subsection console_argattributes Argument attributes
454 Additional attributes can be set for each parameter. They are all passed to the
455 senf::console::ParsedArgumentAttributor::arg() attribute.
458 namespace kw = senf::console::kw;
460 senf::console::root()
462 .doc("Echo text to the console")
463 .overloadDoc("Repeat {text} for {n} lines");
464 .arg( kw::name = "n", kw::description="Number of repetitions" )
465 .arg( kw::name = "text", kw::description="Text to output" );
466 senf::console::root()
468 .overloadDoc("Echo the {text} argument")
469 .arg( kw::name = "text" );
472 (Sadly, there is no way to automatically find out the \e name of an argument, just it's type.)
473 Every callback argument corresponds with a call of the \c arg() attribute. Argument attributes
474 are set using keywords from the \ref senf::console::kw namespace. You will probably either use
475 this namespace via a namespace alias (as above) or via a <tt>using namespace
476 senf::console::kw</tt> declaration (but beware of name collisions).
478 You don't need to specify any information for an argument: To skip an argument, just call \c
479 arg() without attributes for this argument.
481 After adding this information, the online help is much more readable
486 1- test6 n:int text:string
490 n Number of repetitions
493 Echo text to the console
496 Repeat {text} for {n} lines
499 Echo the {text} argument
504 Since most of the time, we only need to set the name and possibly a description for arguments,
505 there is a shortcut: name and description can be specified as positional arguments in this
506 order. So the following will give the exactly same result as above:
508 namespace kw = senf::console::kw;
510 senf::console::root()
512 .doc("Echo text to the console")
513 .overloadDoc("Repeat <text> for <n> lines");
514 .arg("n", "Number of repetitions")
515 .arg("text", "Text to output");
516 senf::console::root()
518 .overloadDoc("Echo the <text> argument")
522 Keyword arguments should always be used if additional attributes are set. You can however mix
523 positional and keyword arguments.
526 \subsection console_defaults Default values
528 Another information which can not be automatically gathered from the type system is default
529 values. These have to be declared explicitly:
531 namespace kw = senf::console::kw;
533 senf::console::root()
535 .doc("Echo {text} to the console, repeating {text} for {n} lines")
536 .arg("n", "Number of repetitions", kw::default_value=1)
537 .arg("text", "Text to output");
540 Default values can be used together with overloading. Default (optional) value support is quite
541 flexible, it is not mandatory, for default values to be specified only for the trailing
542 arguments. For the exact definition, how parsed argument values are assigned to overload
543 arguments in the presence of default values, see \ref senf::console::kw::default_value.
556 test4 [n:unsigned] text:string
559 n Number of repetitions
563 Echo {text} to the console, repeating {text} for {n} lines
569 \subsection console_boostfn Non-function-pointer commands
571 It is possible to add other callable objects besides function (and member-function)
572 pointers. However, since it is not possible to automatically deduce the argument and return
573 types in this case, the callables have to be wrapped in a \c boost::function object:
576 senf::console::root()
578 boost::function<void (std::ostream &, std::string const &)>(
579 boost::bind(&fun3, _1, 4u, _2)));
582 This works with any callable object where argument types cannot be deduced automatically:
583 Boost.Bind expressions, Boost.Lambda expressions, functors and so on.
600 \subsection console_attr_summary Attribute summary
602 Here a summary of the most common attributes
604 <table class="senf fixedwidth">
606 <tr><td style="width:14em">\link senf::console::ParsedArgumentAttributorBase::doc() .doc\endlink
607 ( \e doc )</td><td>Set documentation for all overloads</td></tr>
609 <tr><td>\link senf::console::ParsedArgumentAttributorBase::overloadDoc()
610 .overloadDoc\endlink ( \e doc )</td><td>Set documentation for a specific overload</td></tr>
612 <tr><td>\link senf::console::ParsedArgumentAttributor::arg() .arg\endlink ( \e argument \e
613 attributes )</td><td>Set argument attributes (see below)</td></tr>
617 The most important argument attributes (all defined in the senf::console::kw namespace) are:
619 <table class="senf fixed width">
621 <tr><td style="width:14em">\link senf::console::kw::name kw::name\endlink</td><td>Parameter
624 <tr><td>\link senf::console::kw::description kw::description\endlink</td><td>One-line
625 description of the argument</td></tr>
627 <tr><td>\link senf::console::kw::default_value kw::default_value\endlink</td><td>Arguments
628 default value</td></tr>
633 href="classsenf_1_1console_1_1ParsedArgumentAttributor-members.html">senf::console::ParsedArgumentAttributor
634 / List of all members</a> for the complete attribute interface \n
635 \ref senf::console::kw for a list of all argument attribute keywords
638 \section console_memberfn Member functions
640 Member functions are supported like non-member functions. They must however be added through a
641 senf::console::ScopedDirectory instance to bind them to their instance.
646 senf::console::ScopedDirectory<Test1> dir;
648 Test1(std::string label) : dir(this), label_ (label)
649 { dir.add("test", &Test::test1);
650 dir.add("test", &Test::test2); }
652 std::string test1(std::string const & text)
653 { return label_ + ": " + text; }
655 void test2(std::ostream & os, unsigned n, std::string const & text)
656 { while (n-- > 0) os << label << ": " << text << std::endl; }
664 Test1 test1ob ("test");
665 senf::console::root().add("test1ob", test1ob.dir);
668 Binding via senf::console::ScopedDirectory ensures, that the commands are automatically removed
669 from the tree when the object is destroyed.
672 \section console_variables Variables
674 \subsection console_varadd Adding
676 The console/config library supports the direct registration of variables as commands. A
677 variable command consists of two overloads, one to query the current value and one to change the
683 senf::console::ScopedDirectory<Test2> dir;
685 Test2() : dir(this), var_(0)
686 { dir.add("var", var_); }
693 senf::console::root().add("test2ob", test2ob.dir);
695 This shows the most common scenario: A member variable is added to a ScopedDirectory of the same
696 class. This ensures, that the variable command node is removed from the tree when the instance
697 (and thereby the variable) are destroyed. The variable can now be used like any other command:
700 server:/$ test2ob/var
702 server:/$ test2ob/var 10
703 server:/$ test2ob/var
705 server:/$ help test2ob
714 \subsection console_varro Read-only variables
716 The library also supports read-only variables. To make a variable read-only, just wrap it in \c
717 boost::cref() (where \c cref stands for \c const reference)
721 senf::console::root().add("var1", boost::cref(var));
723 A read-only variable only has a single overload:
736 \subsection console_varattr Attributes
738 The most important Variable command attributes are
740 <table class="senf fixedwidth">
742 <tr><td style="width:14em">\link senf::console::VariableAttributor::doc() .doc\endlink
743 ( \e doc )</td><td>Set variable documentation</td></tr>
745 <tr><td>\link senf::console::VariableAttributor::onChange() .onChange\endlink
746 ( \e handler )</td><td>Set change handler</td></tr>
750 \see senf::console::VariableAttributor for the complete attribute interface
752 \subsection console_varchange Change notification
754 A \e handler can be set to be called, whenever the variable is changed. It will be called with a
755 reference to the old value. The handler is called, after the value has been changed
760 // Since this is int, it would make sense to declare the argument pass-by-value (int old)
761 // but for more complex args, use a const & here
762 void varChanged(int const & old)
767 senf::console::root().add("var2",var)
768 .onChange(&varChanged);
771 After this setup, \c varChanged will be called, whenever the value has changed.
774 \section console_args Registering special argument types
776 By default, argument types which can be read and written using \c iostreams are automatically
777 supported. Other types need to be registered explicitly
780 \subsection console_args_enum Registering enum types
782 Enum types are a special case, since it is not possible, to find a string representation for the
783 enumerator values automatically. Therefore, enum types need to be registered manually.
785 enum MyEnum { Sit, Run, Jump };
786 SENF_CONSOLE_REGISTER_ENUM( MyEnum, (Sit)(Run)(Jump) );
788 MyEnum fun4(MyEnum v) { return v }
790 senf::console::root()
791 .add("test9", &fun4);
794 After an enum type is registered, it can be used like any other type for arguments or
801 server:/$ test9 Crawl
802 argument syntax error: invalid enum value
810 \ref SENF_CONSOLE_REGISTER_ENUM() can only be used, to register enums at namespace scope. To
811 register enums defined within some class, use \ref SENF_CONSOLE_REGISTER_ENUM_MEMBER()
817 enum Color { Red, Green, Blue };
819 senf::console::ScopedDirectory<MyClass> dir;
823 Color mem3(Color c) { return c }
825 SENF_CONSOLE_REGISTER_ENUM_MEMBER( Test3, Color, (Red)(Green)(Blue) );
827 Test3::Test3() : dir(this)
828 { dir.add("test", &MyClass::mem3); }
831 senf::console::root().add("test3ob", test3ob.dir);
834 Using this command/type is identical
837 server:/$ test3ob/test Red
839 server:/$ test3ob/test White
840 argument syntax error: invalid enum value
841 server:/$ help test3ob/test
848 \subsection console_args_custom Customizing argument and return value parsing/formatting
850 To support or customize parsing/formatting of other types, they need to be registered. In it's
851 simplest case, this works, by just providing an appropriate overload for
852 senf_console_parse_argument() and senf_console_format_value():
856 Coordinate() : x(0), y(0) {}
857 Coordinate(int x_, int y_) : x(x_), y(y_) {}
862 void senf_console_parse_argument(senf::console::ParseCommandInfo::TokensRange const & tokens,
865 if (tokens.size() != 2)
866 throw SyntaxErrorException("parameter syntax error");
867 senf::console::ArgumentTraits<int>::parse(
868 senf::console::ParseCommandInfo::TokensRange( tokens.begin(), tokens.begin()+1 ),
870 senf::console::ArgumentTraits<int>::parse(
871 senf::console::ParseCommandInfo::TokensRange( tokens.begin()+1, tokens.end() ),
875 void senf_console_format_value(Coordinate const & value, std::ostream & os)
877 os << '(' << value.x << ' ' << value.y << ')';
880 The parser will accept an argument with two tokens which are each forwarded to the integer
881 parser. The formatter writes out the value as a parenthesized pair.
884 Coordinate fun5(Coordinate const & p) { return Coordinate(2*p.x, 2*p.y) }
886 namespace kw = senf::console::kw;
888 senf::console::root()
889 .add("test10", &fun5)
890 .arg("x","coordinate to double",
891 kw::default_value = Coordinate())
893 We can now call \c test10 with a coordinate argument:
896 server:/$ test10 (2 7)
898 server:/$ help test10
900 test10 [x:Coordinate]
903 x Coordinate to double
909 If you want to customize the formatting of default values differently from the formating of
910 return-values or if you want to change the displayed name of a type, you will need to specialize
911 the senf::console::ArgumentTraits class instead of implementing
912 senf_console_parse_argument(). See senf::console::ArgumentTraits and
913 senf::console::ReturnValueTraits for more.
920 // comment-column: 40
921 // c-file-style: "senf"
922 // indent-tabs-mode: nil
923 // ispell-local-dictionary: "american"
924 // compile-command: "scons -u test"