From b27a278d8ab85afbad191d14962cc33e894718d4 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 2 May 2013 14:21:19 +0300 Subject: [PATCH] Restructure internals of GetOpt Value storage is now handled by a separate class hierarchy, making it more reusable. --- source/core/getopt.cpp | 42 +++++++++++++++------------ source/core/getopt.h | 64 ++++++++++++++++++++++++++---------------- 2 files changed, 64 insertions(+), 42 deletions(-) diff --git a/source/core/getopt.cpp b/source/core/getopt.cpp index 2bbfebc..e909712 100644 --- a/source/core/getopt.cpp +++ b/source/core/getopt.cpp @@ -17,11 +17,14 @@ GetOpt::~GetOpt() delete *i; } -GetOpt::OptBase &GetOpt::add_option(OptBase *opt) +GetOpt::OptionImpl &GetOpt::add_option(char s, const string &l, const Store &t, ArgType a) { + if(l.empty()) + throw invalid_argument("GetOpt::add_option"); + for(OptionList::iterator i=opts.begin(); i!=opts.end(); ) { - if((opt->get_short()!=0 && (*i)->get_short()==opt->get_short()) || (*i)->get_long()==opt->get_long()) + if((s!=0 && (*i)->get_short()==s) || (*i)->get_long()==l) { delete *i; opts.erase(i++); @@ -30,11 +33,11 @@ GetOpt::OptBase &GetOpt::add_option(OptBase *opt) ++i; } - opts.push_back(opt); + opts.push_back(new OptionImpl(s, l, t, a)); return *opts.back(); } -GetOpt::OptBase &GetOpt::get_option(char s) +GetOpt::OptionImpl &GetOpt::get_option(char s) { for(OptionList::iterator i=opts.begin(); i!=opts.end(); ++i) if((*i)->get_short()==s) @@ -42,7 +45,7 @@ GetOpt::OptBase &GetOpt::get_option(char s) throw usage_error(string("Unknown option -")+s); } -GetOpt::OptBase &GetOpt::get_option(const string &l) +GetOpt::OptionImpl &GetOpt::get_option(const string &l) { for(OptionList::iterator i=opts.begin(); i!=opts.end(); ++i) if((*i)->get_long()==l) @@ -94,7 +97,7 @@ unsigned GetOpt::process_long(const char *const *argp) unsigned equals = 0; for(; arg[equals] && arg[equals]!='='; ++equals) ; - OptBase &opt = get_option(string(arg, equals)); + OptionImpl &opt = get_option(string(arg, equals)); if(arg[equals]) // Process the part after the = as option argument @@ -122,7 +125,7 @@ unsigned GetOpt::process_short(const char *const *argp) // Loop through all characters in the argument for(; *arg; ++arg) { - OptBase &opt = get_option(*arg); + OptionImpl &opt = get_option(*arg); if(arg[1] && opt.get_arg_type()!=NO_ARG) { @@ -222,38 +225,41 @@ string GetOpt::generate_help() const } -GetOpt::OptBase::OptBase(char s, const std::string &l, ArgType a): +GetOpt::OptionImpl::OptionImpl(char s, const std::string &l, const Store &t, ArgType a): shrt(s), lng(l), arg_type(a), seen_count(0), ext_seen_count(0), - metavar("ARG") + metavar("ARG"), + store(t.clone()) +{ } + +GetOpt::OptionImpl::~OptionImpl() { - if(lng.empty()) - throw invalid_argument("empty long option name"); + delete store; } -GetOpt::OptBase &GetOpt::OptBase::set_help(const string &h) +GetOpt::OptionImpl &GetOpt::OptionImpl::set_help(const string &h) { help = h; return *this; } -GetOpt::OptBase &GetOpt::OptBase::set_help(const string &h, const string &m) +GetOpt::OptionImpl &GetOpt::OptionImpl::set_help(const string &h, const string &m) { help = h; metavar = m; return *this; } -GetOpt::OptBase &GetOpt::OptBase::bind_seen_count(unsigned &c) +GetOpt::OptionImpl &GetOpt::OptionImpl::bind_seen_count(unsigned &c) { ext_seen_count = &c; return *this; } -void GetOpt::OptBase::process() +void GetOpt::OptionImpl::process() { if(arg_type==REQUIRED_ARG) throw usage_error("--"+lng+" requires an argument"); @@ -264,7 +270,7 @@ void GetOpt::OptBase::process() try { - store(); + store->store(); } catch(const exception &e) { @@ -272,7 +278,7 @@ void GetOpt::OptBase::process() } } -void GetOpt::OptBase::process(const string &arg) +void GetOpt::OptionImpl::process(const string &arg) { if(arg_type==NO_ARG) throw usage_error("--"+lng+" takes no argument"); @@ -283,7 +289,7 @@ void GetOpt::OptBase::process(const string &arg) try { - store(arg); + store->store(arg); } catch(const exception &e) { diff --git a/source/core/getopt.h b/source/core/getopt.h index 4f53cc2..911934a 100644 --- a/source/core/getopt.h +++ b/source/core/getopt.h @@ -79,7 +79,20 @@ public: }; private: - class OptBase: public Option + class Store + { + protected: + Store() { } + public: + virtual ~Store() { } + + virtual Store *clone() const = 0; + + virtual void store() = 0; + virtual void store(const std::string &) = 0; + }; + + class OptionImpl: public Option { protected: char shrt; @@ -89,14 +102,15 @@ private: unsigned *ext_seen_count; std::string help; std::string metavar; + Store *store; - OptBase(char, const std::string &, ArgType); public: - virtual ~OptBase() { } + OptionImpl(char, const std::string &, const Store &, ArgType); + virtual ~OptionImpl(); - virtual OptBase &set_help(const std::string &); - virtual OptBase &set_help(const std::string &, const std::string &); - virtual OptBase &bind_seen_count(unsigned &); + virtual OptionImpl &set_help(const std::string &); + virtual OptionImpl &set_help(const std::string &, const std::string &); + virtual OptionImpl &bind_seen_count(unsigned &); char get_short() const { return shrt; } const std::string &get_long() const { return lng; } ArgType get_arg_type() const { return arg_type; } @@ -105,19 +119,19 @@ private: virtual unsigned get_seen_count() const { return seen_count; } void process(); void process(const std::string &); - protected: - virtual void store() = 0; - virtual void store(const std::string &) = 0; }; template - class SimpleOption: public OptBase + class SimpleStore: public Store { private: T &data; public: - SimpleOption(char s, const std::string &l, T &d, ArgType a): OptBase(s, l, a), data(d) { } + SimpleStore(T &d): data(d) { } + + virtual SimpleStore *clone() const + { return new SimpleStore(data); } virtual void store() { } @@ -126,14 +140,16 @@ private: }; template - class ListOption: public OptBase + class ListStore: public Store { private: T &data; public: - ListOption(char s, const std::string &l, T &d, ArgType a): OptBase(s, l, a), data(d) - { if(arg_type!=REQUIRED_ARG) throw std::invalid_argument("ListOption arg_type!=REQUIRED"); } + ListStore(T &d): data(d) { } + + virtual ListStore *clone() const + { return new ListStore(data); } virtual void store() { } @@ -141,7 +157,7 @@ private: { data.push_back(lexical_cast(a)); } }; - typedef std::list OptionList; + typedef std::list OptionList; bool help; OptionList opts; @@ -161,14 +177,14 @@ public: and an unsigned will be incremented; any other type will be ignored. */ template Option &add_option(char s, const std::string &l, T &d, ArgType a = NO_ARG) - { return add_option(new SimpleOption(s, l, d, a)); } + { return add_option(s, l, SimpleStore(d), a); } /** Adds an option with both short and long forms. The option may be specified multiple times, and the argument from each occurrence is stored in the list. The argument type must be REQUIRED_ARG. */ template Option &add_option(char s, const std::string &l, std::list &d, ArgType a = REQUIRED_ARG) - { return add_option(new ListOption >(s, l, d, a)); } + { return add_option(s, l, ListStore >(d), a); } /** Adds an option with only a long form. */ template @@ -176,10 +192,10 @@ public: { return add_option(0, l, d, a); } private: - OptBase &add_option(OptBase *); + OptionImpl &add_option(char, const std::string &, const Store &, ArgType); - OptBase &get_option(char); - OptBase &get_option(const std::string &); + OptionImpl &get_option(char); + OptionImpl &get_option(const std::string &); public: /** Processes argc/argv style command line arguments. The contents of argv @@ -202,16 +218,16 @@ public: std::string generate_help() const; }; -template<> inline void GetOpt::SimpleOption::store() +template<> inline void GetOpt::SimpleStore::store() { data = true; } -template<> inline void GetOpt::SimpleOption::store() +template<> inline void GetOpt::SimpleStore::store() { ++data; } -template<> inline void GetOpt::SimpleOption::store(const std::string &a) +template<> inline void GetOpt::SimpleStore::store(const std::string &a) { data = a; } -template<> inline void GetOpt::ListOption >::store(const std::string &a) +template<> inline void GetOpt::ListStore >::store(const std::string &a) { data.push_back(a); } } // namespace Msp -- 2.45.2