]> git.tdb.fi Git - libs/core.git/commitdiff
Restructure internals of GetOpt
authorMikko Rasa <tdb@tdb.fi>
Thu, 2 May 2013 11:21:19 +0000 (14:21 +0300)
committerMikko Rasa <tdb@tdb.fi>
Thu, 2 May 2013 11:28:54 +0000 (14:28 +0300)
Value storage is now handled by a separate class hierarchy, making it more
reusable.

source/core/getopt.cpp
source/core/getopt.h

index 2bbfebc5c7a867e200f1b5463d0c9db1894f3899..e909712a87e7527f35bdad1ca2c148c5f3e6dd0d 100644 (file)
@@ -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)
        {
index 4f53cc2ddcafd2b4fbabb19be9e4150120d9bb6d..911934ac08adb7399bbd914b6778a8df8eb99f03 100644 (file)
@@ -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<typename T>
-       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<typename T>
-       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<typename T::value_type>(a)); }
        };
 
-       typedef std::list<OptBase *> OptionList;
+       typedef std::list<OptionImpl *> OptionList;
 
        bool help;
        OptionList opts;
@@ -161,14 +177,14 @@ public:
        and an unsigned will be incremented; any other type will be ignored. */
        template<typename T>
        Option &add_option(char s, const std::string &l, T &d, ArgType a = NO_ARG)
-       { return add_option(new SimpleOption<T>(s, l, d, a)); }
+       { return add_option(s, l, SimpleStore<T>(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<typename T>
        Option &add_option(char s, const std::string &l, std::list<T> &d, ArgType a = REQUIRED_ARG)
-       { return add_option(new ListOption<std::list<T> >(s, l, d, a)); }
+       { return add_option(s, l, ListStore<std::list<T> >(d), a); }
 
        /** Adds an option with only a long form. */
        template<typename T>
@@ -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<bool>::store()
+template<> inline void GetOpt::SimpleStore<bool>::store()
 { data = true; }
 
-template<> inline void GetOpt::SimpleOption<unsigned>::store()
+template<> inline void GetOpt::SimpleStore<unsigned>::store()
 { ++data; }
 
-template<> inline void GetOpt::SimpleOption<std::string>::store(const std::string &a)
+template<> inline void GetOpt::SimpleStore<std::string>::store(const std::string &a)
 { data = a; }
 
-template<> inline void GetOpt::ListOption<std::list<std::string> >::store(const std::string &a)
+template<> inline void GetOpt::ListStore<std::list<std::string> >::store(const std::string &a)
 { data.push_back(a); }
 
 } // namespace Msp