From: g0dil Date: Fri, 23 May 2008 16:24:03 +0000 (+0000) Subject: Console: Refactor config file parser into several classes X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=cb82981586c94137cf1009cecfa3262295b4925c;p=senf.git Console: Refactor config file parser into several classes Console: Implement program option parsing git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@852 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Console/Config.cc b/Console/Config.cc index 3d2200b..dc08724 100644 --- a/Console/Config.cc +++ b/Console/Config.cc @@ -24,48 +24,40 @@ \brief Config non-inline non-template implementation */ #include "Config.hh" -//#include "Config.ih" +#include "Config.ih" // Custom includes +#include "../Utils/membind.hh" //#include "Config.mpp" #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// -// senf::console::ConfigFile +// senf::console::detail::RestrictedExecutor -#ifndef DOXYGEN - -namespace { - struct BindPolicy - { - BindPolicy(senf::console::Executor & e, senf::console::Executor::SecurityPolicy p) - : e_ (e) - { e_.policy(p); } - - ~BindPolicy() - { e_.policy(senf::console::Executor::SecurityPolicy()); } - - senf::console::Executor & e_; - }; +prefix_ senf::console::detail::RestrictedExecutor::RestrictedExecutor(DirectoryNode & root) +{ + executor_ + .chroot(root) + .policy(senf::membind(&RestrictedExecutor::policyCallback, this)); } -#endif +prefix_ void +senf::console::detail::RestrictedExecutor::execute(std::ostream & output, + ParseCommandInfo const & command) +{ + executor_.execute(output, command); +} -prefix_ void senf::console::ConfigFile::parse(DirectoryNode & restrict) +prefix_ void +senf::console::detail::RestrictedExecutor::operator()(std::ostream & output, + ParseCommandInfo const & command) { - DirectoryNode::ptr r (restrict.thisptr()); - BindPolicy bp ( executor_, - boost::bind(&ConfigFile::policyCallback, this, r, _1, _2) ); - if (! parser_.parseFile(filename_, boost::bind( boost::ref(executor_), - boost::ref(std::cerr), - _1 )) ) - throw SyntaxErrorException(); - insertParsedNode(r); + execute(output, command); } -prefix_ bool senf::console::ConfigFile::parsed(GenericNode & node) +prefix_ bool senf::console::detail::RestrictedExecutor::parsed(GenericNode & node) const { ParsedNodes::const_iterator i (parsedNodes_.begin()); @@ -76,18 +68,17 @@ prefix_ bool senf::console::ConfigFile::parsed(GenericNode & node) return false; } -prefix_ void senf::console::ConfigFile::policyCallback(DirectoryNode::ptr restrict, - DirectoryNode & dir, - std::string const & name) +prefix_ void senf::console::detail::RestrictedExecutor::policyCallback(DirectoryNode & dir, + std::string const & name) { if (dir.hasChild(name)) { GenericNode & item (dir.get(name)); - if (restrict && ! item.isChildOf(*restrict) && ! item.isDirectory()) + if (restrict_ && ! item.isChildOf(*restrict_) && ! item.isDirectory()) throw Executor::IgnoreCommandException(); if (parsed(item)) throw Executor::IgnoreCommandException(); } - else if (restrict && ! dir.isChildOf(*restrict)) + else if (restrict_ && ! dir.isChildOf(*restrict_)) throw Executor::IgnoreCommandException(); } @@ -103,20 +94,63 @@ namespace { }; } -prefix_ void senf::console::ConfigFile::insertParsedNode(DirectoryNode::ptr node) +prefix_ void +senf::console::detail::RestrictedExecutor::insertParsedNode(DirectoryNode & node) { parsedNodes_.erase( - std::remove_if(parsedNodes_.begin(), parsedNodes_.end(), RemoveNodesFn(node)), + std::remove_if(parsedNodes_.begin(), parsedNodes_.end(), RemoveNodesFn(node.thisptr())), parsedNodes_.end()); - parsedNodes_.push_back(node); + parsedNodes_.push_back(node.thisptr()); } /////////////////////////////////////////////////////////////////////////// +// senf::console::ConfigBundle + +prefix_ void senf::console::ConfigBundle::parse() +{ + detail::RestrictedExecutor::RestrictGuard guard (executor_); + parseInternal(); +} + +prefix_ void senf::console::ConfigBundle::parse(DirectoryNode & restrict) +{ + detail::RestrictedExecutor::RestrictGuard guard (executor_, restrict); + parseInternal(); +} + +prefix_ void senf::console::ConfigBundle::parseInternal() +{ + Sources::const_iterator i (sources_.begin()); + Sources::const_iterator const i_end (sources_.end()); + for (; i != i_end; ++i) + (*i)->parse(executor_); +} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::RestrictedExecutor::RestrictGuard + +prefix_ senf::console::detail::RestrictedExecutor::RestrictGuard:: +RestrictGuard(RestrictedExecutor & executor) + : executor_ (executor) +{ + // This MUST BE root() not chroot() since restriction does NOT follow symlinks. + // Therefore, if chroot() is a directory of symlinks, restricting to it will + // execute NOTHING. + executor_.restrict_ = senf::console::root().thisptr(); +} + +prefix_ senf::console::detail::RestrictedExecutor::RestrictGuard:: +RestrictGuard(RestrictedExecutor & executor, DirectoryNode & restrict) + : executor_ (executor) +{ + executor_.restrict_ = restrict.thisptr(); +} -prefix_ void senf::console::readConfig(std::string const & filename, DirectoryNode & root) +prefix_ senf::console::detail::RestrictedExecutor::RestrictGuard::~RestrictGuard() { - ConfigFile cfg (filename, root); - cfg.parse(); + if (! std::uncaught_exception()) + executor_.insertParsedNode( *executor_.restrict_ ); + executor_.restrict_ = senf::console::root().thisptr(); } ///////////////////////////////cc.e//////////////////////////////////////// diff --git a/Console/Config.cci b/Console/Config.cci index 3c96a59..1fb445b 100644 --- a/Console/Config.cci +++ b/Console/Config.cci @@ -23,7 +23,7 @@ /** \file \brief Config inline non-template implementation */ -//#include "Config.ih" +#include "Config.ih" // Custom includes #include "../Utils/membind.hh" @@ -32,21 +32,41 @@ ///////////////////////////////cci.p/////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// -// senf::console::ConfigFile +// senf::console::ConfigBundle -prefix_ senf::console::ConfigFile::ConfigFile(std::string const & filename, - DirectoryNode & root) - : filename_ (filename) +prefix_ senf::console::ConfigBundle::ConfigBundle() +{} + +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 { - executor_.chroot(root); + return executor_.complete(); } -prefix_ void senf::console::ConfigFile::parse() +prefix_ bool senf::console::ConfigBundle::parsed(GenericNode & node) + const +{ + return executor_.parsed(node); +} + +prefix_ void senf::console::ConfigBundle::reset() { - parse(executor_.chroot()); + executor_.reset(); } -prefix_ bool senf::console::ConfigFile::complete() +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::RestrictedExecutor + +prefix_ bool senf::console::detail::RestrictedExecutor::complete() const { return parsedNodes_.size() == 1 @@ -54,11 +74,67 @@ prefix_ bool senf::console::ConfigFile::complete() && *parsedNodes_[0].lock() == executor_.chroot(); } -prefix_ void senf::console::ConfigFile::reset() +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) +{ + v_parse(executor); +} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::BundleMixin + +prefix_ senf::console::detail::BundleMixin::BundleMixin() +{} + +prefix_ senf::console::detail::BundleMixin::BundleMixin(DirectoryNode & root) + : bundle_ (root) +{} + +prefix_ void senf::console::detail::BundleMixin::parse() +{ + bundle_.parse(); +} + +prefix_ void senf::console::detail::BundleMixin::parse(DirectoryNode & restrict) +{ + bundle_.parse(restrict); +} + +prefix_ bool senf::console::detail::BundleMixin::complete() + const +{ + return bundle_.complete(); +} + +prefix_ bool senf::console::detail::BundleMixin::parsed(GenericNode & node) + const +{ + return bundle_.parsed(node); +} + +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.hh b/Console/Config.hh index 898a02a..e4f5c63 100644 --- a/Console/Config.hh +++ b/Console/Config.hh @@ -32,45 +32,39 @@ #include "Executor.hh" //#include "Config.mpp" +#include "Config.ih" ///////////////////////////////hh.p//////////////////////////////////////// namespace senf { namespace console { - /** \brief Console node tree based config file parser - - A ConfigFile instance allows flexible parsing of a config file against the console node - tree. If you just want to parse a file completely, the senf::console::readConfig() function - will do that. ConfigFile however allows to incrementally parse only a subdirectory of the - complete configuration file. - \code - senf::console::ConfigFile cf ("/my/config/file") - - // Parse only statements under the directory of some object. The object 'ob' - // must have been registered somewhere in the node tree - cf.parse(ob.dir); - - // Parse rest of the config file - cf.parse(); - \endcode + /** \brief */ - class ConfigFile - : boost::noncopyable + class ConfigBundle { public: /////////////////////////////////////////////////////////////////////////// + // Types + + /////////////////////////////////////////////////////////////////////////// ///\name Structors and default members ///@{ - explicit ConfigFile(std::string const & filename, DirectoryNode & root = root()); - ///< Create ConfigFile object for \a filename - /**< The \a filename configuration file will be parsed using - parse() calls. All configuration statements will be - interpreted relative to \a root as root node. */ + ConfigBundle(); + ConfigBundle(DirectoryNode & root); + + // default default constructor + // default copy constructor + // default copy assignment + // default destructor + + // no conversion constructors ///@} /////////////////////////////////////////////////////////////////////////// + void add(detail::ConfigSource::ptr source); + void parse(); ///< Parse config file /**< All nodes already parsed are skipped */ void parse(DirectoryNode & restrict); ///< Parse config file under \a restrict @@ -79,7 +73,6 @@ namespace console { 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 /**< After a call to reset(), all information about already parsed nodes is cleared. Calling parse() will parse the @@ -88,32 +81,44 @@ namespace console { protected: private: - void policyCallback(DirectoryNode::ptr restrict, DirectoryNode & dir, - std::string const & item); + void parseInternal(); - void insertParsedNode(DirectoryNode::ptr node); + typedef std::vector Sources; - typedef std::vector ParsedNodes; + Sources sources_; + detail::RestrictedExecutor executor_; + }; - std::string filename_; - CommandParser parser_; - Executor executor_; +namespace detail { + // hrmpf ... Can't place this into Config.ih ... - ParsedNodes parsedNodes_; - }; + class BundleMixin + { + public: + BundleMixin(); + BundleMixin(DirectoryNode & root); - /** \brief Read configuration file + void parse(); ///< Parse config file + /**< All nodes already parsed are skipped */ + void parse(DirectoryNode & restrict); ///< Parse config file under \a restrict + /**< Only nodes which are children of \a restrict are + parsed. */ - The configuration file \a filename will be loaded, interpreting all node's relative to \a - root as root node. + 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 + /**< After a call to reset(), all information about already + parsed nodes is cleared. Calling parse() will parse the + complete config file again. */ - This function uses a local ConfigFile object to perform the parsing. + protected: + void add(ConfigSource::ptr source); - \related ConfigFile - */ - void readConfig(std::string const & filename, DirectoryNode & root = root()); + private: + ConfigBundle bundle_; + }; -}} +}}} ///////////////////////////////hh.e//////////////////////////////////////// #include "Config.cci" diff --git a/Console/Config.ih b/Console/Config.ih new file mode 100644 index 0000000..3a598b9 --- /dev/null +++ b/Console/Config.ih @@ -0,0 +1,143 @@ +// $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 internal header */ + +#ifndef IH_Console_Config_ +#define IH_Console_Config_ 1 + +// Custom includes +#include +#include +#include "Executor.hh" +#include "../Utils/intrusive_refcount.hh" + +///////////////////////////////ih.p//////////////////////////////////////// + +namespace senf { +namespace console { +namespace detail { + + class RestrictedExecutor + : boost::noncopyable + { + public: + typedef void result_type; + + /////////////////////////////////////////////////////////////////////////// + //\/name Structors and default members + ///\{ + + RestrictedExecutor(DirectoryNode & root = senf::console::root()); + + ///\} + /////////////////////////////////////////////////////////////////////////// + + void execute(std::ostream & output, ParseCommandInfo const & command); + ///< Execute command + /**< Output will be written to \a output. + Same as operator()(). */ + + void operator()(std::ostream & output, ParseCommandInfo const & command); + ///< Execute command + /**< Output will be written to \a output. + Same as execute(). */ + + 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 + /**< After a call to reset(), all information about already + parsed nodes is cleared. Calling parse() will parse the + complete config file again. */ + + DirectoryNode & root() const; + + class RestrictGuard; + + protected: + + private: + void policyCallback(DirectoryNode & dir, std::string const & item); + void insertParsedNode(DirectoryNode & node); + + typedef std::vector ParsedNodes; + + Executor executor_; + ParsedNodes parsedNodes_; + DirectoryNode::ptr restrict_; + + friend class RestrictGuard; + }; + + class RestrictedExecutor::RestrictGuard + { + public: + /////////////////////////////////////////////////////////////////////////// + //\/name Structors and default members + ///\{ + + explicit RestrictGuard(RestrictedExecutor & executor); + RestrictGuard(RestrictedExecutor & executor, DirectoryNode & restrict); + ~RestrictGuard(); + + ///\} + /////////////////////////////////////////////////////////////////////////// + + protected: + + private: + RestrictedExecutor & executor_; + + }; + + /** \brief + */ + class ConfigSource + : public senf::intrusive_refcount + { + public: + typedef boost::intrusive_ptr ptr; + + void parse(RestrictedExecutor & executor); + + protected: + + private: + virtual void v_parse(RestrictedExecutor & executor) = 0; + }; + +}}} + +///////////////////////////////ih.e//////////////////////////////////////// +#endif + + +// 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.cc b/Console/ConfigFile.cc new file mode 100644 index 0000000..b20529d --- /dev/null +++ b/Console/ConfigFile.cc @@ -0,0 +1,67 @@ +// $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 ConfigFile non-inline non-template implementation */ + +#include "ConfigFile.hh" +#include "ConfigFile.ih" + +// Custom includes + +//#include "ConfigFile.mpp" +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::ConfigFileSource + +prefix_ void senf::console::detail::ConfigFileSource::v_parse(RestrictedExecutor & executor) +{ + if (! parser_.parseFile(filename_, boost::bind( boost::ref(executor), + boost::ref(std::cerr), + _1 )) ) + throw SyntaxErrorException(); +} + +/////////////////////////////////////////////////////////////////////////// + +prefix_ void senf::console::readConfig(std::string const & filename, DirectoryNode & root) +{ + ConfigFile cfg (filename, root); + cfg.parse(); +} + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ +//#include "ConfigFile.mpp" + + +// 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.cci b/Console/ConfigFile.cci new file mode 100644 index 0000000..8e80db8 --- /dev/null +++ b/Console/ConfigFile.cci @@ -0,0 +1,76 @@ +// $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 ConfigFile inline non-template implementation */ + +#include "ConfigFile.ih" + +// Custom includes + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::ConfigFileSource + +prefix_ senf::console::detail::ConfigFileSource::ptr +senf::console::detail::ConfigFileSource::create(std::string const & filename) +{ + return ptr(new ConfigFileSource(filename)); +} + +prefix_ senf::console::detail::ConfigFileSource::ConfigFileSource(std::string const & filename) + : filename_ (filename) +{} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::ConfigFile + +prefix_ senf::console::ConfigFile::ConfigFile(std::string const & filename, + DirectoryNode & root) + : detail::BundleMixin(root) +{ + add(detail::ConfigFileSource::create(filename)); +} + +/////////////////////////////////////////////////////////////////////////// + +prefix_ senf::console::detail::ConfigFileSource::ptr +senf::console::FileConfig(std::string const & filename) +{ + return detail::ConfigFileSource::create(filename); +} + +///////////////////////////////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/ConfigFile.hh b/Console/ConfigFile.hh new file mode 100644 index 0000000..3e08edf --- /dev/null +++ b/Console/ConfigFile.hh @@ -0,0 +1,104 @@ +// $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 ConfigFile public header */ + +#ifndef HH_ConfigFile_ +#define HH_ConfigFile_ 1 + +// Custom includes +#include "Config.hh" + +//#include "ConfigFile.mpp" +#include "ConfigFile.ih" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { +namespace console { + + /** \brief Console node tree based config file parser + + A ConfigFile instance allows flexible parsing of a config file against the console node + tree. If you just want to parse a file completely, the senf::console::readConfig() function + will do that. ConfigFile however allows to incrementally parse only a subdirectory of the + complete configuration file. + \code + senf::console::ConfigFile cf ("/my/config/file") + + // Parse only statements under the directory of some object. The object 'ob' + // must have been registered somewhere in the node tree + cf.parse(ob.dir); + + // Parse rest of the config file + cf.parse(); + \endcode + */ + class ConfigFile + : public detail::BundleMixin + { + public: + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + explicit ConfigFile(std::string const & filename, DirectoryNode & root = root()); + ///< Create ConfigFile object for \a filename + /**< The \a filename configuration file will be parsed using + parse() calls. All configuration statements will be + interpreted relative to \a root as root node. */ + + ///@} + /////////////////////////////////////////////////////////////////////////// + }; + + /** \brief Read configuration file + + The configuration file \a filename will be loaded, interpreting all node's relative to \a + root as root node. + + This function uses a local ConfigFile object to perform the parsing. + + \related ConfigFile + */ + void readConfig(std::string const & filename, DirectoryNode & root = root()); + + detail::ConfigFileSource::ptr FileConfig(std::string const & filename); + +}} + +///////////////////////////////hh.e//////////////////////////////////////// +#include "ConfigFile.cci" +//#include "ConfigFile.ct" +//#include "ConfigFile.cti" +#endif + + +// 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 new file mode 100644 index 0000000..9bb15e2 --- /dev/null +++ b/Console/ConfigFile.ih @@ -0,0 +1,65 @@ +// $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 ConfigFile internal header */ + +#ifndef IH_ConfigFile_ +#define IH_ConfigFile_ 1 + +// Custom includes + +///////////////////////////////ih.p//////////////////////////////////////// + +namespace senf { +namespace console { +namespace detail { + + class ConfigFileSource : public ConfigSource + { + public: + static ptr create(std::string const & filename); + + private: + ConfigFileSource(std::string const & filename); + + virtual void v_parse(RestrictedExecutor & executor); + + std::string filename_; + CommandParser parser_; + }; + +}}} + +///////////////////////////////ih.e//////////////////////////////////////// +#endif + + +// 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.test.cc b/Console/ConfigFile.test.cc similarity index 97% rename from Console/Config.test.cc rename to Console/ConfigFile.test.cc index df3383b..b8e68b9 100644 --- a/Console/Config.test.cc +++ b/Console/ConfigFile.test.cc @@ -21,13 +21,13 @@ // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \file - \brief Config.test unit tests */ + \brief ConfigFile.test unit tests */ -//#include "Config.test.hh" -//#include "Config.test.ih" +//#include "ConfigFile.test.hh" +//#include "ConfigFile.test.ih" // Custom includes -#include "Config.hh" +#include "ConfigFile.hh" #include #include "ScopedDirectory.hh" #include "ParsedCommand.hh" @@ -61,7 +61,6 @@ namespace { std::string name_; std::ofstream file_; }; - } diff --git a/Console/Executor.hh b/Console/Executor.hh index 882792a..81049b1 100644 --- a/Console/Executor.hh +++ b/Console/Executor.hh @@ -72,6 +72,8 @@ namespace console { /// Thrown by the SecurityPolicy to silently ignore a command struct IgnoreCommandException {}; + typedef void result_type; + /////////////////////////////////////////////////////////////////////////// //\/name Structors and default members ///\{ diff --git a/Console/Parse.cc b/Console/Parse.cc index 57aba80..b916ae0 100644 --- a/Console/Parse.cc +++ b/Console/Parse.cc @@ -42,85 +42,70 @@ namespace detail { #ifndef DOXYGEN - struct ParserAccess - { - static void init(ParseCommandInfo & info) - { info.init(); } - - static void setBuiltin(ParseCommandInfo & info, ParseCommandInfo::BuiltinCommand builtin) - { info.setBuiltin(builtin); } - - static void setCommand(ParseCommandInfo & info, std::vector & commandPath) - { info.setCommand(commandPath); } - - static void addToken(ParseCommandInfo & info, Token const & token) - { info.addToken(token); } - }; - struct ParseDispatcher { - ParseCommandInfo info_; + ParseCommandInfo * info_; CommandParser::Callback cb_; struct BindInfo { - BindInfo( ParseDispatcher & d, CommandParser::Callback cb) - : dispatcher (d) { dispatcher.cb_ = cb; } - ~BindInfo() { dispatcher.cb_ = 0; } + BindInfo( ParseDispatcher & d, ParseCommandInfo & info, CommandParser::Callback cb) + : dispatcher (d) { dispatcher.info_ = &info; dispatcher.cb_ = cb; } + ~BindInfo() { dispatcher.info_ = 0; dispatcher.cb_ = 0; } ParseDispatcher & dispatcher; }; void beginCommand(std::vector & command) - { ParserAccess::init(info_); - ParserAccess::setCommand(info_, command); } + { info_->clear(); + info_->command(command); } void endCommand() - { cb_(info_); } + { cb_(*info_); } void pushToken(Token const & token) - { ParserAccess::addToken(info_, token); } + { info_->addToken(token); } void builtin_cd(std::vector & path) - { ParserAccess::init(info_); - ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinCD); + { info_->clear(); + info_->builtin(ParseCommandInfo::BuiltinCD); setBuiltinPathArg(path); - cb_(info_); } + cb_(*info_); } void builtin_ls(std::vector & path) - { ParserAccess::init(info_); - ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinLS); + { info_->clear(); + info_->builtin(ParseCommandInfo::BuiltinLS); setBuiltinPathArg(path); - cb_(info_); } + cb_(*info_); } void pushDirectory(std::vector & path) - { ParserAccess::init(info_); - ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPUSHD); + { info_->clear(); + info_->builtin(ParseCommandInfo::BuiltinPUSHD); setBuiltinPathArg(path); - cb_(info_); } + cb_(*info_); } void popDirectory() - { ParserAccess::init(info_); - ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPOPD); - cb_(info_); } + { info_->clear(); + info_->builtin(ParseCommandInfo::BuiltinPOPD); + cb_(*info_); } void builtin_exit() - { ParserAccess::init(info_); - ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinEXIT); - cb_(info_); } + { info_->clear(); + info_->builtin(ParseCommandInfo::BuiltinEXIT); + cb_(*info_); } void builtin_help(std::vector & path) - { ParserAccess::init(info_); - ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinHELP); + { info_->clear(); + info_->builtin(ParseCommandInfo::BuiltinHELP); setBuiltinPathArg(path); - cb_(info_); } + cb_(*info_); } void setBuiltinPathArg(std::vector & path) { - pushToken(Token(Token::ArgumentGroupOpen, "(")); + pushToken(ArgumentGroupOpenToken()); for (std::vector::const_iterator i (path.begin()); i != path.end(); ++i) pushToken(*i); - pushToken(Token(Token::ArgumentGroupClose, ")")); + pushToken(ArgumentGroupCloseToken()); } }; @@ -270,7 +255,8 @@ prefix_ senf::console::CommandParser::~CommandParser() prefix_ bool senf::console::CommandParser::parse(std::string command, Callback cb) { - detail::ParseDispatcher::BindInfo bind (impl().dispatcher, cb); + ParseCommandInfo info; + detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info, cb); return boost::spirit::parse( command.begin(), command.end(), impl().grammar.use_parser(), impl().grammar.use_parser() @@ -279,7 +265,8 @@ prefix_ bool senf::console::CommandParser::parse(std::string command, Callback c prefix_ bool senf::console::CommandParser::parseFile(std::string filename, Callback cb) { - detail::ParseDispatcher::BindInfo bind (impl().dispatcher, cb); + ParseCommandInfo info; + detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info, cb); boost::spirit::file_iterator<> i (filename); if (!i) throw SystemException(ENOENT SENF_EXC_DEBUGINFO); boost::spirit::file_iterator<> const i_end (i.make_end()); @@ -290,6 +277,16 @@ prefix_ bool senf::console::CommandParser::parseFile(std::string filename, Callb ).full; } +prefix_ bool senf::console::CommandParser::parseArguments(std::string arguments, + ParseCommandInfo & info) +{ + detail::ParseDispatcher::BindInfo bind (impl().dispatcher, info, 0); + return boost::spirit::parse( arguments.begin(), arguments.end(), + impl().grammar.use_parser(), + impl().grammar.use_parser() + ).full; +} + ///////////////////////////////cc.e//////////////////////////////////////// #undef prefix_ //#include "Parse.mpp" diff --git a/Console/Parse.cci b/Console/Parse.cci index 0482101..c7c6c61 100644 --- a/Console/Parse.cci +++ b/Console/Parse.cci @@ -131,6 +131,10 @@ prefix_ senf::console::Token senf::console::WordToken(std::string const & value) /////////////////////////////////////////////////////////////////////////// // senf::console::ParseCommandInfo +prefix_ senf::console::ParseCommandInfo::ParseCommandInfo() + : builtin_ (NoBuiltin) +{} + prefix_ senf::console::ParseCommandInfo::BuiltinCommand senf::console::ParseCommandInfo::builtin() const @@ -159,26 +163,25 @@ prefix_ senf::console::ParseCommandInfo::TokensRange senf::console::ParseCommand return boost::make_iterator_range(tokens_.begin(), tokens_.end()); } -//////////////////////////////////////// -// private members - -prefix_ void senf::console::ParseCommandInfo::init() +prefix_ void senf::console::ParseCommandInfo::clear() { builtin_ = NoBuiltin; commandPath_.clear(); tokens_.clear(); } -prefix_ void senf::console::ParseCommandInfo::setBuiltin(BuiltinCommand builtin) +prefix_ void senf::console::ParseCommandInfo::builtin(BuiltinCommand builtin) { builtin_ = builtin; + commandPath_.clear(); } prefix_ void -senf::console::ParseCommandInfo::setCommand(std::vector & commandPath) +senf::console::ParseCommandInfo::command(std::vector & commandPath) { commandPath_.clear(); commandPath_.swap(commandPath); + builtin_ = NoBuiltin; } prefix_ void senf::console::ParseCommandInfo::addToken(Token const & token) diff --git a/Console/Parse.hh b/Console/Parse.hh index 8c38dae..142060d 100644 --- a/Console/Parse.hh +++ b/Console/Parse.hh @@ -274,7 +274,6 @@ namespace console { std::ostream & operator<<(std::ostream & os, Token const & token); - Token NoneToken(); Token PathSeparatorToken(); Token ArgumentGroupOpenToken(); @@ -325,6 +324,8 @@ namespace console { BuiltinEXIT, BuiltinHELP }; + ParseCommandInfo(); + BuiltinCommand builtin() const; ///< Command type /**< \returns \c NoBuiltin, if the command is an ordinary command, otherwise the id of the built-in command */ @@ -341,21 +342,22 @@ namespace console { TokensRange tokens() const; ///< All argument tokens /**< The returned range contains \e all argument tokens in a single range not divided into separate arguments. */ - protected: - private: - void init(); - void setBuiltin(BuiltinCommand builtin); - void setCommand(std::vector & commandPath); + void clear(); + + void builtin(BuiltinCommand builtin); + void command(std::vector & commandPath); + void addToken(Token const & token); + protected: + + private: struct MakeRange; std::vector commandPath_; BuiltinCommand builtin_; Tokens tokens_; - - friend class detail::ParserAccess; }; /** \brief Iterator parsing argument groups @@ -561,6 +563,8 @@ namespace console { /**< \throws SystemException if the file cannot be read. */ + bool parseArguments(std::string arguments, ParseCommandInfo & info); + private: struct Impl; diff --git a/Console/Parse.ih b/Console/Parse.ih index 79b30b6..ae9a193 100644 --- a/Console/Parse.ih +++ b/Console/Parse.ih @@ -77,7 +77,7 @@ namespace detail { /////////////////////////////////////////////////////////////////////////// // Start rules - enum { CommandParser, SkipParser }; + enum { CommandParser, SkipParser, ArgumentsParser }; /////////////////////////////////////////////////////////////////////////// // The parse context (variables needed while parsing) @@ -174,11 +174,12 @@ namespace detail { template struct definition : public boost::spirit::grammar_def< boost::spirit::rule, + boost::spirit::rule, boost::spirit::rule > { boost::spirit::rule command, path, argument, word, string, hexstring, token, punctuation, hexbyte, balanced_tokens, simple_argument, complex_argument, builtin, - skip, commands, block, statement, relpath, abspath; + skip, commands, block, statement, relpath, abspath, arguments; boost::spirit::chset<> special_p, punctuation_p, space_p, invalid_p, word_p; boost::spirit::distinct_parser<> keyword_p; @@ -284,11 +285,15 @@ namespace detail { statement = eps_p [ self.dispatch(&PD::beginCommand, boost::ref(self.context.path)) ] - >> * argument + >> arguments >> (ch_p(';') | end_p) >> eps_p [ self.dispatch(&PD::endCommand) ] ; + arguments + = * argument + ; + argument = simple_argument [ self.dispatch(&PD::pushToken, boost::ref(self.context.token)) ] @@ -392,7 +397,8 @@ namespace detail { start_parsers( commands, // CommandParser - skip // SkipParser + skip, // SkipParser + arguments // ArgumentsParser ); BOOST_SPIRIT_DEBUG_TRACE_RULE(command,1); diff --git a/Console/ProgramOptions.cc b/Console/ProgramOptions.cc new file mode 100644 index 0000000..118a774 --- /dev/null +++ b/Console/ProgramOptions.cc @@ -0,0 +1,128 @@ +// $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 non-inline non-template implementation */ + +#include "ProgramOptions.hh" +#include "ProgramOptions.ih" + +// Custom includes +#include + +//#include "ProgramOptions.mpp" +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::ProgramOptionsSource + +prefix_ void senf::console::detail::ProgramOptionsSource::v_parse(RestrictedExecutor & executor) +{ + char ** argp (argv_); + int n (argc_); + for (; n; --n, ++argp) { + std::string arg (*argp); + if (boost::algorithm::starts_with(arg, std::string("--"))) + parseLongOption(arg.substr(2), 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) +{ + std::string::size_type ix (arg.find('=')); + std::string name (arg.substr(0,ix)); + std::string value (ix==std::string::npos ? std::string() : arg.substr(ix+1)); + + typedef std::vector Path; + + ParseCommandInfo cmd; + Path path; + + DirectoryNode::ptr cwd (executor.root().thisptr()); + std::string::size_type b (0); + 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; + } + } + if (e == std::string::npos || e <= b) { + // This will produce a correct error message later + path.push_back(WordToken(name.substr(b))); + b = name.size(); + } + } + + cmd.command(path); + parser_.parseArguments(value, cmd); + executor(std::cerr, cmd); +} + +prefix_ void +senf::console::detail::ProgramOptionsSource::parseNonOption(std::string const & arg, + RestrictedExecutor & executor) +{} + +/////////////////////////////////////////////////////////////////////////// + +prefix_ void senf::console::parseOptions(int argc, char ** argv, DirectoryNode & root) +{ + ProgramOptions opts (argc, argv, root); + opts.parse(); +} + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ +//#include "ProgramOptions.mpp" + + +// 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.cci b/Console/ProgramOptions.cci new file mode 100644 index 0000000..96415c0 --- /dev/null +++ b/Console/ProgramOptions.cci @@ -0,0 +1,77 @@ +// $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 non-template implementation */ + +#include "ProgramOptions.ih" + +// Custom includes + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::ProgramOptionsSource + +prefix_ senf::console::detail::ProgramOptionsSource::ptr +senf::console::detail::ProgramOptionsSource::create(int argc, char ** argv) +{ + return ptr(new ProgramOptionsSource(argc,argv)); +} + +prefix_ senf::console::detail::ProgramOptionsSource::ProgramOptionsSource(int argc, + char ** argv) + : argc_ (argc), argv_ (argv) +{} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::ProgramOptions + +prefix_ senf::console::ProgramOptions::ProgramOptions(int argc, char ** argv, + DirectoryNode & root) + : detail::BundleMixin (root) +{ + add(detail::ProgramOptionsSource::create(argc, argv)); +} + +/////////////////////////////////////////////////////////////////////////// + +prefix_ senf::console::detail::ProgramOptionsSource::ptr +senf::console::OptionsConfig(int argc, char ** argv) +{ + return detail::ProgramOptionsSource::create(argc, argv); +} + +///////////////////////////////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/ProgramOptions.hh b/Console/ProgramOptions.hh new file mode 100644 index 0000000..253f1a8 --- /dev/null +++ b/Console/ProgramOptions.hh @@ -0,0 +1,74 @@ +// $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 public header */ + +#ifndef HH_ProgramOptions_ +#define HH_ProgramOptions_ 1 + +// Custom includes +#include "Config.hh" + + +//#include "ProgramOptions.mpp" +#include "ProgramOptions.ih" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { +namespace console { + + class ProgramOptions + : public detail::BundleMixin + { + public: + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + ProgramOptions(int argc, char ** argv, DirectoryNode & root = root()); + + ///@} + /////////////////////////////////////////////////////////////////////////// + }; + + void parseOptions(int argc, char ** argv, DirectoryNode & root = root()); + + detail::ProgramOptionsSource::ptr OptionsConfig(int argc, char ** argv); +}} + +///////////////////////////////hh.e//////////////////////////////////////// +#include "ProgramOptions.cci" +//#include "ProgramOptions.ct" +//#include "ProgramOptions.cti" +#endif + + +// 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.ih b/Console/ProgramOptions.ih new file mode 100644 index 0000000..36e9e55 --- /dev/null +++ b/Console/ProgramOptions.ih @@ -0,0 +1,70 @@ +// $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 internal header */ + +#ifndef IH_ProgramOptions_ +#define IH_ProgramOptions_ 1 + +// Custom includes +#include "Parse.hh" + +///////////////////////////////ih.p//////////////////////////////////////// + +namespace senf { +namespace console { +namespace detail { + + class ProgramOptionsSource : public ConfigSource + { + public: + static ptr create(int argc, char ** argv); + + private: + ProgramOptionsSource(int argc, char ** argv); + + virtual void v_parse(RestrictedExecutor & executor); + + void parseLongOption(std::string const & arg, RestrictedExecutor & executor); + void parseNonOption(std::string const & arg, RestrictedExecutor & executor); + + int argc_; + char ** argv_; + CommandParser parser_; + }; + +}}} + +///////////////////////////////ih.e//////////////////////////////////////// +#endif + + +// 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.test.cc b/Console/ProgramOptions.test.cc new file mode 100644 index 0000000..2e24c8b --- /dev/null +++ b/Console/ProgramOptions.test.cc @@ -0,0 +1,106 @@ +// $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.test unit tests */ + +//#include "ProgramOptions.test.hh" +//#include "ProgramOptions.test.ih" + +// Custom includes +#include "ProgramOptions.hh" +#include "ScopedDirectory.hh" +#include "ParsedCommand.hh" + +#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; } +} + +BOOST_AUTO_UNIT_TEST(programOptions) +{ + senf::console::ScopedDirectory<> root; + senf::console::root().add("root", root); + + root.mkdir("dir1").add("fun1", &fun1); + root.add("fun2", &fun2); + root.mkdir("name-with-dashes").add("fun-2", &fun2); + + { + char * argv[] = { "--dir1-fun1=foo","--fun2" }; + senf::console::ProgramOptions opts (sizeof(argv)/sizeof(argv[0]), argv, root); + + SENF_CHECK_NO_THROW( opts.parse() ); + BOOST_CHECK_EQUAL( val1, "foo" ); + BOOST_CHECK_EQUAL( val2, true ); + } + + { + char * argv[] = { "--d-f=foo","--fun" }; + senf::console::ProgramOptions opts (sizeof(argv)/sizeof(argv[0]), argv, root); + + val1 = ""; + val2 = false; + + SENF_CHECK_NO_THROW( opts.parse() ); + BOOST_CHECK_EQUAL( val1, "foo" ); + BOOST_CHECK_EQUAL( val2, true ); + } + + { + char * argv[] = { "--name-w-fun" }; + senf::console::ProgramOptions opts (sizeof(argv)/sizeof(argv[0]), argv, root); + + val1 = ""; + val2 = false; + + SENF_CHECK_NO_THROW( opts.parse() ); + BOOST_CHECK_EQUAL( val1, "" ); + 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: