Console: Implement short-option and non-option parsing
g0dil [Tue, 27 May 2008 12:58:44 +0000 (12:58 +0000)]
Fix lot's of inline implementation ordering errors (make sure, all inline functions are implemented before first use)

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@853 270642c3-0616-0410-b53a-bc976706d245

23 files changed:
Console/Config.cc
Console/Config.cci
Console/Config.cti [new file with mode: 0644]
Console/Config.hh
Console/Config.ih
Console/Config.test.cc [new file with mode: 0644]
Console/ConfigFile.ih
Console/Node.cc
Console/Node.cci
Console/OverloadedCommand.cci
Console/Parse.cc
Console/Parse.cci
Console/ParsedCommand.cc
Console/ParsedCommand.cci
Console/ParsedCommand.cti
Console/ParsedCommand.ih
Console/ProgramOptions.cc
Console/ProgramOptions.cci
Console/ProgramOptions.cti [new file with mode: 0644]
Console/ProgramOptions.hh
Console/ProgramOptions.ih
Console/ProgramOptions.test.cc
Console/Server.cci

index dc08724..1895d16 100644 (file)
@@ -153,6 +153,12 @@ prefix_ senf::console::detail::RestrictedExecutor::RestrictGuard::~RestrictGuard
     executor_.restrict_ = senf::console::root().thisptr();
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::ConfigSource
+
+prefix_ senf::console::detail::ConfigSource::~ConfigSource()
+{}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 //#include "Config.mpp"
index 1fb445b..1f41ebf 100644 (file)
 ///////////////////////////////cci.p///////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::RestrictedExecutor
+
+prefix_ bool senf::console::detail::RestrictedExecutor::complete()
+    const
+{
+    return parsedNodes_.size() == 1 
+        && ! parsedNodes_[0].expired() 
+        && *parsedNodes_[0].lock() == executor_.chroot();
+}
+
+prefix_ void senf::console::detail::RestrictedExecutor::reset()
+{
+    parsedNodes_.clear();
+}
+
+prefix_ senf::console::DirectoryNode & senf::console::detail::RestrictedExecutor::root()
+    const
+{
+    return executor_.chroot();
+}
+
+///////////////////////////////////////////////////////////////////////////
 // senf::console::ConfigBundle
 
 prefix_ senf::console::ConfigBundle::ConfigBundle()
@@ -41,11 +63,6 @@ prefix_ senf::console::ConfigBundle::ConfigBundle(DirectoryNode & root)
     : executor_ (root)
 {}
 
-prefix_ void senf::console::ConfigBundle::add(detail::ConfigSource::ptr source)
-{
-    sources_.push_back(source);
-}
-
 prefix_ bool senf::console::ConfigBundle::complete()
     const
 {
@@ -64,28 +81,6 @@ prefix_ void senf::console::ConfigBundle::reset()
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// senf::console::detail::RestrictedExecutor
-
-prefix_ bool senf::console::detail::RestrictedExecutor::complete()
-    const
-{
-    return parsedNodes_.size() == 1 
-        && ! parsedNodes_[0].expired() 
-        && *parsedNodes_[0].lock() == executor_.chroot();
-}
-
-prefix_ void senf::console::detail::RestrictedExecutor::reset()
-{
-    parsedNodes_.clear();
-}
-
-prefix_ senf::console::DirectoryNode & senf::console::detail::RestrictedExecutor::root()
-    const
-{
-    return executor_.chroot();
-}
-
-///////////////////////////////////////////////////////////////////////////
 // senf::console::detail::ConfigSource
 
 prefix_ void senf::console::detail::ConfigSource::parse(RestrictedExecutor & executor)
@@ -130,11 +125,6 @@ prefix_ void senf::console::detail::BundleMixin::reset()
     bundle_.reset();
 }
 
-prefix_ void senf::console::detail::BundleMixin::add(ConfigSource::ptr source)
-{
-    bundle_.add(source);
-}
-
 ///////////////////////////////cci.e///////////////////////////////////////
 #undef prefix_
 
diff --git a/Console/Config.cti b/Console/Config.cti
new file mode 100644 (file)
index 0000000..720f68b
--- /dev/null
@@ -0,0 +1,64 @@
+// $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 Config inline template implementation */
+
+#include "Config.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::ConfigBundle
+
+template <class Source>
+prefix_ Source & senf::console::ConfigBundle::add(boost::intrusive_ptr<Source> source)
+{
+    sources_.push_back(source);
+    return *source;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::BundleMixin
+
+template <class Source>
+prefix_ Source & senf::console::detail::BundleMixin::add(boost::intrusive_ptr<Source> source)
+{
+    return bundle_.add(source);
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// 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:
index e4f5c63..81a94ef 100644 (file)
@@ -63,7 +63,8 @@ namespace console {
         ///@}
         ///////////////////////////////////////////////////////////////////////////
 
-        void add(detail::ConfigSource::ptr source);
+        template <class Source>
+        Source & add(boost::intrusive_ptr<Source> source);
 
         void parse();                   ///< Parse config file
                                         /**< All nodes already parsed are skipped */
@@ -112,8 +113,9 @@ namespace detail {
                                              complete config file again. */
 
     protected:
-        void add(ConfigSource::ptr source);
-
+        template <class Source>
+        Source & add(boost::intrusive_ptr<Source> source);
+        
     private:
         ConfigBundle bundle_;
     };
@@ -123,7 +125,7 @@ namespace detail {
 ///////////////////////////////hh.e////////////////////////////////////////
 #include "Config.cci"
 //#include "Config.ct"
-//#include "Config.cti"
+#include "Config.cti"
 #endif
 
 \f
index 3a598b9..ceb081b 100644 (file)
@@ -117,6 +117,7 @@ namespace detail {
     {
     public:
         typedef boost::intrusive_ptr<ConfigSource> ptr;
+        virtual ~ConfigSource();
 
         void parse(RestrictedExecutor & executor);
 
diff --git a/Console/Config.test.cc b/Console/Config.test.cc
new file mode 100644 (file)
index 0000000..58d5c1b
--- /dev/null
@@ -0,0 +1,103 @@
+// $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 Config.test unit tests */
+
+//#include "Config.test.hh"
+//#include "Config.test.ih"
+
+// Custom includes
+#include "Config.hh"
+#include "ScopedDirectory.hh"
+#include "ParsedCommand.hh"
+#include "ConfigFile.hh"
+#include "ProgramOptions.hh"
+#include <boost/filesystem/operations.hpp>
+
+#include "../Utils/auto_unit_test.hh"
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+    std::string val1;
+    bool val2 (false);
+
+    void fun1(std::string p)
+    { val1 = p; }
+
+    void fun2()
+    { val2 = true; }
+
+    class TempFile
+    {
+    public:
+        TempFile(std::string const & name) : name_ (name), file_ (name_.c_str()) {}
+        ~TempFile() { file_.close(); boost::filesystem::remove(name_); }
+        
+        template <class T> TempFile & operator<<(T const & v) { file_ << v; return *this; }
+        enum Closer { close }; void operator<<(Closer) { file_.close(); }
+        std::string const & name() { return name_; }
+
+    private:
+        std::string name_;
+        std::ofstream file_;
+    };
+}
+
+BOOST_AUTO_UNIT_TEST(configBundle)
+{
+    senf::console::ScopedDirectory<> root;
+    senf::console::root().add("root",root);
+
+    root.mkdir("dir1").add("fun1",&fun1);
+    root.add("fun2",&fun2);
+
+    TempFile cfg ("test.cfg");
+    cfg << "dir1/fun1 foo; fun2;" << TempFile::close;
+
+    char * argv[] = { "", "--dir1-fun1=bar" };
+
+    senf::console::ConfigBundle bundle(root);
+    bundle.add( senf::console::FileConfig(cfg.name()) );
+    bundle.add( senf::console::OptionsConfig(sizeof(argv)/sizeof(argv[0]), argv) );
+
+    SENF_CHECK_NO_THROW( bundle.parse() );
+    BOOST_CHECK_EQUAL( val1, "bar" );
+    BOOST_CHECK_EQUAL( val2, true );
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// 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:
index 9bb15e2..a02c467 100644 (file)
@@ -37,6 +37,8 @@ namespace detail {
     class ConfigFileSource : public ConfigSource
     {
     public:
+        typedef boost::intrusive_ptr<ConfigFileSource> ptr;
+
         static ptr create(std::string const & filename);
 
     private:
index 42086bb..fddf01a 100644 (file)
@@ -200,15 +200,6 @@ prefix_ senf::console::GenericNode & senf::console::detail::NodeTraverser::node(
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// senf::console::SyntaxErrorException
-
-prefix_ char const * senf::console::SyntaxErrorException::what()
-    const throw()
-{
-    return message().empty() ? "syntax error" : message().c_str();
-}
-
-///////////////////////////////////////////////////////////////////////////
 // senf::console::SimpleCommandNode
 
 prefix_ void senf::console::SimpleCommandNode::v_help(std::ostream & output)
index 242881f..1fe834d 100644 (file)
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::GenericNode
 
+prefix_ senf::console::GenericNode::ptr senf::console::GenericNode::thisptr()
+{
+    return shared_from_this();
+}
+
+prefix_ senf::console::GenericNode::cptr senf::console::GenericNode::thisptr()
+    const
+{
+    return shared_from_this();
+}
+
 prefix_ senf::console::GenericNode::~GenericNode()
 {}
 
@@ -73,17 +84,6 @@ prefix_ void senf::console::GenericNode::help(std::ostream & output)
     v_help(output);
 }
 
-prefix_ senf::console::GenericNode::ptr senf::console::GenericNode::thisptr()
-{
-    return shared_from_this();
-}
-
-prefix_ senf::console::GenericNode::cptr senf::console::GenericNode::thisptr()
-    const
-{
-    return shared_from_this();
-}
-
 prefix_ bool senf::console::GenericNode::operator==(GenericNode & other)
     const
 {
@@ -117,6 +117,12 @@ prefix_ bool senf::console::GenericNode::isCommand()
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::LinkNode
 
+prefix_ senf::console::GenericNode & senf::console::LinkNode::follow()
+    const
+{
+    return *node_;
+}
+
 prefix_ senf::console::LinkNode::ptr senf::console::LinkNode::create(GenericNode & node)
 {
     GenericNode::ptr p (node.thisptr());
@@ -125,12 +131,6 @@ prefix_ senf::console::LinkNode::ptr senf::console::LinkNode::create(GenericNode
     return ptr(new LinkNode(*p));
 }
 
-prefix_ senf::console::GenericNode & senf::console::LinkNode::follow()
-    const
-{
-    return *node_;
-}
-
 prefix_ senf::console::LinkNode::LinkNode(GenericNode & node)
     : node_ (node.thisptr())
 {}
@@ -250,23 +250,6 @@ prefix_ senf::console::detail::NodeTraverser::NodeTraverser(DirectoryNode & root
 {}
 
 ///////////////////////////////////////////////////////////////////////////
-// senf::console::SyntaxErrorException
-
-prefix_ senf::console::SyntaxErrorException::SyntaxErrorException(std::string const & msg)
-    : message_(msg)
-{}
-
-prefix_ senf::console::SyntaxErrorException::~SyntaxErrorException()
-    throw()
-{}
-
-prefix_ std::string const & senf::console::SyntaxErrorException::message()
-    const
-{
-    return message_;
-}
-
-///////////////////////////////////////////////////////////////////////////
 // senf::console::CommandNode
 
 prefix_ senf::console::CommandNode::ptr senf::console::CommandNode::thisptr()
index 4892e53..d48d9d6 100644 (file)
 ///////////////////////////////cci.p///////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::console::OverloadedCommandNode
+
+prefix_ senf::console::OverloadedCommandNode::ptr senf::console::OverloadedCommandNode::create()
+{
+    return ptr(new OverloadedCommandNode());
+}
+
+prefix_ senf::console::OverloadedCommandNode::ptr senf::console::OverloadedCommandNode::thisptr()
+{
+    return boost::static_pointer_cast<OverloadedCommandNode>(shared_from_this());
+}
+
+prefix_ senf::console::OverloadedCommandNode::cptr senf::console::OverloadedCommandNode::thisptr()
+    const
+{
+    return boost::static_pointer_cast<OverloadedCommandNode const>(shared_from_this());
+}
+
+prefix_ senf::console::OverloadedCommandNode &
+senf::console::OverloadedCommandNode::doc(std::string const & doc)
+{
+    doc_ = doc;
+    return *this;
+}
+
+prefix_ unsigned
+senf::console::OverloadedCommandNode::overloadIndex(CommandOverload const & overload)
+{
+    return find(overloads_.begin(), overloads_.end(), CommandOverload::cptr(&overload)) 
+        - overloads_.begin() + 1;
+}
+
+prefix_ senf::console::OverloadedCommandNode::OverloadedCommandNode()
+{}
+
+///////////////////////////////////////////////////////////////////////////
 // senf::console::CommandOverload
 
 prefix_ senf::console::CommandOverload::~CommandOverload()
@@ -84,42 +120,6 @@ prefix_ senf::console::CommandOverload::CommandOverload()
 {}
 
 ///////////////////////////////////////////////////////////////////////////
-// senf::console::OverloadedCommandNode
-
-prefix_ senf::console::OverloadedCommandNode::ptr senf::console::OverloadedCommandNode::create()
-{
-    return ptr(new OverloadedCommandNode());
-}
-
-prefix_ senf::console::OverloadedCommandNode::ptr senf::console::OverloadedCommandNode::thisptr()
-{
-    return boost::static_pointer_cast<OverloadedCommandNode>(shared_from_this());
-}
-
-prefix_ senf::console::OverloadedCommandNode::cptr senf::console::OverloadedCommandNode::thisptr()
-    const
-{
-    return boost::static_pointer_cast<OverloadedCommandNode const>(shared_from_this());
-}
-
-prefix_ senf::console::OverloadedCommandNode &
-senf::console::OverloadedCommandNode::doc(std::string const & doc)
-{
-    doc_ = doc;
-    return *this;
-}
-
-prefix_ unsigned
-senf::console::OverloadedCommandNode::overloadIndex(CommandOverload const & overload)
-{
-    return find(overloads_.begin(), overloads_.end(), CommandOverload::cptr(&overload)) 
-        - overloads_.begin() + 1;
-}
-
-prefix_ senf::console::OverloadedCommandNode::OverloadedCommandNode()
-{}
-
-///////////////////////////////////////////////////////////////////////////
 // senf::console::SimpleCommandOverload
 
 prefix_ senf::console::SimpleCommandOverload::ptr
index b916ae0..bc4fd46 100644 (file)
@@ -287,6 +287,15 @@ prefix_ bool senf::console::CommandParser::parseArguments(std::string arguments,
         ).full;
 }
 
+///////////////////////////////////////////////////////////////////////////
+// senf::console::SyntaxErrorException
+
+prefix_ char const * senf::console::SyntaxErrorException::what()
+    const throw()
+{
+    return message().empty() ? "syntax error" : message().c_str();
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 //#include "Parse.mpp"
index c7c6c61..fcce862 100644 (file)
@@ -224,6 +224,23 @@ prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::increment()
 }
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::console::SyntaxErrorException
+
+prefix_ senf::console::SyntaxErrorException::SyntaxErrorException(std::string const & msg)
+    : message_(msg)
+{}
+
+prefix_ senf::console::SyntaxErrorException::~SyntaxErrorException()
+    throw()
+{}
+
+prefix_ std::string const & senf::console::SyntaxErrorException::message()
+    const
+{
+    return message_;
+}
+
+///////////////////////////////////////////////////////////////////////////
 
 prefix_ senf::console::CheckedArgumentIteratorWrapper::
 CheckedArgumentIteratorWrapper(ParseCommandInfo::ArgumentsRange const & range,
index d593eb1..da6144b 100644 (file)
 ///////////////////////////////cc.p////////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::ArgumentInfoBase
+
+prefix_ senf::console::detail::ArgumentInfoBase::~ArgumentInfoBase()
+{}
+
+////////////////////////////////////////////////////////////////////////
 // senf::console::ParsedCommandOverloadBase
 
 prefix_ unsigned senf::console::ParsedCommandOverloadBase::v_numArguments()
index 1cd764b..aeab60e 100644 (file)
 ///////////////////////////////cci.p///////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::ArgumentInfoBase
+
+prefix_ senf::console::detail::ArgumentInfoBase::ArgumentInfoBase(std::string const & type_)
+    : type (type_), name (), hasDefault (false)
+{}
+
+///////////////////////////////////////////////////////////////////////////
 // senf::console::ParsedCommandOverloadBase
 
 prefix_ senf::console::ParsedCommandOverloadBase::ParsedCommandOverloadBase()
@@ -70,6 +77,13 @@ ParsedCommandAttributorBase(ParsedCommandOverloadBase & overload, unsigned index
     : overload_ (overload), index_ (index)
 {}
 
+prefix_ senf::console::ParsedCommandOverloadBase &
+senf::console::ParsedCommandAttributorBase::overload()
+    const
+{
+    return overload_;
+}
+
 prefix_ void senf::console::ParsedCommandAttributorBase::argName(std::string const & name)
     const
 {
@@ -94,13 +108,6 @@ prefix_ void senf::console::ParsedCommandAttributorBase::defaultDoc(std::string
     overload().arg(index_).defaultDoc = doc;
 }
 
-prefix_ senf::console::ParsedCommandOverloadBase &
-senf::console::ParsedCommandAttributorBase::overload()
-    const
-{
-    return overload_;
-}
-
 prefix_ void senf::console::ParsedCommandAttributorBase::overloadDoc(std::string const & doc)
     const
 {
index 61b447f..b6d140f 100644 (file)
 ///////////////////////////////cti.p///////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////
-// senf::console::detail::ArgumentInfoBase
-
-prefix_ senf::console::detail::ArgumentInfoBase::ArgumentInfoBase(std::string const & type_)
-    : type (type_), name (), hasDefault (false)
-{}
-
-///////////////////////////////////////////////////////////////////////////
 // senf::console::detail::ArgumentInfo<ParameterType>
 
 template <class ParameterType>
index 90231c2..330ea7c 100644 (file)
@@ -66,6 +66,7 @@ namespace detail {
         std::string doc;
         
         ArgumentInfoBase(std::string const & type);
+        virtual ~ArgumentInfoBase();
 
         virtual std::string defaultValueStr() const = 0;
     };
index 118a774..6eb3107 100644 (file)
 
 // Custom includes
 #include <boost/algorithm/string/predicate.hpp>
+#include <boost/format.hpp>
 
 //#include "ProgramOptions.mpp"
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::ProgramOptionsSource::NonOptionContainer
+
+prefix_ senf::console::detail::ProgramOptionsSource::NonOptionContainer::~NonOptionContainer()
+{}
+
+///////////////////////////////////////////////////////////////////////////
 // senf::console::detail::ProgramOptionsSource
 
 prefix_ void senf::console::detail::ProgramOptionsSource::v_parse(RestrictedExecutor & executor)
 {
-    char ** argp (argv_);
-    int n (argc_);
+    if (nonOptions_)
+        nonOptions_->clear();
+    if (argc_ <= 1)
+        return;
+    char ** argp (argv_+1);
+    int n (argc_-1);
     for (; n; --n, ++argp) {
         std::string arg (*argp);
-        if (boost::algorithm::starts_with(arg, std::string("--")))
+        if (arg == "--") {
+            for (; n; --n, ++argp)
+                parseNonOption(arg, executor);
+            break;
+        }
+        else if (boost::algorithm::starts_with(arg, std::string("--")) && arg.size() > 2)
             parseLongOption(arg.substr(2), executor);
+        else if (boost::algorithm::starts_with(arg, std::string("-")) && arg.size() > 1) {
+            for (std::string::size_type i (1); i<arg.size(); ++i) {
+                char opt (arg[i]);
+                ShortOptions::iterator j (shortOptions_.find(opt));
+                if (j == shortOptions_.end())
+                    throw SyntaxErrorException(
+                        (boost::format("invalid short option '%c'") % opt).str());
+                std::string param;
+                if (j->second.withArg) {
+                    if (i >= arg.size()-1) {
+                        if (n > 0) {
+                            param = *(++argp);
+                            --n;
+                        }
+                    }
+                    else 
+                        param = arg.substr(i+1);
+                    i = arg.size();
+                }
+                std::string longOpt (j->second.longOpt);
+                if (! param.empty() ) {
+                    longOpt += "=";
+                    longOpt += param;
+                }
+                if (boost::algorithm::starts_with(longOpt, std::string("--")))
+                    longOpt = longOpt.substr(2);
+                parseLongOption(longOpt, executor);
+            }
+        }
         else
             parseNonOption(arg, executor);
     }
 }
 
-namespace {
-    struct MakeWordToken
-    {
-        typedef senf::console::Token result_type;
-        template <class Range>
-        result_type operator()(Range const & r) const
-            { return senf::console::WordToken(std::string(boost::begin(r), boost::end(r))); }
-    };
-}
-
 prefix_ void
 senf::console::detail::ProgramOptionsSource::parseLongOption(std::string const & arg,
                                                              RestrictedExecutor & executor)
@@ -77,18 +112,24 @@ senf::console::detail::ProgramOptionsSource::parseLongOption(std::string const &
     while (b < name.size()) {
         std::string::size_type e (name.size());
         for (;e != std::string::npos && e > b; e = name.rfind('-', e)) {
-            DirectoryNode::ChildrenRange completions (cwd->completions(name.substr(b,e-b)));
-            if (completions.size() == 1) {
-                path.push_back(WordToken(completions.begin()->first));
-                if (e < name.size())
-                    cwd = cwd->getDirectory(completions.begin()->first).thisptr();
-                b = e+1;
-                e = b+1;
-                break;
+            std::string key (name.substr(b,e-b));
+            if (! cwd->hasChild(key)) {
+                DirectoryNode::ChildrenRange completions (cwd->completions(key));
+                if (completions.size() == 1)
+                    key = completions.begin()->first;
+                else
+                    continue;
             }
+            path.push_back(WordToken(key));
+            if (e < name.size())
+                cwd = cwd->getDirectory(key).thisptr();
+            b = e+1;
+            e = b+1;
+            break;
         }
         if (e == std::string::npos || e <= b) {
-            // This will produce a correct error message later
+            // This will produce a correct error message later or will skip the node,
+            // if parsing is restricted to a subtree
             path.push_back(WordToken(name.substr(b)));
             b = name.size();
         }
@@ -102,7 +143,11 @@ senf::console::detail::ProgramOptionsSource::parseLongOption(std::string const &
 prefix_ void
 senf::console::detail::ProgramOptionsSource::parseNonOption(std::string const & arg,
                                                             RestrictedExecutor & executor)
-{}
+{
+    if (! nonOptions_)
+        throw SyntaxErrorException("invalid non-option argument");
+    nonOptions_->push_back(arg);
+}
 
 ///////////////////////////////////////////////////////////////////////////
 
index 96415c0..8896fa0 100644 (file)
@@ -44,14 +44,35 @@ prefix_ senf::console::detail::ProgramOptionsSource::ProgramOptionsSource(int ar
     : argc_ (argc), argv_ (argv)
 {}
 
+prefix_ senf::console::detail::ProgramOptionsSource &
+senf::console::detail::ProgramOptionsSource::alias(char letter, std::string const & longOpt,
+                                                   bool withArg)
+{
+    shortOptions_.insert(std::make_pair(letter, ShortOption(withArg, longOpt)));
+    return *this;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::ProgramOptionsSource::ShortOption
+
+prefix_ senf::console::detail::ProgramOptionsSource::ShortOption::
+ShortOption(bool withArg_, std::string const & longOpt_)
+    : withArg (withArg_), longOpt (longOpt_)
+{}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::ProgramOptions
 
 prefix_ senf::console::ProgramOptions::ProgramOptions(int argc, char ** argv,
                                                       DirectoryNode & root)
-    : detail::BundleMixin (root)
+    : detail::BundleMixin (root), config_ (add(detail::ProgramOptionsSource::create(argc, argv)))
+{}
+
+prefix_ senf::console::ProgramOptions &
+senf::console::ProgramOptions::alias(char letter, std::string const & longOpt, bool withArg)
 {
-    add(detail::ProgramOptionsSource::create(argc, argv));
+    config_.alias(letter, longOpt, withArg);
+    return *this;
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/Console/ProgramOptions.cti b/Console/ProgramOptions.cti
new file mode 100644 (file)
index 0000000..0091819
--- /dev/null
@@ -0,0 +1,92 @@
+// $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 ProgramOptions inline template implementation */
+
+#include "ProgramOptions.ih"
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::ProgramOptionsSource
+
+template <class Container>
+prefix_ senf::console::detail::ProgramOptionsSource &
+senf::console::detail::ProgramOptionsSource::nonOptions(Container & container)
+{
+    nonOptions_.reset(new NonOptionContainerImpl<Container>(container));
+    return *this;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::detail::ProgramOptionsSource::NonOptionContainerImpl
+
+template <class Container>
+prefix_
+senf::console::detail::ProgramOptionsSource::NonOptionContainerImpl<Container>::
+NonOptionContainerImpl(Container & c)
+    : c_ (c)
+{}
+
+template <class Container>
+prefix_ void
+senf::console::detail::ProgramOptionsSource::NonOptionContainerImpl<Container>::clear()
+{
+    c_.clear();
+}
+
+template <class Container>
+prefix_ void
+senf::console::detail::ProgramOptionsSource::NonOptionContainerImpl<Container>::
+push_back(std::string const & value)
+{
+    c_.push_back(value);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::ProgramOptions
+
+template <class Container>
+prefix_ senf::console::ProgramOptions &
+senf::console::ProgramOptions::nonOptions(Container & container)
+{
+    config_.nonOptions(container);
+    return *this;
+}
+
+///////////////////////////////cti.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// 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:
index 253f1a8..7fab5dc 100644 (file)
@@ -49,6 +49,13 @@ namespace console {
 
         ///@}
         ///////////////////////////////////////////////////////////////////////////
+        
+        template <class Container>
+        ProgramOptions & nonOptions(Container & container);
+        ProgramOptions & alias(char letter, std::string const & longOpt, bool withArg=false);
+
+    private:
+        detail::ProgramOptionsSource & config_;
     };
 
     void parseOptions(int argc, char ** argv, DirectoryNode & root = root());
@@ -59,7 +66,7 @@ namespace console {
 ///////////////////////////////hh.e////////////////////////////////////////
 #include "ProgramOptions.cci"
 //#include "ProgramOptions.ct"
-//#include "ProgramOptions.cti"
+#include "ProgramOptions.cti"
 #endif
 
 \f
index 36e9e55..8fdf488 100644 (file)
@@ -27,6 +27,7 @@
 #define IH_ProgramOptions_ 1
 
 // Custom includes
+#include <boost/scoped_ptr.hpp>
 #include "Parse.hh"
 
 ///////////////////////////////ih.p////////////////////////////////////////
@@ -38,7 +39,13 @@ namespace detail {
     class ProgramOptionsSource : public ConfigSource
     {
     public:
+        typedef boost::intrusive_ptr<ProgramOptionsSource> ptr;
+
         static ptr create(int argc, char ** argv);
+
+        template <class Container>
+        ProgramOptionsSource & nonOptions(Container & container);
+        ProgramOptionsSource & alias(char letter, std::string const & longOpt, bool withArg=false);
         
     private:
         ProgramOptionsSource(int argc, char ** argv);
@@ -47,10 +54,40 @@ namespace detail {
 
         void parseLongOption(std::string const & arg, RestrictedExecutor & executor);
         void parseNonOption(std::string const & arg, RestrictedExecutor & executor);
+
+        struct NonOptionContainer
+        {
+            virtual ~NonOptionContainer();
+            virtual void clear() = 0;
+            virtual void push_back(std::string const & value) = 0;
+        };
+
+        template <class Container>
+        struct NonOptionContainerImpl
+            : public NonOptionContainer
+        {
+            NonOptionContainerImpl(Container & c);
+
+            void clear();
+            void push_back(std::string const & value);
+
+            Container & c_;
+        };
+
+        struct ShortOption
+        {
+            ShortOption(bool withArg, std::string const & longOpt);
+            bool withArg;
+            std::string longOpt;
+        };
+
+        typedef std::map<char, ShortOption> ShortOptions;
         
         int argc_;
         char ** argv_;
         CommandParser parser_;
+        ShortOptions shortOptions_;
+        boost::scoped_ptr<NonOptionContainer> nonOptions_;
     };
 
 }}}
index 2e24c8b..f630141 100644 (file)
@@ -58,7 +58,7 @@ BOOST_AUTO_UNIT_TEST(programOptions)
     root.mkdir("name-with-dashes").add("fun-2", &fun2);
 
     {
-        char * argv[] = { "--dir1-fun1=foo","--fun2" };
+        char * argv[] = { "", "--dir1-fun1=foo","--fun2" };
         senf::console::ProgramOptions opts (sizeof(argv)/sizeof(argv[0]), argv, root);
 
         SENF_CHECK_NO_THROW( opts.parse() );
@@ -67,7 +67,7 @@ BOOST_AUTO_UNIT_TEST(programOptions)
     }
 
     {
-        char * argv[] = { "--d-f=foo","--fun" };
+        char * argv[] = { "", "--d-f=foo","--fun" };
         senf::console::ProgramOptions opts (sizeof(argv)/sizeof(argv[0]), argv, root);
 
         val1 = "";
@@ -79,7 +79,7 @@ BOOST_AUTO_UNIT_TEST(programOptions)
     }
 
     {
-        char * argv[] = { "--name-w-fun" };
+        char * argv[] = { "", "--name-w-fun" };
         senf::console::ProgramOptions opts (sizeof(argv)/sizeof(argv[0]), argv, root);
 
         val1 = "";
@@ -89,6 +89,51 @@ BOOST_AUTO_UNIT_TEST(programOptions)
         BOOST_CHECK_EQUAL( val1, "" );
         BOOST_CHECK_EQUAL( val2, true );
     }
+    
+    {
+        char * argv[] = { "", "-ab" };
+        senf::console::ProgramOptions opts(sizeof(argv)/sizeof(argv[0]), argv, root);
+        opts
+            .alias('a', "--dir1-fun1=baz")
+            .alias('b', "--fun2");
+
+        val1 = "";
+        val2 = false;
+
+        SENF_CHECK_NO_THROW( opts.parse() );
+        BOOST_CHECK_EQUAL( val1, "baz" );
+        BOOST_CHECK_EQUAL( val2, true );
+    }
+
+    {
+        char * argv[] = { "", "-badoo" };
+        senf::console::ProgramOptions opts(sizeof(argv)/sizeof(argv[0]), argv, root);
+        opts
+            .alias('a', "--dir1-fun1", true)
+            .alias('b', "--fun2");
+
+        val1 = "";
+        val2 = false;
+
+        SENF_CHECK_NO_THROW( opts.parse() );
+        BOOST_CHECK_EQUAL( val1, "doo" );
+        BOOST_CHECK_EQUAL( val2, true );
+    }
+
+    {
+        char * argv[] = { "", "-a","dii","-b" };
+        senf::console::ProgramOptions opts(sizeof(argv)/sizeof(argv[0]), argv, root);
+        opts
+            .alias('a', "--dir1-fun1", true)
+            .alias('b', "--fun2");
+
+        val1 = "";
+        val2 = false;
+
+        SENF_CHECK_NO_THROW( opts.parse() );
+        BOOST_CHECK_EQUAL( val1, "dii" );
+        BOOST_CHECK_EQUAL( val2, true );
+    }
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index 78387d6..427e8ea 100644 (file)
@@ -59,6 +59,46 @@ prefix_ void senf::console::Server::stop()
 }
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::console::Client
+
+prefix_ senf::console::Client::~Client()
+{}
+
+prefix_ void senf::console::Client::stop()
+{
+    // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER removeClient RETURNS
+    server_.removeClient(*this);
+}
+
+prefix_ std::string const & senf::console::Client::name()
+    const
+{
+    return name_;
+}
+
+prefix_ std::string senf::console::Client::promptString()
+    const
+{
+    return name_ + ":" + executor_.cwdPath() + "$ ";
+}
+
+prefix_ senf::console::Client & senf::console::Client::get(std::ostream & os)
+{
+    return dynamic_cast<detail::NonblockingSocketOStream&>(os)->client();
+}
+
+prefix_ senf::console::Client::ClientHandle senf::console::Client::handle()
+    const
+{
+    return handle_;
+}
+
+prefix_ std::ostream & senf::console::Client::stream()
+{
+    return out_t::member;
+}
+
+///////////////////////////////////////////////////////////////////////////
 // senf::console::detail::ClientReader
 
 prefix_ senf::console::detail::ClientReader::~ClientReader()
@@ -118,46 +158,6 @@ prefix_ senf::console::detail::ClientReader::ClientReader(Client & client)
     : client_ (client)
 {}
 
-///////////////////////////////////////////////////////////////////////////
-// senf::console::Client
-
-prefix_ senf::console::Client::~Client()
-{}
-
-prefix_ void senf::console::Client::stop()
-{
-    // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER removeClient RETURNS
-    server_.removeClient(*this);
-}
-
-prefix_ std::string const & senf::console::Client::name()
-    const
-{
-    return name_;
-}
-
-prefix_ std::string senf::console::Client::promptString()
-    const
-{
-    return name_ + ":" + executor_.cwdPath() + "$ ";
-}
-
-prefix_ senf::console::Client & senf::console::Client::get(std::ostream & os)
-{
-    return dynamic_cast<detail::NonblockingSocketOStream&>(os)->client();
-}
-
-prefix_ senf::console::Client::ClientHandle senf::console::Client::handle()
-    const
-{
-    return handle_;
-}
-
-prefix_ std::ostream & senf::console::Client::stream()
-{
-    return out_t::member;
-}
-
 ///////////////////////////////cci.e///////////////////////////////////////
 #undef prefix_