X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Console%2FMainpage.dox;h=e6cf4044619e9bdd08139ecd985b55d3e19ede5c;hb=1b1d76302a5d61e918ef71f1c8e11f80ac1262e2;hp=9c0ea9a8c2a1041c67dfc74197f18dd62bdb748e;hpb=be33ff96c5b89738694da272d8610564cce48bfb;p=senf.git diff --git a/Console/Mainpage.dox b/Console/Mainpage.dox index 9c0ea9a..e6cf404 100644 --- a/Console/Mainpage.dox +++ b/Console/Mainpage.dox @@ -20,28 +20,30 @@ // Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -/** \mainpage The Configuration and Runtime Control Framework +/** \mainpage The Configuration and Runtime Control Library The Console library implements a runtime interactive (network) console which allows to configure, control and manipulate a running application in any way. Additionally this library provides support for configuration files and command line parsing which can be used with or without the network console. - \section console_intro Introduction + \autotoc - There are two components to the Config/console framework: + \section console_intro Introduction - \li Building the node tree by registering objects and callbacks - \li Utilizing the config/console framework by writing configuration files or using the - interactive console. + There are three parts to the Config/console library: - Basic data structure of the console and config framework is the config/console node tree. This - tree. This tree works like a file-system. Commands are added to this tree and can then be called - from configuration files or from the interactive console. + \li The console/config library is based on a \link node_tree tree of console/config + nodes. \endlink + \li Besides directories, the node contains command nodes. Commands are based on \link + console_commands variables or callbacks.\endlink + \li The console/config library is utilized by writing configuration files or interactive + commands in \link console_parser the console/config language.\endlink - To get started using the config/console library, see - \li \ref node_tree - \li \ref console_parser + The node tree works like a directory structure. Commands are entered into this directory + structure and can be called passing arbitrary arguments. Configuration parameters are just + commands which set their respective parameter, however the library allows commands to do much + more than just that. \section console_example Example @@ -49,13 +51,17 @@ library. See above links for more: \code + #include + // Define callback function. - void mycommand(std::ostream & os, senf::console::ParseCommandInfo const & command) + void mycommand(std::ostream & os, int foo, int bar) { // ... os << "!! Important message ...\n"; } + namespace kw = senf::console::kw; + int main(int, char**) { // Provide global documentation @@ -65,8 +71,9 @@ // Add a command senf::console::root() .add("mycommand", &mycommand) - .doc("mycommand []\n\n" - "If is given, flurgle the , otherwise burgle it"); + .doc("If is given, flurgle the , otherwise burgle it") + .arg("foo") + .arg(kw::name = "bar", kw::default_value = 0); // Start the interactive console server senf::console::Server::start(senf::INet4SocketAddress(senf::INet4Address::None, 23232u)) @@ -91,6 +98,867 @@ Connection closed by foreign host. $ + + \see \ref console_testserver for a complete example application + + \section intro_init Initialization + + To make the console accessible, it must be initialized when the program is started: + \code + #include + + int main(int argc, char * argv []) + { + // Configure console nodes, add commands ... + + // Start console server + senf::console::start(senf::INet4SocketAddress(12345u)) + .name("myserver"); + + // You need to enter the scheduler main-loop for the server to work + senf::Scheduler::instance().process(); + + // Alternatively enter the main-loop via the PPI + // senf::ppi::run(); + } + \endcode + + This will start the server on IPv4 port 12345. The servers name (as displayed in the interactive + console prompt) is set to 'myserver'. + + After launching the application, the server can be accessed at the given port: + \htmlonly +
+    bash$ telnet localhost 12345
+    Trying 127.0.0.1...
+    Connected to localhost.
+    Escape character is '^]'.
+
+    myserver:/$ exit
+    Connection closed by foreign host.
+    bash$
+    
+ \endhtmlonly + + \section intro_nodes The node tree + + The basic idea is, that the console/config library manages a directory structure of parameters + and auxiliary commands. Parameters are just commands which set a parameter value so everything + is either a directory entry (senf::console::DirectoryNode) or a command + (senf::console::CommandNode). + + \see \ref node_tree + + + \section intro_commands Registering console/config commands + + The console/config language does not define, how arguments are passed to the commands, it just + tokenizes the input and passes the tokens to the commands which then handle the + conversion. + + Since parsing the tokens into something usable is quite tedious and error prone, the library + implements automatic argument parsing where the argument tokens are automatically parsed + depending on argument types. This enables you to register a command taking an integer argument + which will be called with an already parsed integer value (or throw a + senf::console::SyntaxErrorException if the conversion fails). This will be the most often used + command. + + \see \ref console_commands + + + \section intro_language The console/config language + + To call the commands and set parameters, a very simple language is defined. The language is + almost declarative (e.g. it does not have any control-flow statements) but is processed + imperatively from top to bottom. This is very simple and flexible. + + Commands are referenced by their path in the node tree. To simplify working with deeply nested + directory structures, the current directory may be changed persistently or temporarily for some + commands. + \code + /server/port 1234; + + /logger/targets/console { + accept senf::log::Debug IMPORTANT; + accept server::ServerLog CRITICAL; + } + \endcode + + \see \ref console_parser + + + \section console_misc Further features + + \subsection console_serverclient Server and Client objects + + The senf::console::Server and senf::console::Client objects offer further API calls. To access + the server instance you need to store away the senf::console::Server reference returned when + starting the server so you can later refer to it: + \code + int main(int, char**) + { + senf::console::Server & server ( senf::console::start( ... ) ); + + // Do something ... + + server.stop() + } + \endcode + + The client instance can be accessed via the \c std::ostream arg of any command callback + \code + void someCallback(std::ostream & os, ... ) + { + senf::console::Client & client (senf::console::Client::get(os)); + + // Use the client's log target + client.route(); + } + \endcode + + \see + senf::console::Server for the Server API \n + senf::console::Client / List of all + members for the Client API + + + \subsection console_shell Features of the interactive console shell + + The interactive shell will use the GNU readline library for the first connected + instance. Further users will not have access to this functionality since GNU readline is + completely non-reentrant. + + The shell supports auto-cd and auto-completion: If you enter the name of a directory at the + prompt, the console will change to that directory. With auto-completion, any unique beginning of + a path component will be completed automatically and transparently to th corresponding full + name. + */ + +/** \defgroup console_commands Supported command types + + The Console/config library supports quite a number of different command types. All these types + of command are registered, by passing them to DirectoryNode::add() + + \autotoc + + \section console_cmdadd Adding commands and setting attributes + + Basically, all commands are added using senf::console::DirectoryNode::add(). What exactly + happens depends on the type of object added. + \code + dir.add("name", callback) + \endcode + will add a command 'name' which will execute 'callback' when called, where 'callback' can be a + lot of things as documented in the following chapters. + + The add call always returns (something which can be used as) a reference to the command node + added: + \code + senf::console::CommandNode & node ( dir.add( ... ) ); + \endcode + + Depending on the object added, you can also bind to a more specific node type + (e.g. senf::console::SimpleCommand) if you know the type of node returned. + + Depending on the type of object added, there are additional attributes which can be set. These + attributes are always set by calling them on the return value before saving that value as a + node reference. It is \e not guaranteed, you can call these members on the node + reference. + \code + dir.add("name", callback) + .doc("The documentation"); + \endcode + sets the \e doc attribute (if that is available, otherwise this will fail to compile). The + attribute members return value is again (something which can be used as) a reference to the + command node + \code + senf::console::CommandNode & node ( + dir.add("name", callback) + .doc("The documentation") ); + \endcode + + + \section console_manualparse Manually parsing command arguments + + This is the most primitive type of command. It will be called with an output stream and with a + senf::console::ParseCommandInfo reference which holds information about the command parsed. + + From this information the command callback gets a list of arguments or tokens which then can be + interpreted in an arbitrary way. + \code + void fun1(std::ostream & os, senf::console::ParseCommandInfo const & command) + { + // We take exactly one argument + if (command.arguments().size() != 1) + raise senf::console::SyntaxErrorException("invalid number of arguments"); + + senf::console::ParseCommandInfo::TokensRange & argTokens ( + command.arguments()[0]); + + // The argument must have exactly one token + if (argTokens.size() != 1) + raise senf::console::SyntaxErrorException("argument syntax error"); + + // Retrieve the token value + std::string arg (argTokens[0].value()); + + // In this example, we just write the argument to the output stream + os << arg << std::endl; + } + \endcode + + Registering this callback is done by simply adding it. To provide online help, pass it to + 'doc()': + \code + senf::console::root() + .add("test1", &fun1) + .doc("Usage:\n" + " test1 arg\n" + "\n" + "Echo 'arg' to the console"); + \endcode + + The callback may now be called interactively on the console by it's registered name: + \htmlonly +
+    server:/$ test1
+    invalid number of arguments
+    server:/$ test1 stefan@j32.de
+    stefan@j32.de
+    server:/$ test1 (echo me)
+    argument syntax error
+    server:/$ help test1
+    Usage:
+        test1 arg
+
+    Echo 'arg' to the console
+    server:/$
+    
+ \endhtmlonly + + As you can see above, the arguments and tokens are returned as + boost::iterator_range instances. These behave much like containers: They have \c begin() and + \c end() and some other useful members. + + The parser will have divided the argument tokens into arguments already. This simplifies further + parsing. If however you want to access the list of argument tokens as a single list, you can do + so using senf::console::ParseCommandInfo::tokens(). + + Parsing arguments is quite simple but can get very tedious. To simplify this task, the parsing + can be delegated to the Console/config library. See the next section. + + This type of command has only a single attribute, \e doc to set the commands documentation. + + + \section console_autoparse Automatic argument parsing + + To greatly simplify parsing complex commands, we turn to automatic argument parsing. + + \subsection console_autoadd Adding + + Automatically parsed commands are registered by just adding a callback which has the correct + arguments and return-value defined: + \code + std::string fun2(std::string const & arg) + { + return arg; + } + \endcode + + This extremely simple callback may be registered by adding it to a senf::console::DirectoryNode. + \code + senf::console::root() + .add("test2", &fun2); + \endcode + The functionality is now identical to \c test1: + \htmlonly +
+    server:/$ test2
+    invalid number of arguments
+    server:/$ test2 stefan@j32.de
+    stefan@j32.de
+    server:/$ test2 (echo me)
+    argument syntax error
+    server:/$ help test2
+    Usage:
+        test2 arg11:string
+    server:/$
+    
+ \endhtmlonly + + + \subsection command_ostream Accessing the console stream + + Commands may have an optional first argument of type std::ostream &. This argument is + not considered part of the real interface. When the command is executed, the callback will be + passed the current consoles output stream object in this argument. With this, the callback can + output arbitrary messages to the network console. + \code + void fun3(std::ostream & os, unsigned n, std::string text) + { + while (n-- > 0) os << text << std::endl; + } + + senf::console::root() + .add("test3", &fun3); + \endcode + + This simple command can now be used thus: + \htmlonly +
+    server:/$ test3
+    invalid number of arguments
+    server:/$ test3 stefan@j32.de
+    invalid number of arguments
+    server:/$ test3 2 ok
+    ok
+    ok
+    server:/$ help test3
+    Usage:
+        test3 arg11:int arg12:string
+    server:/$
+    
+ \endhtmlonly + + \subsection command_overload Overloading + + Automatically parsed commands can be overloaded: You can register multiple commands under the + same name. Each overload is tried in turn until no SyntaxErrorException is raised. + \code + senf::console::root() + .add("test4", &fun3); + senf::console::root() + .add("test4", &fun2); + \endcode + And now, we can call \c test4 with one or two args: +
+    server:/$ test4
+    invalid number of arguments
+    server:/$ test4 stefan@j32.de
+    stefan@j32.de
+    server:/$ test4 2 ok
+    ok
+    ok
+    server:/$ help test4
+    Usage:
+        1- test4 arg11:int arg12:string
+        2- test4 arg21:string
+    server:/$
+    
+ + One note: When taking the address of an overloaded function (member or non-member), the C++ + language forces you to cast that address to one of the possible types so the compiler knows, + which overload is requested. So to add a function which is overloaded in C++, each overload + needs to be added explicitly, casting to the correct type: + \code + void over(int); + void over(int,int); + + senf::console::root() + .add("over", static_cast(&over)); + senf::console::root() + .add("over", static_cast(&over)); + \endcode + + + \subsection console_attributes Attributes + + As have seen so far, some documentation is automatically provided. We can add more info, by + setting additional attributes. + \code + senf::console::root() + .add("test5", &fun3) + .doc("Echo text to the console") + .overloadDoc("Repeat {arg12} for {arg11} lines"); + senf::console::root() + .add("test4", &fun2) + .overloadDoc("Echo the {arg21} argument") + \endcode + + This additional info is used to provide more documentation: + \htmlonly +
+    server:/$ help test5
+    Usage:
+        1- test5 arg11:int arg12:string
+        2- test5 arg21:string
+
+    Echo text to the console
+
+    Variant 1:
+    Repeat {arg12} for {arg11} lines
+    
+    Variant 2:
+    Echo the {arg21} argument
+    senf:/$
+    
+ \endhtmlonly + + + \subsection console_argattributes Argument attributes + + Additional attributes can be set for each parameter. They are all passed to the + senf::console::ParsedArgumentAttributor::arg() attribute. + + \code + namespace kw = senf::console::kw; + + senf::console::root() + .add("test6", &fun3) + .doc("Echo text to the console") + .overloadDoc("Repeat {text} for {n} lines"); + .arg( kw::name = "n", kw::description="Number of repetitions" ) + .arg( kw::name = "text", kw::description="Text to output" ); + senf::console::root() + .add("test6", &fun2) + .overloadDoc("Echo the {text} argument") + .arg( kw::name = "text" ); + \endcode + + (Sadly, there is no way to automatically find out the \e name of an argument, just it's type.) + Every callback argument corresponds with a call of the \c arg() attribute. Argument attributes + are set using keywords from the \ref senf::console::kw namespace. You will probably either use + this namespace via a namespace alias (as above) or via a using namespace + senf::console::kw declaration (but beware of name collisions). + + You don't need to specify any information for an argument: To skip an argument, just call \c + arg() without attributes for this argument. + + After adding this information, the online help is much more readable + \htmlonly +
+    server:/$ help test6
+    Usage:
+        1- test6 n:int text:string
+        2- test6 text:string
+
+    With:
+        n         Number of repetitions
+        text      Text to output
+
+    Echo text to the console
+
+    Variant 1:
+    Repeat {text} for {n} lines
+    
+    Variant 2:
+    Echo the {text} argument
+    senf:/$
+    
+ \endhtmlonly + + Since most of the time, we only need to set the name and possibly a description for arguments, + there is a shortcut: name and description can be specified as positional arguments in this + order. So the following will give the exactly same result as above: + \code + namespace kw = senf::console::kw; + + senf::console::root() + .add("test6", &fun3) + .doc("Echo text to the console") + .overloadDoc("Repeat for lines"); + .arg("n", "Number of repetitions") + .arg("text", "Text to output"); + senf::console::root() + .add("test6", &fun2) + .overloadDoc("Echo the argument") + .arg("text"); + \endcode + + Keyword arguments should always be used if additional attributes are set. You can however mix + positional and keyword arguments. + + + \subsection console_defaults Default values + + Another information which can not be automatically gathered from the type system is default + values. These have to be declared explicitly: + \code + namespace kw = senf::console::kw; + + senf::console::root() + .add("test7", &fun3) + .doc("Echo {text} to the console, repeating {text} for {n} lines") + .arg("n", "Number of repetitions", kw::default_value=1) + .arg("text", "Text to output"); + \endcode + + Default values can be used together with overloading. Default (optional) value support is quite + flexible, it is not mandatory, for default values to be specified only for the trailing + arguments. For the exact definition, how parsed argument values are assigned to overload + arguments in the presence of default values, see \ref senf::console::kw::default_value. + + \htmlonly +
+    server:/$ test7 echo
+    echo
+    server:/$ test7 4 ok
+    ok
+    ok
+    ok
+    ok
+    server:/$ help test7
+    Usage:
+        test4 [n:unsigned] text:string
+    
+    With:
+        n         Number of repetitions
+            default: 1
+        text      Text to output
+
+    Echo {text} to the console, repeating {text} for {n} lines
+    server:/$
+    
+ \endhtmlonly + + + \subsection console_boostfn Non-function-pointer commands + + It is possible to add other callable objects besides function (and member-function) + pointers. However, since it is not possible to automatically deduce the argument and return + types in this case, the callables have to be wrapped in a \c boost::function object: + + \code + senf::console::root() + .add("test8", + boost::function( + boost::bind(&fun3, _1, 4u, _2))); + \endcode + + This works with any callable object where argument types cannot be deduced automatically: + Boost.Bind expressions, Boost.Lambda expressions, functors and so on. + + \htmlonly +
+    server:/$ test8 ok
+    ok
+    ok
+    ok
+    ok
+    server:/$ help test8
+    Usage:
+        test8 arg11:string
+    server:/$
+    
+ \endhtmlonly + + + \subsection console_attr_summary Attribute summary + + Here a summary of the most common attributes + + + + + + + + + +
\link senf::console::ParsedArgumentAttributorBase::doc() .doc\endlink + ( \e doc )Set documentation for all overloads
\link senf::console::ParsedArgumentAttributorBase::overloadDoc() + .overloadDoc\endlink ( \e doc )Set documentation for a specific overload
\link senf::console::ParsedArgumentAttributor::arg() .arg\endlink ( \e argument \e + attributes )Set argument attributes (see below)
+ + The most important argument attributes (all defined in the senf::console::kw namespace) are: + + + + + + + + + +
\link senf::console::kw::name kw::name\endlinkParameter + name
\link senf::console::kw::description kw::description\endlinkOne-line + description of the argument
\link senf::console::kw::default_value kw::default_value\endlinkArguments + default value
+ + \see senf::console::ParsedArgumentAttributor + / List of all members for the complete attribute interface \n + \ref senf::console::kw for a list of all argument attribute keywords + + + \section console_memberfn Member functions + + Non-static member functions are supported like non-member functions (static member functions are + identical to non-members). They must however be added through a senf::console::ScopedDirectory + instance to bind them to their instance. + \code + class Test1 + { + public: + senf::console::ScopedDirectory dir; + + Test1(std::string label) : dir(this), label_ (label) + { dir.add("test", &Test::test1); + dir.add("test", &Test::test2); } + + std::string test1(std::string const & text) + { return label_ + ": " + text; } + + void test2(std::ostream & os, unsigned n, std::string const & text) + { while (n-- > 0) os << label << ": " << text << std::endl; } + + private: + std::string label_; + }; + + // ... + + Test1 test1ob ("test"); + senf::console::root().add("test1ob", test1ob.dir); + \endcode + + Binding via senf::console::ScopedDirectory ensures, that the commands are automatically removed + from the tree when the object is destroyed. + + + \section console_variables Variables + + \subsection console_varadd Adding + + The console/config library supports the direct registration of variables as commands. A + variable command consists of two overloads, one to query the current value and one to change the + value. + \code + class Test2 + { + public: + senf::console::ScopedDirectory dir; + + Test2() : dir(this), var_(0) + { dir.add("var", var_); } + + private: + int var_; + }; + + Test2 test2ob; + senf::console::root().add("test2ob", test2ob.dir); + \endcode + This shows the most common scenario: A member variable is added to a ScopedDirectory of the same + class. This ensures, that the variable command node is removed from the tree when the instance + (and thereby the variable) are destroyed. The variable can now be used like any other command: + \htmlonly +
+    server:/$ test2ob/var
+    0
+    server:/$ test2ob/var 10
+    server:/$ test2ob/var
+    10
+    server:/$ help test2ob
+    Usage:
+        1- var new_value:int
+        2- var
+    server:/$
+    
+ \endhtmlonly + + + \subsection console_varro Read-only variables + + The library also supports read-only variables. To make a variable read-only, just wrap it in \c + boost::cref() (where \c cref stands for \c const reference) + \code + int var (0); + + senf::console::root().add("var1", boost::cref(var)); + \endcode + A read-only variable only has a single overload: + \htmlonly +
+    server:/$ var1
+    0
+    server:/$ help var1
+    Usage:
+        var1
+    server:/$ 
+    
+ \endhtmlonly + + + \subsection console_varattr Attributes + + The most important Variable command attributes are + + + + + + + +
\link senf::console::VariableAttributor::doc() .doc\endlink + ( \e doc )Set variable documentation
\link senf::console::VariableAttributor::onChange() .onChange\endlink + ( \e handler )Set change handler
+ + \see senf::console::VariableAttributor for the complete attribute interface + + \subsection console_varchange Change notification + + A \e handler can be set to be called, whenever the variable is changed. It will be called with a + reference to the old value. The handler is called, after the value has been changed + + \code + int var (0); + + // Since this is int, it would make sense to declare the argument pass-by-value (int old) + // but for more complex args, use a const & here + void varChanged(int const & old) + { + // ... + } + + senf::console::root().add("var2",var) + .onChange(&varChanged); + \endcode + + After this setup, \c varChanged will be called, whenever the value has changed. + + + \section console_args Registering special argument types + + By default, argument types which can be read and written using \c iostreams are automatically + supported. Other types need to be registered explicitly + + + \subsection console_args_enum Registering enum types + + Enum types are a special case, since it is not possible, to find a string representation for the + enumerator values automatically. Therefore, enum types need to be registered manually. + \code + enum MyEnum { Sit, Run, Jump }; + SENF_CONSOLE_REGISTER_ENUM( MyEnum, (Sit)(Run)(Jump) ); + + MyEnum fun4(MyEnum v) { return v } + + senf::console::root() + .add("test9", &fun4); + \endcode + + After an enum type is registered, it can be used like any other type for arguments or + return-values: + + \htmlonly +
+    server:/$ test9 Sit
+    Sit
+    server:/$ test9 Crawl
+    argument syntax error: invalid enum value
+    server:/$ help test9
+    Usage:
+        test9 arg11:MyEnum
+    server:/$
+    
+ \endhtmlonly + + \ref SENF_CONSOLE_REGISTER_ENUM() can only be used, to register enums at namespace scope. To + register enums defined within some class, use \ref SENF_CONSOLE_REGISTER_ENUM_MEMBER() + + \code + class Test3 + { + public: + enum Color { Red, Green, Blue }; + + senf::console::ScopedDirectory dir; + + Test3(); + + Color mem3(Color c) { return c } + }; + SENF_CONSOLE_REGISTER_ENUM_MEMBER( Test3, Color, (Red)(Green)(Blue) ); + + Test3::Test3() : dir(this) + { dir.add("test", &MyClass::mem3); } + + Test3 test3ob; + senf::console::root().add("test3ob", test3ob.dir); + \endcode + + Using this command/type is identical + \htmlonly +
+    server:/$ test3ob/test Red
+    Red
+    server:/$ test3ob/test White
+    argument syntax error: invalid enum value
+    server:/$ help test3ob/test
+    Usage:
+        test arg11:Color
+    
+ \endhtmlonly + + + \subsection console_args_custom Customizing argument and return value parsing/formatting + + To support or customize parsing/formatting of other types, they need to be registered. In it's + simplest case, this works, by just providing an appropriate overload for + senf_console_parse_argument() and senf_console_format_value(): + \code + struct Coordinate + { + Coordinate() : x(0), y(0) {} + Coordinate(int x_, int y_) : x(x_), y(y_) {} + + int x, y; + } + + void senf_console_parse_argument(senf::console::ParseCommandInfo::TokensRange const & tokens, + Coordinate & out) + { + if (tokens.size() != 2) + throw SyntaxErrorException("parameter syntax error"); + senf::console::ArgumentTraits::parse( + senf::console::ParseCommandInfo::TokensRange( tokens.begin(), tokens.begin()+1 ), + out.x ) + senf::console::ArgumentTraits::parse( + senf::console::ParseCommandInfo::TokensRange( tokens.begin()+1, tokens.end() ), + out.y ) + } + + void senf_console_format_value(Coordinate const & value, std::ostream & os) + { + os << '(' << value.x << ' ' << value.y << ')'; + } + \endcode + The parser will accept an argument with two tokens which are each forwarded to the integer + parser. The formatter writes out the value as a parenthesized pair. + + \code + Coordinate fun5(Coordinate const & p) { return Coordinate(2*p.x, 2*p.y) } + + namespace kw = senf::console::kw; + + senf::console::root() + .add("test10", &fun5) + .arg("x","coordinate to double", + kw::default_value = Coordinate()) + \endcode + We can now call \c test10 with a coordinate argument: + \htmlonly +
+    server:/$ test10 (2 7)
+    (4 14)
+    server:/$ help test10
+    Usage:
+        test10 [x:Coordinate]
+
+    With:
+        x         Coordinate to double
+            default: (0 0)
+    server:/$
+    
+ \endhtmlonly + + If you want to customize the formatting of default values differently from the formating of + return-values or if you want to change the displayed name of a type, you will need to specialize + the senf::console::ArgumentTraits class instead of implementing + senf_console_parse_argument(). See senf::console::ArgumentTraits and + senf::console::ReturnValueTraits for more. */ @@ -102,6 +970,6 @@ // indent-tabs-mode: nil // ispell-local-dictionary: "american" // compile-command: "scons -u test" -// mode: flyspell // mode: auto-fill // End: +