From: g0dil Date: Fri, 30 May 2008 16:23:49 +0000 (+0000) Subject: Console: Extended boolean parsing / formatting X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=9d97626a51a793a3f882b31ebbeae6239602c612;p=senf.git Console: Extended boolean parsing / formatting git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@864 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Console/Mainpage.dox b/Console/Mainpage.dox index 46f8a05..b0440b0 100644 --- a/Console/Mainpage.dox +++ b/Console/Mainpage.dox @@ -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 @@ -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
@@ -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 @@ \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 @@ \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: + +
+ + + + + +
\c true \c false \ref senf::console::formatTrueFalse
\c on \c off \ref senf::console::formatOnOff
\c enabled \c disabled \ref senf::console::formatEnabledDisabled
\c yes \c no \ref senf::console::formatYesNo
non-zero integer\c 0\ref senf::console::formatOneZero
+ + 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 diff --git a/Console/Server.ih b/Console/Server.ih index b107867..925fd64 100644 --- a/Console/Server.ih +++ b/Console/Server.ih @@ -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 diff --git a/Console/Traits.cci b/Console/Traits.cci new file mode 100644 index 0000000..6625e60 --- /dev/null +++ b/Console/Traits.cci @@ -0,0 +1,119 @@ +// $Id$ +// +// Copyright (C) 2008 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// 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 + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::console::ArgumentTraits + +prefix_ void +senf::console::ArgumentTraits::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::description() +{ + return "bool"; +} + +prefix_ std::string senf::console::ArgumentTraits::str(bool value) +{ + return value ? "true" : "false"; +} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::ReturnValueTraits + +prefix_ void senf::console::ReturnValueTraits::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: diff --git a/Console/Traits.hh b/Console/Traits.hh index 69533b4..b647dd4 100644 --- a/Console/Traits.hh +++ b/Console/Traits.hh @@ -133,6 +133,44 @@ namespace console { template void parse(ParseCommandInfo::TokensRange const & tokens, Type & out); +#ifndef DOXYGEN + + // Parse bool: true/false, yes/no, enabled/disabled, 0/1 + template <> + struct ArgumentTraits + { + 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 + { + 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 diff --git a/Console/Traits.test.cc b/Console/Traits.test.cc index b11c4b5..bc122ea 100644 --- a/Console/Traits.test.cc +++ b/Console/Traits.test.cc @@ -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( 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( 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( 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( 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( boost::ref(executor), boost::ref(ss), _1 )) ); + BOOST_CHECK_EQUAL( ss.str(), "disabled\n" "enabled\n" ); } BOOST_AUTO_UNIT_TEST(enumSupport)