Skip to content
Snippets Groups Projects
Commit efd1e14d authored by g0dil's avatar g0dil
Browse files

Console: Extended boolean parsing / formatting

parent c19cda97
No related branches found
No related tags found
No related merge requests found
......@@ -29,6 +29,7 @@
\autotoc
\section console_intro Introduction
There are three parts to the Config/console library:
......@@ -47,6 +48,7 @@
commands which set their respective parameter, however the library allows commands to do much
more than just that.
\section console_example Example
The following example shows a \e very short summary on how to integrate the config/console
......@@ -115,6 +117,7 @@
\see \ref console_testserver for a complete example application
\section intro_usage Access
There are several ways to access the node tree:
......@@ -124,6 +127,7 @@
\see console_access
\section intro_nodes The node tree
The basic idea is, that the console/config library manages a directory structure of parameters
......@@ -157,6 +161,7 @@
\autotoc
\section console_access_config Configuration support
The configuration support of the Console/Config library revolves around the ConfigSource
......@@ -175,6 +180,7 @@
node used during parsing and it is also possible to restrict parsing to a command subset. See
\ref console_access_partial.
\subsection console_access_file Configuration files
<table class="senf fixedwidth">
......@@ -203,6 +209,7 @@
and a user specific configuration file) see \ref console_access_multiple and add one (or more)
senf::console::FileConfig() source to a senf::console::ConfigBundle.
\subsubsection console_access_file_syntax Configuration file syntax
Configuration files are written in a simple configuration language. This language is almost
......@@ -223,6 +230,7 @@
\see \ref console_parser
\subsection console_access_options Command line options
<table class="senf fixedwidth">
......@@ -258,6 +266,7 @@
See \ref senf::console::ProgramOptions for the source specific additional parameters. These
apply to senf::console::ProgramOptions and to the senf::console::OptionsConfig() source.
\subsubsection console_access_options_syntax Options syntax
Command line options are primarily parsed as long-options. Long options start with '--'. Further
......@@ -327,6 +336,7 @@
(Beware, that the second argument to \c alias() is \e not shell quoted).
\subsection console_access_root Changing the root node
When used in it's default state, parsing will always interpret all commands relative to the
......@@ -347,6 +357,7 @@
selectively choose commands from the node tree which are to be made accessible for
configuration. See \ref node_tree.
\subsection console_access_partial Partial / incremental configuration
Another feature provided by senf::console::ConfigBundle and all helper classes is partial
......@@ -378,6 +389,7 @@
important: It allows a subsystem to parse it's configuration parameters irrespective of any
links pointing to nodes of that subsystem.
\subsection console_access_multiple Multiple sources
Most of the time, an application will utilize multiple configuration sources: A global
......@@ -421,6 +433,7 @@
order they are specified, so in this case, the command line options will override any options
specified in one of the configuration files.
\section console_access_console The network console
To make the network console accessible, it must be initialized when the program is started:
......@@ -460,6 +473,10 @@
</pre>
\endhtmlonly
It is possible to start multiple server consoles by calling \c start() multiple times with
different ports/addresses. Each server can be configured separately (e.g. root node, mode ...).q
\subsection console_serverclient Server and Client objects
The senf::console::Server and senf::console::Client objects offer further API calls. To access
......@@ -505,6 +522,7 @@
a path component will be completed automatically and transparently to the corresponding full
name.
\subsection console_noninteractive Non-interactive network console
After a new connection is established, the console server waits a short time for data to arrive.
......@@ -543,6 +561,7 @@
\autotoc
\section console_cmdadd Adding commands and setting attributes
Basically, all commands are added using senf::console::DirectoryNode::add(). What exactly
......@@ -657,6 +676,7 @@
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
......@@ -723,6 +743,7 @@
</pre>
\endhtmlonly
\subsection command_overload Overloading
Automatically parsed commands can be overloaded: You can register multiple commands under the
......@@ -1099,6 +1120,7 @@
\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
......@@ -1121,12 +1143,33 @@
After this setup, \c varChanged will be called, whenever the value has changed.
\section console_args Registering special argument types
\section console_args 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_bool Boolean arguments and return values
The console library by default formats boolean values using the strings \c true and \c false for
their representation. When parsing a boolean value, most sensible representations will be
accepted:
<table class="senf">
<tr><td>\c true</td> <td>\c false</td> <td>\ref senf::console::formatTrueFalse</td></tr>
<tr><td>\c on</td> <td>\c off</td> <td>\ref senf::console::formatOnOff</td></tr>
<tr><td>\c enabled</td> <td>\c disabled</td> <td>\ref senf::console::formatEnabledDisabled</td></tr>
<tr><td>\c yes</td> <td>\c no</td> <td>\ref senf::console::formatYesNo</td></tr>
<tr><td><em>non-zero integer</em></td><td>\c 0</td><td>\ref senf::console::formatOneZero</td></tr>
</table>
The boolean parser will accept these values in any (mixed) case and accepts any unique initial
substring (e.g. \c Y / \c N).
The last column lists explicit formatters which can be set to customize the return value
formatting of a registered overload accordingly.
\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
......@@ -1195,7 +1238,7 @@
\endhtmlonly
\subsection console_args_custom Customizing argument and return value parsing/formatting
\subsection console_args_custom Extending the library to support additional types
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
......
......@@ -62,6 +62,8 @@ namespace detail {
/** \brief Internal: Nonblocking boost::iostreams::sink
The sink discards data if the output socket would.
\fixme Don't throw exceptions ... set stream error indicator (if at all)
*/
class NonblockingSocketSink
: public boost::iostreams::sink
......
// $Id$
//
// Copyright (C) 2008
// Fraunhofer Institute for Open Communication Systems (FOKUS)
// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief Traits inline non-template implementation */
#include "Traits.ih"
// Custom includes
#include <boost/algorithm/string/predicate.hpp>
#define prefix_ inline
///////////////////////////////cci.p///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// senf::console::ArgumentTraits<bool>
prefix_ void
senf::console::ArgumentTraits<bool>::parse(ParseCommandInfo::TokensRange const & tokens,
bool & out)
{
if (tokens.size() != 1)
throw SyntaxErrorException("argument syntax error");
if ( boost::istarts_with(std::string("true"), tokens.begin()->value())
|| boost::istarts_with(std::string("enabled"), tokens.begin()->value())
|| boost::istarts_with(std::string("yes"), tokens.begin()->value())
|| boost::iequals(std::string("on"), tokens.begin()->value()) )
out = true;
else if (boost::istarts_with(std::string("false"), tokens.begin()->value())
|| boost::istarts_with(std::string("disabled"), tokens.begin()->value())
|| boost::istarts_with(std::string("no"), tokens.begin()->value())
|| (boost::istarts_with(std::string("off"), tokens.begin()->value())
&& tokens.begin()->value().size() >= 2) )
out = false;
else {
int v (0);
senf::console::parse(tokens, v);
out = v;
}
}
prefix_ std::string senf::console::ArgumentTraits<bool>::description()
{
return "bool";
}
prefix_ std::string senf::console::ArgumentTraits<bool>::str(bool value)
{
return value ? "true" : "false";
}
///////////////////////////////////////////////////////////////////////////
// senf::console::ReturnValueTraits<bool>
prefix_ void senf::console::ReturnValueTraits<bool>::format(bool value, std::ostream & os)
{
formatTrueFalse(value, os);
}
///////////////////////////////////////////////////////////////////////////
prefix_ void senf::console::formatTrueFalse(bool value, std::ostream & os)
{
os << (value ? "true" : "false");
}
prefix_ void senf::console::formatYesNo(bool value, std::ostream & os)
{
os << (value ? "yes" : "no");
}
prefix_ void senf::console::formatEnabledDisabled(bool value, std::ostream & os)
{
os << (value ? "enabled" : "disabled");
}
prefix_ void senf::console::formatOnOff(bool value, std::ostream & os)
{
os << (value ? "on" : "off");
}
prefix_ void senf::console::formatOneZero(bool value, std::ostream & os)
{
os << (value ? "0" : "1");
}
///////////////////////////////cci.e///////////////////////////////////////
#undef prefix_
// Local Variables:
// mode: c++
// fill-column: 100
// comment-column: 40
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
// compile-command: "scons -u test"
// End:
......@@ -133,6 +133,44 @@ namespace console {
template <class Type>
void parse(ParseCommandInfo::TokensRange const & tokens, Type & out);
#ifndef DOXYGEN
// Parse bool: true/false, yes/no, enabled/disabled, 0/1
template <>
struct ArgumentTraits<bool>
{
typedef bool type;
static void parse(ParseCommandInfo::TokensRange const & tokens, bool & out);
static std::string description();
static std::string str(bool value);
};
template <>
struct ReturnValueTraits<bool>
{
typedef bool type;
static void format(bool value, std::ostream & os);
};
#endif
/** \brief Format boolean value as \c true / \c false */
void formatTrueFalse(bool value, std::ostream & os);
/** \brief Format boolean value as \c yes / \c no */
void formatYesNo(bool value, std::ostream & os);
/** \brief Format boolean value as \c enabled / \c disabled */
void formatEnabledDisabled(bool value, std::ostream & os);
/** \brief Format boolean value as \c on / \c off */
void formatOnOff(bool value, std::ostream & os);
/** \brief Format boolean value as \c 1 / \c 0 */
void formatOneZero(bool value, std::ostream & os);
/** \brief Register enum type for argument parsing
Enum types need to be registered explicitly to support parsing.
......@@ -169,7 +207,7 @@ namespace console {
}}
///////////////////////////////hh.e////////////////////////////////////////
//#include "Traits.cci"
#include "Traits.cci"
#include "Traits.ct"
#include "Traits.cti"
#endif
......
......@@ -50,7 +50,49 @@ namespace {
static MemberEnum test (MemberEnum value) { return value; }
};
SENF_CONSOLE_REGISTER_ENUM_MEMBER( TestClass, MemberEnum, (MemberFoo)(MemberBar) );
bool boolTest(bool value) { return value; }
}
BOOST_AUTO_UNIT_TEST(boolTraits)
{
senf::console::Executor executor;
senf::console::CommandParser parser;
senf::console::ScopedDirectory<> dir;
senf::console::root().add("test", dir);
dir.add("test", &boolTest);
std::stringstream ss;
BOOST_CHECK_NO_THROW(
parser.parse("test/test true; test/test false",
boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
BOOST_CHECK_EQUAL( ss.str(), "true\n" "false\n" );
ss.str("");
BOOST_CHECK_NO_THROW(
parser.parse("test/test enabled; test/test disabled",
boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
BOOST_CHECK_EQUAL( ss.str(), "true\n" "false\n" );
ss.str("");
BOOST_CHECK_NO_THROW(
parser.parse("test/test yes; test/test no",
boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
BOOST_CHECK_EQUAL( ss.str(), "true\n" "false\n" );
ss.str("");
BOOST_CHECK_NO_THROW(
parser.parse("test/test Y; test/test enA",
boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
BOOST_CHECK_EQUAL( ss.str(), "true\n" "true\n" );
dir.add("test2", &boolTest).formatter( senf::console::formatEnabledDisabled );
ss.str("");
BOOST_CHECK_NO_THROW(
parser.parse("test/test2 0; test/test2 -1",
boost::bind<void>( boost::ref(executor), boost::ref(ss), _1 )) );
BOOST_CHECK_EQUAL( ss.str(), "disabled\n" "enabled\n" );
}
BOOST_AUTO_UNIT_TEST(enumSupport)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment