From: g0dil Date: Tue, 3 Mar 2009 09:39:42 +0000 (+0000) Subject: Utils/Console: Extend enum parsing to ignore case and accept arbitrary unique initial... X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=4941cc3d46b3c8066eee01846e2d8de01b87e4e2;p=senf.git Utils/Console: Extend enum parsing to ignore case and accept arbitrary unique initial substrings as valid enum value git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1139 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Utils/Console/Traits.cc b/Utils/Console/Traits.cc index 1f082eb..c1e1cbc 100644 --- a/Utils/Console/Traits.cc +++ b/Utils/Console/Traits.cc @@ -39,10 +39,21 @@ prefix_ long senf::console::detail::parseEnum(EnumTable const & table, if (tokens.size() != 1) throw SyntaxErrorException("parameter syntax error"); - 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"); - return i->second; + std::string sym (tokens.begin()[0].value()); + boost::algorithm::to_lower(sym); + EnumTable::left_map::const_iterator i1 (table.left.lower_bound(sym)); + EnumTable::left_map::const_iterator i2 (table.left.lower_bound(sym+"\xff")); + if (i1 == i2) + throw SyntaxErrorException("parameter syntax error: invalid enum value: ") + << tokens.begin()[0].value(); + long v (i1->second); + if (boost::algorithm::to_lower_copy(i1->first) == sym) + return v; + ++i1; + if (i1 != i2) + throw SyntaxErrorException("parameter syntax error: ambiguous enum value: ") + << tokens.begin()[0].value(); + return v; } prefix_ std::string senf::console::detail::formatEnum(EnumTable const & table, long value) diff --git a/Utils/Console/Traits.hh b/Utils/Console/Traits.hh index f7fa1e4..df2a6a8 100644 --- a/Utils/Console/Traits.hh +++ b/Utils/Console/Traits.hh @@ -184,6 +184,10 @@ namespace console { 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. + \note All enumerator values must be unique ignoring case. + + The enum parser will accept any unique initial substring ignoring case as valid enum value. + \ingroup console_commands */ # define SENF_CONSOLE_REGISTER_ENUM(Type, Values) \ diff --git a/Utils/Console/Traits.ih b/Utils/Console/Traits.ih index b9f3b1b..bac962a 100644 --- a/Utils/Console/Traits.ih +++ b/Utils/Console/Traits.ih @@ -33,6 +33,7 @@ #include #include #include +#include #include "../../Utils/singleton.hh" ///////////////////////////////ih.p//////////////////////////////////////// @@ -42,45 +43,41 @@ namespace console { namespace detail { #ifndef DOXYGEN + struct StringILess + { + bool operator()(std::string const & left, std::string const & right) const + { return boost::algorithm::to_lower_copy(left) + < boost::algorithm::to_lower_copy(right); } + }; - typedef boost::bimap EnumTable; + typedef boost::bimap, long> EnumTable; long parseEnum(EnumTable const & table, ParseCommandInfo::TokensRange const & tokens); std::string formatEnum(EnumTable const & table, long value); - template - struct EnumTraits : public senf::singleton< EnumTraits > - { - using senf::singleton< EnumTraits >::instance; - EnumTable table; - }; - # define SENF_CONSOLE_REGISTER_ENUM_ELT(r,d,e) \ - (BOOST_PP_STRINGIZE(e), static_cast(d e)) + ( BOOST_PP_STRINGIZE(e), static_cast(d e) ) # define SENF_CONSOLE_REGISTER_ENUM_(Prefix, Type, Values) \ - void senf_console_init_enum_table(Prefix Type) \ + senf::console::detail::EnumTable & senf_console_enum_table(Prefix Type) \ { \ - senf::console::detail::EnumTraits & traits ( \ - senf::console::detail::EnumTraits::instance() ); \ - if (traits.table.empty()) \ - boost::assign::insert(traits.table) \ + static senf::console::detail::EnumTable table; \ + if (table.empty()) \ + boost::assign::insert(table) \ BOOST_PP_SEQ_FOR_EACH( SENF_CONSOLE_REGISTER_ENUM_ELT, Prefix, Values ); \ + return table; \ } \ void senf_console_parse_argument( \ senf::console::ParseCommandInfo::TokensRange const & tokens, Prefix Type & out) \ { \ - senf_console_init_enum_table( Prefix Type() ); \ out = static_cast( \ senf::console::detail::parseEnum( \ - senf::console::detail::EnumTraits::instance().table, tokens)); \ + senf_console_enum_table( Prefix Type() ), tokens) ); \ } \ void senf_console_format_value(Prefix Type value, std::ostream & os) \ { \ - senf_console_init_enum_table( Prefix Type() ); \ os << senf::console::detail::formatEnum( \ - senf::console::detail::EnumTraits::instance().table, \ - static_cast(value) ); \ + senf_console_enum_table( Prefix Type() ), static_cast(value) ); \ } #endif diff --git a/Utils/Console/Traits.test.cc b/Utils/Console/Traits.test.cc index 054f993..2e54245 100644 --- a/Utils/Console/Traits.test.cc +++ b/Utils/Console/Traits.test.cc @@ -40,8 +40,8 @@ ///////////////////////////////cc.p//////////////////////////////////////// namespace { - enum TestEnum { Foo, Bar }; - SENF_CONSOLE_REGISTER_ENUM( TestEnum, (Foo)(Bar) ); + enum TestEnum { Foo, Bar, FooBar }; + SENF_CONSOLE_REGISTER_ENUM( TestEnum, (Foo)(Bar)(FooBar) ); TestEnum test (TestEnum value) { return value; } @@ -139,6 +139,24 @@ BOOST_AUTO_UNIT_TEST(enumSupport) parser.parse("test/member MemberBar", boost::bind( boost::ref(executor), boost::ref(ss), _1 )) ); BOOST_CHECK_EQUAL( ss.str(), "MemberBar\n" ); + + ss.str(""); + SENF_CHECK_NO_THROW( + parser.parse("test/test foob", + boost::bind( boost::ref(executor), boost::ref(ss), _1 )) ); + BOOST_CHECK_EQUAL( ss.str(), "FooBar\n" ); + + ss.str(""); + SENF_CHECK_NO_THROW( + parser.parse("test/test b", + boost::bind( boost::ref(executor), boost::ref(ss), _1 )) ); + BOOST_CHECK_EQUAL( ss.str(), "Bar\n" ); + + ss.str(""); + SENF_CHECK_NO_THROW( + parser.parse("test/test foo", + boost::bind( boost::ref(executor), boost::ref(ss), _1 )) ); + BOOST_CHECK_EQUAL( ss.str(), "Foo\n" ); }