\see \ref node_tree
- \section intro_commands Console/config commands
+ \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
if (command.arguments().size() != 1)
raise senf::console::SyntaxErrorException("invalid number of arguments");
- senf::console::ParseCommandInfo::TokenRange & argTokens (
+ senf::console::ParseCommandInfo::TokensRange & argTokens (
command.arguments()[0]);
// The argument must have exactly one token
Commands may have an optional first argument of type <tt>std::ostream &</tt>. This argument is
not considered part of the real interface. When the command is executed, the callback will be
- passed the current console's output stream object in this argument. With this, the callback can
+ 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)
<tr><td style="width:14em">\link senf::console::VariableAttributor::doc() .doc\endlink
( \e doc )</td><td>Set variable documentation</td></tr>
- <tr><td>\link senf::console::VariableAttributor::onChange() .onchange\endlink
+ <tr><td>\link senf::console::VariableAttributor::onChange() .onChange\endlink
( \e handler )</td><td>Set change handler</td></tr>
</table>
After this setup, \c varChanged will be called, whenever the value has changed.
- \see senf::console::VariableAttributor for the complete attribute interface
+ \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
+ <pre>
+ server:/$ test9 Sit
+ Sit
+ server:/$ test9 Crawl
+ argument syntax error: invalid enum value
+ server:/$ help test9
+ Usage:
+ test9 arg11:MyEnum
+ server:/$
+ </pre>
+ \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<MyClass> 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
+ <pre>
+ server:/$ test3ob/test Red
+ Red
+ server:/$ test3ob/test White
+ argument syntax error: invalid enum value
+ server:/$ help test3ob/test
+ Usage:
+ test arg11:Color
+ </pre>
+ \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,
+ MyClass & out)
+ {
+ if (tokens.size() != 2)
+ throw SyntaxErrorException("parameter syntax error");
+ senf::console::ArgumentTraits<int>::parse(
+ senf::console::ParseCommandInfo::TokensRange( tokens.begin(), tokens.begin()+1 ),
+ out.x )
+ senf::console::ArgumentTraits<int>::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
+ <pre>
+ server:/$ test10 (2 7)
+ (4 14)
+ server:/$ help test10
+ Usage:
+ test10 [x:Coordinate]
+
+ With:
+ x Coordinate to double
+ default: (0 0)
+ server:/$
+ </pre>
+ \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.
*/
\f
EnumTable::left_map::const_iterator i (table.left.find(tokens.begin()[0].value()));
if (i == table.left.end())
- throw SyntaxErrorException("parameter syntax error: Invalid enum value");
+ throw SyntaxErrorException("parameter syntax error: invalid enum value");
return i->second;
}
/** \brief Customize return value formating
ReturnValueTraits provides return value formatting. The default implementation provided here
- will just write the value to the output stream.
+ will forward the call directly to senf_console_format_value(). The default implementation of
+ that function will write the \a value to \a os using standard iostream formatting.
- To customize this behavior for some type, specialize this class for the type.
+ To customize this behavior for some type, either provide an implementation of
+ senf_console_format_value() in the types namespace or provide a specialization of
+ ReturnValueTraits.
The output should \e not end in a newline since one is added automatically.
*/
static void format(Type const & value, std::ostream & os);
///< Write \a value to \a os
};
-
+
+ /** \brief Return value formatter
+
+ \see ReturnValuetraits
+
+ \related ReturnValueTraits
+ */
template <class Type>
void senf_console_format_value(Type const & value, std::ostream & os);
string-description of a type and to convert a value back into it's string representation
used to display default values.
- The default implementation provided here will use \c boost::lexical_cast and thereby \c
- iostreams to convert an argument consisting of a single input token into the required
- type. Types are named by returning the last component of the fully scoped name (e.g. \c
- "string" for \c std::string). Values are formatted again using \c boost::lexical_cast.
-
- To customize this behavior for some type, specialize this class for the type.
+ The default implementation provided here
+ \li will use senf_console_parse_argument() to parse a value. This functions default
+ implementation uses \c boost::lexical_cast and thereby \c iostreams to convert an
+ argument consisting of a single input token into the required type.
+ \li will name types by returning the last component of the fully scoped name (e.g. \c
+ "string" for \c std::string).
+ \li Will format values (for default value display) by forwarding the value to the
+ ReturnValueTraits of that type.
+
+ To customize just the argument parsing, just provide an implementation of
+ senf_console_parse_argument(). Alternatively or to customize type naming or default value
+ formatting, specialize ArgumentTraits for the type.
*/
template <class Type>
struct ArgumentTraits
ReturnValueTraits for this conversion. */
};
+ /** \brief Argument parser
+
+ \see ArgumentTraits
+
+ \related ArgumentTraits
+ */
template <class Type>
void senf_console_parse_argument(ParseCommandInfo::TokensRange const & tokens, Type & out);
-# define SENF_CONSOLE_REGISTER_ENUM(Type, Values) SENF_CONSOLE_REGISTER_ENUM_(Type, Values)
+ /** \brief Register enum type for argument parsing
+
+ Enum types need to be registered explicitly to support parsing.
+ \code
+ enum Foo { Foo1, Foo2 };
+ SENF_CONSOLE_REGISTER_ENUM( Foo, (Foo1)(Foo2) );
+ \endcode
+ This macro will register an enum type and it's enumerators defined at namespace scope. See
+ \ref SENF_CONSOLE_REGISTER_ENUM_MEMBER to register a member enum type.
+
+ \ingroup console_commands
+ */
+# define SENF_CONSOLE_REGISTER_ENUM(Type, Values) \
+ SENF_CONSOLE_REGISTER_ENUM_(BOOST_PP_EMPTY(), Type, Values)
+
+ /** \brief Register enum type for argument parsing
+
+ Enum types need to be registered explicitly to support parsing.
+ \code
+ class SomeClass
+ {
+ enum Foo { Foo1, Foo2 };
+ };
+
+ SENF_CONSOLE_REGISTER_ENUM_MEMBER( SomeClass, Foo, (Foo1)(Foo2) );
+ \endcode This macro will register an enum type and it's enumerators defined in a class. See
+ \ref SENF_CONSOLE_REGISTER_ENUM to register an enum type declared at namespace scope.
+
+ \ingroup console_commands
+ */
+# define SENF_CONSOLE_REGISTER_ENUM_MEMBER(Class, Type, Values) \
+ SENF_CONSOLE_REGISTER_ENUM_(Class::, Type, Values)
}}
#include <string>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>
+#include <boost/preprocessor/facilities/empty.hpp>
#include <boost/bimap.hpp>
#include <boost/assign/list_inserter.hpp>
#include "../Utils/singleton.hh"
namespace console {
namespace detail {
+#ifndef DOXYGEN
+
typedef boost::bimap<std::string, long> EnumTable;
long parseEnum(EnumTable const & table, ParseCommandInfo::TokensRange const & tokens);
EnumTable table;
};
-# define SENF_CONSOLE_REGISTER_ENUM_ELT(r,d,e) (BOOST_PP_STRINGIZE(e), static_cast<long>(e))
+# define SENF_CONSOLE_REGISTER_ENUM_ELT(r,d,e) \
+ (BOOST_PP_STRINGIZE(e), static_cast<long>(d e))
-# define SENF_CONSOLE_REGISTER_ENUM_(Type, Values) \
- void senf_console_init_enum_table(Type) \
+# define SENF_CONSOLE_REGISTER_ENUM_(Prefix, Type, Values) \
+ void senf_console_init_enum_table(Prefix Type) \
{ \
- senf::console::detail::EnumTraits<Type> & traits ( \
- senf::console::detail::EnumTraits<Type>::instance() ); \
+ senf::console::detail::EnumTraits<Prefix Type> & traits ( \
+ senf::console::detail::EnumTraits<Prefix Type>::instance() ); \
if (traits.table.empty()) \
boost::assign::insert(traits.table) \
- BOOST_PP_SEQ_FOR_EACH( SENF_CONSOLE_REGISTER_ENUM_ELT, _, Values ); \
+ BOOST_PP_SEQ_FOR_EACH( SENF_CONSOLE_REGISTER_ENUM_ELT, Prefix, Values ); \
} \
void senf_console_parse_argument( \
- senf::console::ParseCommandInfo::TokensRange const & tokens, Type & out) \
+ senf::console::ParseCommandInfo::TokensRange const & tokens, Prefix Type & out) \
{ \
- senf_console_init_enum_table( Type() ); \
- out = static_cast<Type>( \
+ senf_console_init_enum_table( Prefix Type() ); \
+ out = static_cast<Prefix Type>( \
senf::console::detail::parseEnum( \
- senf::console::detail::EnumTraits<Type>::instance().table, tokens)); \
+ senf::console::detail::EnumTraits<Prefix Type>::instance().table, tokens)); \
} \
- void senf_console_format_value(Type value, std::ostream & os) \
+ void senf_console_format_value(Prefix Type value, std::ostream & os) \
{ \
- senf_console_init_enum_table( Type() ); \
+ senf_console_init_enum_table( Prefix Type() ); \
os << senf::console::detail::formatEnum( \
- senf::console::detail::EnumTraits<Type>::instance().table, \
+ senf::console::detail::EnumTraits<Prefix Type>::instance().table, \
static_cast<long>(value) ); \
}
+#endif
+
}}}
///////////////////////////////ih.e////////////////////////////////////////
SENF_CONSOLE_REGISTER_ENUM( TestEnum, (Foo)(Bar) );
TestEnum test (TestEnum value) { return value; }
+
+ struct TestClass {
+ enum MemberEnum { MemberFoo, MemberBar };
+ static MemberEnum test (MemberEnum value) { return value; }
+ };
+ SENF_CONSOLE_REGISTER_ENUM_MEMBER( TestClass, MemberEnum, (MemberFoo)(MemberBar) );
+
}
BOOST_AUTO_UNIT_TEST(enumSupport)
parser.parse("test/test Baz",
boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )),
senf::console::SyntaxErrorException );
+
+ dir.add("member", &TestClass::test);
+
+ ss.str("");
+ BOOST_CHECK_NO_THROW(
+ parser.parse("test/member MemberFoo",
+ boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
+ BOOST_CHECK_EQUAL( ss.str(), "MemberFoo\n" );
+
+ ss.str("");
+ BOOST_CHECK_NO_THROW(
+ parser.parse("test/member MemberBar",
+ boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
+ BOOST_CHECK_EQUAL( ss.str(), "MemberBar\n" );
}
anotherCallback
api
arg
+argattributes
argc
args
+argTokens
ArgumentToken
argv
async
+attr
Augustin
+autoadd
+autoparse
autoThrottling
autotoc
aVectorCollection
BerliOS
bitfield
bool
+boostfn
bund
calculateChecksum
+callables
callback
callbacks
CapitalziedLettersToSeparateWords
checksumEnabled
checksumPresent
CIDR
+classsenf
ClientSocketHandle
CloneSource
cmd
+cmdadd
com
CommandNode
CommandOverload
CPPPATH
createAfter
createBefore
+cref
ct
cti
CXXFLAGS
ElementParser
enableChecksum
endcode
+endhtmlonly
endif
endl
endlink
ENOFILE
enum
+enums
env
eof
EPIPE
findNext
findPrev
fixedcolumn
+fixedwidth
fixme
fixvariant
flurgle
href
htm
html
+htmlonly
http
iana
ias
IPv
IPX
isock
+iter
iterator
jens
jkaeber
join
key
+kw
li
libboost
libc
MACAddress
MACAddressParser
mainpage
+manualparse
+mem
+memberfn
mixin
mkdir
MPEGDVBBundle
mpp
multicast
+MyClass
mycommand
mydir
myDirectory
+MyEnum
MyList
MyNodeType
MyParser
ob
ObjectDirectory
offene
-Ok
+ok
+onChange
onRequest
onThrottle
onUnthrottle
outputRequest
outputSocket
OverlayField
+overloadDoc
OverloadedCommand
OverloadedCommandNode
PacketData
ParseArray
parsecollection
ParseCommandInfo
+ParsedArgumentAttributor
+ParsedArgumentAttributorBase
ParseHelpers
parseint
ParseInt
SIGWINCH
SIGXCPU
SIGXFSZ
+SimpleCommand
SimpleCommandNode
SimpleCommandOverload
SimplePacketType
ThrottleBarrier
tigris
todo
+tokenizes
+TokensRange
tr
TruncatedPacketException
tt
unthrottling
Utils
var
+varadd
+varattr
+varchange
+varChanged
+VariableAttributor
+varro
VectorN
Ver
vlanId