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 // Here we declare variables for the arguments
295 // We parse the arguments using the CheckedArgumentIteratorWrapper. This wrapper
296 // will throw a SyntaxErrorException if we access a nonexistent argument or if we
297 // do not parse all arguments.
298 senf::console::CheckedArgumentIteratorWrapper args (command.arguments());
300 senf::console::ParseCommandInfo::TokensRange argTokens ( *(args++) );
301 if (arg1Tokens.size() != 1)
302 raise senf::console::SyntaxErrorException("argument syntax error");
303 value = arg1Tokens[0];
306 os << value << std::endl;
310 Registering this callback is done by simply adding it. To provide online help, pass it to
313 senf::console::root()
318 "Echo 'arg' to the console");
321 The callback may now be called interactively on the console by it's registered name:
325 invalid number of arguments
326 server:/$ test1 stefan@j32.de
328 server:/$ test1 (echo me)
329 argument syntax error
334 Echo 'arg' to the console
339 As you can see above, the arguments and tokens are returned as <a
340 href="http://www.boost.org/doc/libs/1_33_1/libs/range/doc/utility_class.html#iter_range">
341 boost::iterator_range</a> instances. These behave much like containers: They have \c begin() and
342 \c end() and some other useful members.
344 The parser will have divided the argument tokens into arguments already. This simplifies further
345 parsing. If however you want to access the list of argument tokens as a single list, you can do
346 so using senf::console::ParseCommandInfo::tokens().
348 Parsing arguments is quite simple but can get very tedious. To simplify this task, the parsing
349 can be delegated to the Console/config library. See the next section.
351 This type of command has only a single attribute, \e doc to set the commands documentation.
354 \section console_autoparse Automatic argument parsing
356 To greatly simplify parsing complex commands, we turn to automatic argument parsing.
358 \subsection console_autoadd Adding
360 Automatically parsed commands are registered by just adding a callback which has the correct
361 arguments and return-value defined:
363 std::string fun2(std::string const & arg)
369 This extremely simple callback may be registered by adding it to a senf::console::DirectoryNode.
371 senf::console::root()
372 .add("test2", &fun2);
374 The functionality is now identical to \c test1:
378 invalid number of arguments
379 server:/$ test2 stefan@j32.de
381 server:/$ test2 (echo me)
382 argument syntax error
391 \subsection command_ostream Accessing the console stream
393 Commands may have an optional first argument of type <tt>std::ostream &</tt>. This argument is
394 not considered part of the real interface. When the command is executed, the callback will be
395 passed the current consoles output stream object in this argument. With this, the callback can
396 output arbitrary messages to the network console.
398 void fun3(std::ostream & os, unsigned n, std::string text)
400 while (n-- > 0) os << text << std::endl;
403 senf::console::root()
404 .add("test3", &fun3);
407 This simple command can now be used thus:
411 invalid number of arguments
412 server:/$ test3 stefan@j32.de
413 invalid number of arguments
419 test3 arg11:int arg12:string
424 \subsection command_overload Overloading
426 Automatically parsed commands can be overloaded: You can register multiple commands under the
427 same name. Each overload is tried in turn until no SyntaxErrorException is raised.
429 senf::console::root()
430 .add("test4", &fun3);
431 senf::console::root()
432 .add("test4", &fun2);
434 And now, we can call \c test4 with one or two args:
437 invalid number of arguments
438 server:/$ test4 stefan@j32.de
445 1- test4 arg11:int arg12:string
446 2- test4 arg21:string
450 One note: When taking the address of an overloaded function (member or non-member), the C++
451 language forces you to cast that address to one of the possible types so the compiler knows,
452 which overload is requested. So to add a function which is overloaded in C++, each overload
453 needs to be added explicitly, casting to the correct type:
458 senf::console::root()
459 .add("over", static_cast<void (*)(int)>(&over));
460 senf::console::root()
461 .add("over", static_cast<void (*)(int,int)>(&over));
465 \subsection console_attributes Attributes
467 As have seen so far, some documentation is automatically provided. We can add more info, by
468 setting additional attributes.
470 senf::console::root()
472 .doc("Echo text to the console")
473 .overloadDoc("Repeat {arg12} for {arg11} lines");
474 senf::console::root()
476 .overloadDoc("Echo the {arg21} argument")
479 This additional info is used to provide more documentation:
484 1- test5 arg11:int arg12:string
485 2- test5 arg21:string
487 Echo text to the console
490 Repeat {arg12} for {arg11} lines
493 Echo the {arg21} argument
499 \subsection console_argattributes Argument attributes
501 Additional attributes can be set for each parameter. They are all passed to the
502 senf::console::ParsedArgumentAttributor::arg() attribute.
505 namespace kw = senf::console::kw;
507 senf::console::root()
509 .doc("Echo text to the console")
510 .overloadDoc("Repeat {text} for {n} lines");
511 .arg( kw::name = "n", kw::description="Number of repetitions" )
512 .arg( kw::name = "text", kw::description="Text to output" );
513 senf::console::root()
515 .overloadDoc("Echo the {text} argument")
516 .arg( kw::name = "text" );
519 (Sadly, there is no way to automatically find out the \e name of an argument, just it's type.)
520 Every callback argument corresponds with a call of the \c arg() attribute. Argument attributes
521 are set using keywords from the \ref senf::console::kw namespace. You will probably either use
522 this namespace via a namespace alias (as above) or via a <tt>using namespace
523 senf::console::kw</tt> declaration (but beware of name collisions).
525 You don't need to specify any information for an argument: To skip an argument, just call \c
526 arg() without attributes for this argument.
528 After adding this information, the online help is much more readable
533 1- test6 n:int text:string
537 n Number of repetitions
540 Echo text to the console
543 Repeat {text} for {n} lines
546 Echo the {text} argument
551 Since most of the time, we only need to set the name and possibly a description for arguments,
552 there is a shortcut: name and description can be specified as positional arguments in this
553 order. So the following will give the exactly same result as above:
555 namespace kw = senf::console::kw;
557 senf::console::root()
559 .doc("Echo text to the console")
560 .overloadDoc("Repeat <text> for <n> lines");
561 .arg("n", "Number of repetitions")
562 .arg("text", "Text to output");
563 senf::console::root()
565 .overloadDoc("Echo the <text> argument")
569 Keyword arguments should always be used if additional attributes are set. You can however mix
570 positional and keyword arguments.
573 \subsection console_defaults Default values
575 Another information which can not be automatically gathered from the type system is default
576 values. These have to be declared explicitly:
578 namespace kw = senf::console::kw;
580 senf::console::root()
582 .doc("Echo {text} to the console, repeating {text} for {n} lines")
583 .arg("n", "Number of repetitions", kw::default_value=1)
584 .arg("text", "Text to output");
587 Default values can be used together with overloading. Default (optional) value support is quite
588 flexible, it is not mandatory, for default values to be specified only for the trailing
589 arguments. For the exact definition, how parsed argument values are assigned to overload
590 arguments in the presence of default values, see \ref senf::console::kw::default_value.
603 test4 [n:unsigned] text:string
606 n Number of repetitions
610 Echo {text} to the console, repeating {text} for {n} lines
616 \subsection console_boostfn Non-function-pointer commands
618 It is possible to add other callable objects besides function (and member-function)
619 pointers. However, since it is not possible to automatically deduce the argument and return
620 types in this case, the callables have to be wrapped in a \c boost::function object:
623 senf::console::root()
625 boost::function<void (std::ostream &, std::string const &)>(
626 boost::bind(&fun3, _1, 4u, _2)));
629 This works with any callable object where argument types cannot be deduced automatically:
630 Boost.Bind expressions, Boost.Lambda expressions, functors and so on.
647 \subsection console_attr_summary Attribute summary
649 Here a summary of the most common attributes
651 <table class="senf fixedwidth">
653 <tr><td style="width:14em">\link senf::console::ParsedArgumentAttributorBase::doc() .doc\endlink
654 ( \e doc )</td><td>Set documentation for all overloads</td></tr>
656 <tr><td>\link senf::console::ParsedArgumentAttributorBase::overloadDoc()
657 .overloadDoc\endlink ( \e doc )</td><td>Set documentation for a specific overload</td></tr>
659 <tr><td>\link senf::console::ParsedArgumentAttributor::arg() .arg\endlink ( \e argument \e
660 attributes )</td><td>Set argument attributes (see below)</td></tr>
664 The most important argument attributes (all defined in the senf::console::kw namespace) are:
666 <table class="senf fixed width">
668 <tr><td style="width:14em">\link senf::console::kw::name kw::name\endlink</td><td>Parameter
671 <tr><td>\link senf::console::kw::description kw::description\endlink</td><td>One-line
672 description of the argument</td></tr>
674 <tr><td>\link senf::console::kw::default_value kw::default_value\endlink</td><td>Arguments
675 default value</td></tr>
680 href="classsenf_1_1console_1_1ParsedArgumentAttributor-members.html">senf::console::ParsedArgumentAttributor
681 / List of all members</a> for the complete attribute interface \n
682 \ref senf::console::kw for a list of all argument attribute keywords
685 \section console_memberfn Member functions
687 Non-static member functions are supported like non-member functions (static member functions are
688 identical to non-members). They must however be added through a senf::console::ScopedDirectory
689 instance to bind them to their instance.
694 senf::console::ScopedDirectory<Test1> dir;
696 Test1(std::string label) : dir(this), label_ (label)
697 { dir.add("test", &Test::test1);
698 dir.add("test", &Test::test2); }
700 std::string test1(std::string const & text)
701 { return label_ + ": " + text; }
703 void test2(std::ostream & os, unsigned n, std::string const & text)
704 { while (n-- > 0) os << label << ": " << text << std::endl; }
712 Test1 test1ob ("test");
713 senf::console::root().add("test1ob", test1ob.dir);
716 Binding via senf::console::ScopedDirectory ensures, that the commands are automatically removed
717 from the tree when the object is destroyed.
720 \section console_variables Variables
722 \subsection console_varadd Adding
724 The console/config library supports the direct registration of variables as commands. A
725 variable command consists of two overloads, one to query the current value and one to change the
731 senf::console::ScopedDirectory<Test2> dir;
733 Test2() : dir(this), var_(0)
734 { dir.add("var", var_); }
741 senf::console::root().add("test2ob", test2ob.dir);
743 This shows the most common scenario: A member variable is added to a ScopedDirectory of the same
744 class. This ensures, that the variable command node is removed from the tree when the instance
745 (and thereby the variable) are destroyed. The variable can now be used like any other command:
748 server:/$ test2ob/var
750 server:/$ test2ob/var 10
751 server:/$ test2ob/var
753 server:/$ help test2ob
762 \subsection console_varro Read-only variables
764 The library also supports read-only variables. To make a variable read-only, just wrap it in \c
765 boost::cref() (where \c cref stands for \c const reference)
769 senf::console::root().add("var1", boost::cref(var));
771 A read-only variable only has a single overload:
784 \subsection console_varattr Attributes
786 The most important Variable command attributes are
788 <table class="senf fixedwidth">
790 <tr><td style="width:14em">\link senf::console::VariableAttributor::doc() .doc\endlink
791 ( \e doc )</td><td>Set variable documentation</td></tr>
793 <tr><td>\link senf::console::VariableAttributor::onChange() .onChange\endlink
794 ( \e handler )</td><td>Set change handler</td></tr>
798 \see senf::console::VariableAttributor for the complete attribute interface
800 \subsection console_varchange Change notification
802 A \e handler can be set to be called, whenever the variable is changed. It will be called with a
803 reference to the old value. The handler is called, after the value has been changed
808 // Since this is int, it would make sense to declare the argument pass-by-value (int old)
809 // but for more complex args, use a const & here
810 void varChanged(int const & old)
815 senf::console::root().add("var2",var)
816 .onChange(&varChanged);
819 After this setup, \c varChanged will be called, whenever the value has changed.
822 \section console_args Registering special argument types
824 By default, argument types which can be read and written using \c iostreams are automatically
825 supported. Other types need to be registered explicitly
828 \subsection console_args_enum Registering enum types
830 Enum types are a special case, since it is not possible, to find a string representation for the
831 enumerator values automatically. Therefore, enum types need to be registered manually.
833 enum MyEnum { Sit, Run, Jump };
834 SENF_CONSOLE_REGISTER_ENUM( MyEnum, (Sit)(Run)(Jump) );
836 MyEnum fun4(MyEnum v) { return v }
838 senf::console::root()
839 .add("test9", &fun4);
842 After an enum type is registered, it can be used like any other type for arguments or
849 server:/$ test9 Crawl
850 argument syntax error: invalid enum value
858 \ref SENF_CONSOLE_REGISTER_ENUM() can only be used, to register enums at namespace scope. To
859 register enums defined within some class, use \ref SENF_CONSOLE_REGISTER_ENUM_MEMBER()
865 enum Color { Red, Green, Blue };
867 senf::console::ScopedDirectory<MyClass> dir;
871 Color mem3(Color c) { return c }
873 SENF_CONSOLE_REGISTER_ENUM_MEMBER( Test3, Color, (Red)(Green)(Blue) );
875 Test3::Test3() : dir(this)
876 { dir.add("test", &MyClass::mem3); }
879 senf::console::root().add("test3ob", test3ob.dir);
882 Using this command/type is identical
885 server:/$ test3ob/test Red
887 server:/$ test3ob/test White
888 argument syntax error: invalid enum value
889 server:/$ help test3ob/test
896 \subsection console_args_custom Customizing argument and return value parsing/formatting
898 To support or customize parsing/formatting of other types, they need to be registered. In it's
899 simplest case, this works, by just providing an appropriate overload for
900 senf_console_parse_argument() and senf_console_format_value():
904 Coordinate() : x(0), y(0) {}
905 Coordinate(int x_, int y_) : x(x_), y(y_) {}
910 void senf_console_parse_argument(senf::console::ParseCommandInfo::TokensRange const & tokens,
913 senf::console::CheckedArgumentIteratorWrapper arg (tokens);
914 senf::console::parse( *(arg++), out.x );
915 senf::console::parse( *(arg++), out.y );
918 void senf_console_format_value(Coordinate const & value, std::ostream & os)
920 os << '(' << value.x << ' ' << value.y << ')';
924 The parser will accept an argument with two tokens which are each forwarded to the integer
925 parser. The senf::console::CheckedArgumentIteratorWrapper ensures two things: That all input
926 tokens are parsed and no extra trailing tokens are left unparsed and it checks, that all
927 referenced tokens really exist.
929 The formatter writes out the value as a parenthesized pair.
932 Coordinate fun5(Coordinate const & p) { return Coordinate(2*p.x, 2*p.y) }
934 namespace kw = senf::console::kw;
936 senf::console::root()
937 .add("test10", &fun5)
938 .arg("x","coordinate to double",
939 kw::default_value = Coordinate())
941 We can now call \c test10 with a coordinate argument:
944 server:/$ test10 (2 7)
946 server:/$ help test10
948 test10 [x:Coordinate]
951 x Coordinate to double
957 If you want to customize the formatting of default values differently from the formating of
958 return-values or if you want to change the displayed name of a type, you will need to specialize
959 the senf::console::ArgumentTraits class instead of implementing
960 senf_console_parse_argument(). See senf::console::ArgumentTraits and
961 senf::console::ReturnValueTraits for more.
968 // comment-column: 40
969 // c-file-style: "senf"
970 // indent-tabs-mode: nil
971 // ispell-local-dictionary: "american"
972 // compile-command: "scons -u test"