Utils/Console: Implement special single-token argument parsing for program options...
g0dil [Thu, 4 Jun 2009 13:57:01 +0000 (13:57 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1222 270642c3-0616-0410-b53a-bc976706d245

15 files changed:
Utils/Console/Config.cc
Utils/Console/Config.ih
Utils/Console/Executor.cc
Utils/Console/Executor.hh
Utils/Console/OverloadedCommand.cci
Utils/Console/OverloadedCommand.hh
Utils/Console/ParsedCommand.cc
Utils/Console/ParsedCommand.cci
Utils/Console/ParsedCommand.cti
Utils/Console/ParsedCommand.ih
Utils/Console/ProgramOptions.cc
Utils/Console/STLSupport.hh
Utils/Console/Traits.ct
Utils/Console/Traits.hh
Utils/Console/Traits.test.cc

index e6723aa..f844f8a 100644 (file)
@@ -57,6 +57,12 @@ senf::console::detail::RestrictedExecutor::operator()(std::ostream & output,
     execute(output, command);
 }
 
+prefix_ senf::console::GenericNode &
+senf::console::detail::RestrictedExecutor::getNode(ParseCommandInfo const & command)
+{
+    return executor_.getNode(command);
+}
+
 prefix_ bool senf::console::detail::RestrictedExecutor::parsed(GenericNode & node)
     const
 {
index 4b54736..d85a646 100644 (file)
@@ -69,6 +69,8 @@ namespace detail {
                                         /**< Output will be written to \a output. 
                                              Same as execute(). */
 
+        GenericNode & getNode(ParseCommandInfo const & command);
+
         bool complete() const;          ///< \c true, if all nodes have been parsed
         bool parsed(GenericNode & node) const; ///< \c true. if \a node has been parsed
         void reset();                   ///< Reset node parse info state
index 10d45df..141565a 100644 (file)
@@ -161,6 +161,12 @@ prefix_ void senf::console::Executor::execute(std::ostream & output,
     catch (IgnoreCommandException &) {}
 }
 
+prefix_ senf::console::GenericNode &
+senf::console::Executor::getNode(ParseCommandInfo const & command)
+{
+    return traverseNode(command.commandPath());
+}
+
 prefix_ void senf::console::Executor::exec(std::ostream & output,
                                            ParseCommandInfo const & command)
 {
index 2fc9c06..ce8b86c 100644 (file)
@@ -92,6 +92,7 @@ namespace console {
                                         ///< Execute command
                                         /**< Output will be written to \a output. 
                                              Same as execute(). */
+        GenericNode & getNode(ParseCommandInfo const & command);
         DirectoryNode & cwd() const;    ///< Current working directory
         std::string cwdPath() const;    ///< Return pathname of current directory
         bool skipping() const;          ///< \c true, if currently skipping a directory group
index dbbb7c0..c891fda 100644 (file)
@@ -70,6 +70,13 @@ senf::console::OverloadedCommandNode::overloadIndex(CommandOverload const & over
         - overloads_.begin() + 1;
 }
 
+prefix_ senf::console::OverloadedCommandNode::OverloadsRange
+senf::console::OverloadedCommandNode::overloads()
+    const
+{
+    return boost::make_iterator_range(overloads_.begin(), overloads_.end());
+}
+
 prefix_ senf::console::OverloadedCommandNode::OverloadedCommandNode()
 {}
 
index fb374ec..4402742 100644 (file)
@@ -29,6 +29,7 @@
 // Custom includes
 #include "Node.hh"
 #include <boost/intrusive_ptr.hpp>
+#include <boost/range/iterator_range.hpp>
 #include "../../Utils/intrusive_refcount.hh"
 
 //#include "OverloadedCommand.mpp"
@@ -48,6 +49,7 @@ namespace console {
         std::string type; ///< Argument type (string representation)
         std::string defaultValue; ///< Default value (string representation) or empty string
         std::string doc; ///< Documentation for this argument
+        bool singleToken; ///< \c true, if argument is parsed from single token
     };
 
     /** \brief Base class for command overload of OverloadedCommandNode
@@ -159,6 +161,8 @@ namespace console {
     class OverloadedCommandNode
         : public CommandNode
     {
+        typedef std::vector<CommandOverload::ptr> Overloads;
+
     public:
         ///////////////////////////////////////////////////////////////////////////
         // Types
@@ -170,6 +174,8 @@ namespace console {
         typedef OverloadedCommandNode node_type;
         typedef OverloadedCommandNode & return_type;
 
+        typedef boost::iterator_range<Overloads::const_iterator> OverloadsRange;
+
         ///////////////////////////////////////////////////////////////////////////
         ///\name Structors and default members
         ///@{
@@ -192,6 +198,8 @@ namespace console {
                                         /**< overloadIndex returns the index of \a overload in the
                                              internal list of overloads. */
 
+        OverloadsRange overloads() const; ///< Get all overloads
+
         ptr thisptr();
         cptr thisptr() const;
 
@@ -203,8 +211,6 @@ namespace console {
         virtual void v_execute(boost::any & rv, std::ostream & os, ParseCommandInfo const & command)
             const;
 
-        typedef std::vector<CommandOverload::ptr> Overloads;
-
         Overloads overloads_;
         std::string doc_;
         std::string shortdoc_;
index da6144b..bca4793 100644 (file)
@@ -65,6 +65,7 @@ prefix_ void senf::console::ParsedCommandOverloadBase::v_argumentDoc(unsigned in
             doc.defaultValue = "(empty)";
     }
     doc.doc = arg.doc;
+    doc.singleToken = arg.singleToken;
 }
 
 prefix_ std::string senf::console::ParsedCommandOverloadBase::v_doc()
index 1ec6a29..5d168ec 100644 (file)
@@ -33,8 +33,9 @@
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::detail::ArgumentInfoBase
 
-prefix_ senf::console::detail::ArgumentInfoBase::ArgumentInfoBase(std::string const & type_)
-    : type (type_), name (), hasDefault (false)
+prefix_ senf::console::detail::ArgumentInfoBase::ArgumentInfoBase(std::string const & type_,
+                                                                  bool singleToken_)
+    : type (type_), name (), hasDefault (false), singleToken (singleToken_)
 {}
 
 ///////////////////////////////////////////////////////////////////////////
index 7e9710f..a35a827 100644 (file)
@@ -45,7 +45,8 @@ senf::console::detail::ArgumentInfo<ParameterType>::create()
 
 template <class ParameterType>
 prefix_ senf::console::detail::ArgumentInfo<ParameterType>::ArgumentInfo()
-    : ArgumentInfoBase ( ArgumentTraits<ParameterType>::description() ),
+    : ArgumentInfoBase ( ArgumentTraits<ParameterType>::description(), 
+                         ArgumentTraits<ParameterType>::singleToken ),
       defaultValue ()
 {}
 
index 65a02f7..0dbe33b 100644 (file)
@@ -64,8 +64,9 @@ namespace detail {
         std::string defaultDoc;
         bool hasDefault;
         std::string doc;
+        bool singleToken;
         
-        ArgumentInfoBase(std::string const & type);
+        explicit ArgumentInfoBase(std::string const & type, bool singleToken=false);
         virtual ~ArgumentInfoBase();
 
         virtual std::string defaultValueStr() const = 0;
index 245cce3..951c5f0 100644 (file)
@@ -30,6 +30,7 @@
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/format.hpp>
 #include "../../Utils/range.hh"
+#include "OverloadedCommand.hh"
 
 //#include "ProgramOptions.mpp"
 #define prefix_
@@ -151,8 +152,35 @@ senf::console::detail::ProgramOptionsSource::parseLongOption(std::string const &
     }
 
     cmd.command(path);
-    parser_.parseArguments(value, cmd);
-    executor(executor.stream(), cmd);
+    // Here we check, whether the command
+    // - is an overloaded/parsed command
+    // - with a single overload
+    // - taking only a single argument
+    // - which consists of a single token
+    // If all these conditions are met, we pass the parameter value as a single WordToken
+    // otherwise we parse it using the config parser
+    try {
+        GenericNode const & node (executor.getNode(cmd));
+        OverloadedCommandNode const * cmdnode (dynamic_cast<OverloadedCommandNode const *>(&node));
+        if (cmdnode && cmdnode->overloads().size() == 1) {
+            CommandOverload const & overload (**cmdnode->overloads().begin());
+            if (overload.numArguments() == 1) {
+                ArgumentDoc argdoc;
+                argdoc.singleToken = false;
+                overload.argumentDoc(0, argdoc);
+                if (argdoc.singleToken) {
+                    cmd.addToken(WordToken(value));
+                    goto execute;
+                }
+            }
+        } /* else */ {
+            parser_.parseArguments(value, cmd);
+        }
+    execute:
+        executor(executor.stream(), cmd);
+    }
+    catch (Executor::IgnoreCommandException &)
+    {}
 }
 
 prefix_ void
index 6879483..69a6e14 100644 (file)
@@ -43,6 +43,7 @@ namespace console {
     struct SequenceArgumentTraits
     {
         typedef Sequence type;
+        static bool const singleToken = false;
 
         static void parse(ParseCommandInfo::TokensRange const & tokens, type & out);
         static std::string description();
index 0f8da26..8749e9a 100644 (file)
@@ -31,7 +31,7 @@
 ///////////////////////////////ct.p////////////////////////////////////////
 
 template <class Type>
-prefix_ void
+prefix_ bool
 senf::console::senf_console_parse_argument(ParseCommandInfo::TokensRange const & tokens,
                                            Type & out)
 {
@@ -44,6 +44,7 @@ senf::console::senf_console_parse_argument(ParseCommandInfo::TokensRange const &
     catch (std::bad_cast & ex) {
         throw SyntaxErrorException("parameter syntax error");
     }
+    return false;
 }
 
 ///////////////////////////////////////////////////////////////////////////
index 2e84882..a5b0ccd 100644 (file)
@@ -29,6 +29,7 @@
 // Custom includes
 #include <iostream>
 #include <boost/intrusive_ptr.hpp>
+#include <boost/type_traits/is_same.hpp>
 #include "../../Utils/intrusive_refcount.hh"
 #include "Parse.hh"
 #include "Node.hh"
@@ -94,6 +95,12 @@ namespace console {
     {
         typedef Type type;
 
+        static bool const singleToken = 
+            boost::is_same< typeof(senf_console_parse_argument(
+                                       *static_cast<ParseCommandInfo::TokensRange const *>(0),
+                                       *static_cast<Type*>(0))),
+                            bool >::value;
+
         static void parse(ParseCommandInfo::TokensRange const & tokens, Type & out);
                                         ///< Parse token range into value
                                         /**< This function needs to parse \a tokens and write the
@@ -121,7 +128,7 @@ namespace console {
         \related ArgumentTraits
      */
     template <class Type>
-    void senf_console_parse_argument(ParseCommandInfo::TokensRange const & tokens, Type & out);
+    bool senf_console_parse_argument(ParseCommandInfo::TokensRange const & tokens, Type & out);
 
     /** \brief Parse token range
 
@@ -143,6 +150,7 @@ namespace console {
     struct ArgumentTraits<bool>
     {
         typedef bool type;
+        static bool const singleToken = true;
 
         static void parse(ParseCommandInfo::TokensRange const & tokens, bool & out);
         static std::string description();
@@ -225,6 +233,7 @@ namespace console {
     struct ArgumentTraits< FlagCollection<Enum> >
     {
         typedef FlagCollection<Enum> type;
+        static bool const singleToken = false;
         static void parse(ParseCommandInfo::TokensRange const & tokens, type & out);
         static std::string description();
         static std::string str(type const & value);
index 03dc80e..1e77cf7 100644 (file)
@@ -191,6 +191,14 @@ BOOST_AUTO_UNIT_TEST(flagCollection)
     BOOST_CHECK_EQUAL( ss.str(), "()\n" );
 }
 
+BOOST_AUTO_UNIT_TEST(singleToken)
+{
+    BOOST_CHECK( senf::console::ArgumentTraits<std::string>::singleToken );
+    BOOST_CHECK( senf::console::ArgumentTraits<int>::singleToken );
+    BOOST_CHECK( ! senf::console::ArgumentTraits< 
+                       senf::console::FlagCollection<TestEnum> >::singleToken );
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_