From: g0dil Date: Tue, 27 May 2008 12:58:44 +0000 (+0000) Subject: Console: Implement short-option and non-option parsing X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=408efb5a03252b4a278f69ab9bc588af438c55de;p=senf.git Console: Implement short-option and non-option parsing 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 --- diff --git a/Console/Config.cc b/Console/Config.cc index dc08724..1895d16 100644 --- a/Console/Config.cc +++ b/Console/Config.cc @@ -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" diff --git a/Console/Config.cci b/Console/Config.cci index 1fb445b..1f41ebf 100644 --- a/Console/Config.cci +++ b/Console/Config.cci @@ -32,6 +32,28 @@ ///////////////////////////////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 index 0000000..720f68b --- /dev/null +++ b/Console/Config.cti @@ -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 +// +// 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 +prefix_ Source & senf::console::ConfigBundle::add(boost::intrusive_ptr source) +{ + sources_.push_back(source); + return *source; +} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::BundleMixin + +template +prefix_ Source & senf::console::detail::BundleMixin::add(boost::intrusive_ptr source) +{ + return bundle_.add(source); +} + +///////////////////////////////cti.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/Config.hh b/Console/Config.hh index e4f5c63..81a94ef 100644 --- a/Console/Config.hh +++ b/Console/Config.hh @@ -63,7 +63,8 @@ namespace console { ///@} /////////////////////////////////////////////////////////////////////////// - void add(detail::ConfigSource::ptr source); + template + Source & add(boost::intrusive_ptr 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 + Source & add(boost::intrusive_ptr 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 diff --git a/Console/Config.ih b/Console/Config.ih index 3a598b9..ceb081b 100644 --- a/Console/Config.ih +++ b/Console/Config.ih @@ -117,6 +117,7 @@ namespace detail { { public: typedef boost::intrusive_ptr ptr; + virtual ~ConfigSource(); void parse(RestrictedExecutor & executor); diff --git a/Console/Config.test.cc b/Console/Config.test.cc new file mode 100644 index 0000000..58d5c1b --- /dev/null +++ b/Console/Config.test.cc @@ -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 +// +// 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 + +#include "../Utils/auto_unit_test.hh" +#include + +#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 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_ + + +// 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/ConfigFile.ih b/Console/ConfigFile.ih index 9bb15e2..a02c467 100644 --- a/Console/ConfigFile.ih +++ b/Console/ConfigFile.ih @@ -37,6 +37,8 @@ namespace detail { class ConfigFileSource : public ConfigSource { public: + typedef boost::intrusive_ptr ptr; + static ptr create(std::string const & filename); private: diff --git a/Console/Node.cc b/Console/Node.cc index 42086bb..fddf01a 100644 --- a/Console/Node.cc +++ b/Console/Node.cc @@ -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) diff --git a/Console/Node.cci b/Console/Node.cci index 242881f..1fe834d 100644 --- a/Console/Node.cci +++ b/Console/Node.cci @@ -34,6 +34,17 @@ /////////////////////////////////////////////////////////////////////////// // 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() diff --git a/Console/OverloadedCommand.cci b/Console/OverloadedCommand.cci index 4892e53..d48d9d6 100644 --- a/Console/OverloadedCommand.cci +++ b/Console/OverloadedCommand.cci @@ -31,6 +31,42 @@ ///////////////////////////////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(shared_from_this()); +} + +prefix_ senf::console::OverloadedCommandNode::cptr senf::console::OverloadedCommandNode::thisptr() + const +{ + return boost::static_pointer_cast(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(shared_from_this()); -} - -prefix_ senf::console::OverloadedCommandNode::cptr senf::console::OverloadedCommandNode::thisptr() - const -{ - return boost::static_pointer_cast(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 diff --git a/Console/Parse.cc b/Console/Parse.cc index b916ae0..bc4fd46 100644 --- a/Console/Parse.cc +++ b/Console/Parse.cc @@ -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" diff --git a/Console/Parse.cci b/Console/Parse.cci index c7c6c61..fcce862 100644 --- a/Console/Parse.cci +++ b/Console/Parse.cci @@ -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, diff --git a/Console/ParsedCommand.cc b/Console/ParsedCommand.cc index d593eb1..da6144b 100644 --- a/Console/ParsedCommand.cc +++ b/Console/ParsedCommand.cc @@ -33,6 +33,12 @@ ///////////////////////////////cc.p//////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// +// senf::console::detail::ArgumentInfoBase + +prefix_ senf::console::detail::ArgumentInfoBase::~ArgumentInfoBase() +{} + +//////////////////////////////////////////////////////////////////////// // senf::console::ParsedCommandOverloadBase prefix_ unsigned senf::console::ParsedCommandOverloadBase::v_numArguments() diff --git a/Console/ParsedCommand.cci b/Console/ParsedCommand.cci index 1cd764b..aeab60e 100644 --- a/Console/ParsedCommand.cci +++ b/Console/ParsedCommand.cci @@ -31,6 +31,13 @@ ///////////////////////////////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 { diff --git a/Console/ParsedCommand.cti b/Console/ParsedCommand.cti index 61b447f..b6d140f 100644 --- a/Console/ParsedCommand.cti +++ b/Console/ParsedCommand.cti @@ -34,13 +34,6 @@ ///////////////////////////////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 template diff --git a/Console/ParsedCommand.ih b/Console/ParsedCommand.ih index 90231c2..330ea7c 100644 --- a/Console/ParsedCommand.ih +++ b/Console/ParsedCommand.ih @@ -66,6 +66,7 @@ namespace detail { std::string doc; ArgumentInfoBase(std::string const & type); + virtual ~ArgumentInfoBase(); virtual std::string defaultValueStr() const = 0; }; diff --git a/Console/ProgramOptions.cc b/Console/ProgramOptions.cc index 118a774..6eb3107 100644 --- a/Console/ProgramOptions.cc +++ b/Console/ProgramOptions.cc @@ -28,37 +28,72 @@ // Custom includes #include +#include //#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); isecond.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 - 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); +} /////////////////////////////////////////////////////////////////////////// diff --git a/Console/ProgramOptions.cci b/Console/ProgramOptions.cci index 96415c0..8896fa0 100644 --- a/Console/ProgramOptions.cci +++ b/Console/ProgramOptions.cci @@ -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 index 0000000..0091819 --- /dev/null +++ b/Console/ProgramOptions.cti @@ -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 +// +// 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 +prefix_ senf::console::detail::ProgramOptionsSource & +senf::console::detail::ProgramOptionsSource::nonOptions(Container & container) +{ + nonOptions_.reset(new NonOptionContainerImpl(container)); + return *this; +} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::ProgramOptionsSource::NonOptionContainerImpl + +template +prefix_ +senf::console::detail::ProgramOptionsSource::NonOptionContainerImpl:: +NonOptionContainerImpl(Container & c) + : c_ (c) +{} + +template +prefix_ void +senf::console::detail::ProgramOptionsSource::NonOptionContainerImpl::clear() +{ + c_.clear(); +} + +template +prefix_ void +senf::console::detail::ProgramOptionsSource::NonOptionContainerImpl:: +push_back(std::string const & value) +{ + c_.push_back(value); +} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::ProgramOptions + +template +prefix_ senf::console::ProgramOptions & +senf::console::ProgramOptions::nonOptions(Container & container) +{ + config_.nonOptions(container); + return *this; +} + +///////////////////////////////cti.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/ProgramOptions.hh b/Console/ProgramOptions.hh index 253f1a8..7fab5dc 100644 --- a/Console/ProgramOptions.hh +++ b/Console/ProgramOptions.hh @@ -49,6 +49,13 @@ namespace console { ///@} /////////////////////////////////////////////////////////////////////////// + + template + 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 diff --git a/Console/ProgramOptions.ih b/Console/ProgramOptions.ih index 36e9e55..8fdf488 100644 --- a/Console/ProgramOptions.ih +++ b/Console/ProgramOptions.ih @@ -27,6 +27,7 @@ #define IH_ProgramOptions_ 1 // Custom includes +#include #include "Parse.hh" ///////////////////////////////ih.p//////////////////////////////////////// @@ -38,7 +39,13 @@ namespace detail { class ProgramOptionsSource : public ConfigSource { public: + typedef boost::intrusive_ptr ptr; + static ptr create(int argc, char ** argv); + + template + 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 + 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 ShortOptions; int argc_; char ** argv_; CommandParser parser_; + ShortOptions shortOptions_; + boost::scoped_ptr nonOptions_; }; }}} diff --git a/Console/ProgramOptions.test.cc b/Console/ProgramOptions.test.cc index 2e24c8b..f630141 100644 --- a/Console/ProgramOptions.test.cc +++ b/Console/ProgramOptions.test.cc @@ -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//////////////////////////////////////// diff --git a/Console/Server.cci b/Console/Server.cci index 78387d6..427e8ea 100644 --- a/Console/Server.cci +++ b/Console/Server.cci @@ -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(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(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_